Optionally display the value of several variables within the Status command.
[asterisk/asterisk.git] / funcs / func_enum.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006
5  *
6  * Mark Spencer <markster@digium.com>
7  * Oleksiy Krivoshey <oleksiyk@gmail.com>
8  * Russell Bryant <russelb@clemson.edu>
9  * Brett Bryant <bbryant@digium.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief ENUM Functions
25  *
26  * \author Mark Spencer <markster@digium.com>
27  * \author Oleksiy Krivoshey <oleksiyk@gmail.com>
28  * \author Russell Bryant <russelb@clemson.edu>
29  * \author Brett Bryant <bbryant@digium.com>
30  *
31  * \arg See also AstENUM
32  *
33  * \ingroup functions
34  */
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include "asterisk/module.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/lock.h"
45 #include "asterisk/file.h"
46 #include "asterisk/enum.h"
47 #include "asterisk/app.h"
48
49 static char *synopsis = "Syntax: ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])\n";
50
51 static int function_enum(struct ast_channel *chan, const char *cmd, char *data,
52                          char *buf, size_t len)
53 {
54         AST_DECLARE_APP_ARGS(args,
55                 AST_APP_ARG(number);
56                 AST_APP_ARG(tech);
57                 AST_APP_ARG(options);
58                 AST_APP_ARG(record);
59                 AST_APP_ARG(zone);
60         );
61         int res = 0;
62         char tech[80];
63         char dest[256] = "", tmp[2] = "", num[AST_MAX_EXTENSION] = "";
64         char *s, *p;
65         unsigned int record = 1;
66
67         buf[0] = '\0';
68
69         if (ast_strlen_zero(data)) {
70                 ast_log(LOG_WARNING, "%s", synopsis);
71                 return -1;
72         }
73
74         AST_STANDARD_APP_ARGS(args, data);
75
76         if (args.argc < 1) {
77                 ast_log(LOG_WARNING, "%s", synopsis);
78                 return -1;
79         }
80
81         ast_copy_string(tech, args.tech ? args.tech : "sip", sizeof(tech));
82
83         if (!args.zone)
84                 args.zone = "e164.arpa";
85
86         if (!args.options)
87                 args.options = "";
88
89         if (args.record)
90                 record = atoi(args.record);
91
92         /* strip any '-' signs from number */
93         for (s = p = args.number; *s; s++) {
94                 if (*s != '-') {
95                         snprintf(tmp, sizeof(tmp), "%c", *s);
96                         strncat(num, tmp, sizeof(num) - strlen(num) - 1);
97                 }
98
99         }
100
101         res = ast_get_enum(chan, num, dest, sizeof(dest), tech, sizeof(tech), args.zone, args.options, 1, NULL);
102
103         p = strchr(dest, ':');
104         if (p && strcasecmp(tech, "ALL"))
105                 ast_copy_string(buf, p + 1, len);
106         else
107                 ast_copy_string(buf, dest, len);
108
109         return 0;
110 }
111
112 unsigned int enum_datastore_id;
113
114 struct enum_result_datastore {
115         struct enum_context *context;
116         unsigned int id;
117 };
118
119 static void erds_destroy(struct enum_result_datastore *data) 
120 {
121         int k;
122
123         for (k = 0; k < data->context->naptr_rrs_count; k++) {
124                 ast_free(data->context->naptr_rrs[k].result);
125                 ast_free(data->context->naptr_rrs[k].tech);
126         }
127
128         ast_free(data->context->naptr_rrs);
129         ast_free(data->context);
130         ast_free(data);
131 }
132
133 static void erds_destroy_cb(void *data) 
134 {
135         struct enum_result_datastore *erds = data;
136         erds_destroy(erds);
137 }
138
139 const struct ast_datastore_info enum_result_datastore_info = {
140         .type = "ENUMQUERY",
141         .destroy = erds_destroy_cb,
142 }; 
143
144 static int enum_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
145 {
146         struct enum_result_datastore *erds;
147         struct ast_datastore *datastore;
148         char *parse, tech[128], dest[128];
149         int res = -1;
150
151         AST_DECLARE_APP_ARGS(args,
152                 AST_APP_ARG(number);
153                 AST_APP_ARG(tech);
154                 AST_APP_ARG(zone);
155         );
156
157         if (ast_strlen_zero(data)) {
158                 ast_log(LOG_WARNING, "ENUMQUERY requires at least a number as an argument...\n");
159                 goto finish;
160         }
161
162         parse = ast_strdupa(data);
163     
164         AST_STANDARD_APP_ARGS(args, parse);
165
166         if (!chan) {
167                 ast_log(LOG_ERROR, "ENUMQUERY cannot be used without a channel!\n");
168                 goto finish;
169         }
170
171         if (!args.zone)
172                 args.zone = "e164.zone";
173
174         ast_copy_string(tech, args.tech ? args.tech : "sip", sizeof(tech));
175
176         if (!(erds = ast_calloc(1, sizeof(*erds))))
177                 goto finish;
178
179         if (!(erds->context = ast_calloc(1, sizeof(*erds->context)))) {
180                 ast_free(erds);
181                 goto finish;
182         }
183
184         erds->id = ast_atomic_fetchadd_int((int *) &enum_datastore_id, 1);
185
186         snprintf(buf, len, "%u", erds->id);
187
188         if (!(datastore = ast_channel_datastore_alloc(&enum_result_datastore_info, buf))) {
189                 ast_free(erds->context);
190                 ast_free(erds);
191                 goto finish;
192         }
193
194         ast_get_enum(chan, args.number, dest, sizeof(dest), tech, sizeof(tech), args.zone, "", 1, &erds->context);
195
196         datastore->data = erds;
197
198         ast_channel_lock(chan);
199         ast_channel_datastore_add(chan, datastore);
200         ast_channel_unlock(chan);
201    
202         res = 0;
203     
204 finish:
205
206         return res;
207 }
208
209 static int enum_result_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
210 {
211         struct enum_result_datastore *erds;
212         struct ast_datastore *datastore;
213         char *parse, *p;
214         unsigned int num;
215         int res = -1, k;
216         AST_DECLARE_APP_ARGS(args, 
217                 AST_APP_ARG(id);
218                 AST_APP_ARG(resultnum);
219         );
220
221         if (ast_strlen_zero(data)) {
222                 ast_log(LOG_WARNING, "ENUMRESULT requires two arguments (id and resultnum)\n");
223                 goto finish;
224         }
225
226         if (!chan) {
227                 ast_log(LOG_ERROR, "ENUMRESULT can not be used without a channel!\n");
228                 goto finish;
229         }
230    
231         parse = ast_strdupa(data);
232
233         AST_STANDARD_APP_ARGS(args, parse);
234
235         if (ast_strlen_zero(args.id)) {
236                 ast_log(LOG_ERROR, "A result ID must be provided to ENUMRESULT\n");
237                 goto finish;
238         }
239
240         if (ast_strlen_zero(args.resultnum)) {
241                 ast_log(LOG_ERROR, "A result number must be given to ENUMRESULT!\n");
242                 goto finish;
243         }
244
245         ast_channel_lock(chan);
246         datastore = ast_channel_datastore_find(chan, &enum_result_datastore_info, args.id);
247         ast_channel_unlock(chan);
248         if (!datastore) {
249                 ast_log(LOG_WARNING, "No ENUM results found for query id!\n");
250                 goto finish;
251         }
252
253         erds = datastore->data;
254
255         if (!strcasecmp(args.resultnum, "getnum")) {
256                 snprintf(buf, len, "%u", erds->context->naptr_rrs_count);
257                 res = 0;
258                 goto finish;
259         }
260
261         if (sscanf(args.resultnum, "%u", &num) != 1) {
262                 ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to ENUMRESULT!\n", args.resultnum);
263                 goto finish;
264         }
265
266         if (!num || num > erds->context->naptr_rrs_count) {
267                 ast_log(LOG_WARNING, "Result number %u is not valid for ENUM query results for ID %s!\n", num, args.id);
268                 goto finish;
269         }
270
271         for (k = 0; k < erds->context->naptr_rrs_count; k++) {
272                 if (num - 1 != erds->context->naptr_rrs[k].sort_pos)
273                         continue;
274
275                 p = strchr(erds->context->naptr_rrs[k].result, ':');
276               
277                 if (p && strcasecmp(erds->context->naptr_rrs[k].tech, "ALL"))
278                         ast_copy_string(buf, p + 1, len);
279                 else
280                         ast_copy_string(buf, erds->context->naptr_rrs[k].result, len);
281
282                 break;
283         }
284
285         res = 0;
286
287 finish:
288
289         return res;
290 }
291
292 static struct ast_custom_function enum_query_function = {
293         .name = "ENUMQUERY",
294         .synopsis = "Initiate an ENUM query",
295         .syntax = "ENUMQUERY(number[,Method-type[,zone-suffix]])",
296         .desc = "This will do a ENUM lookup of the given phone number.\n"
297         "If no method-tpye is given, the default will be sip. If no\n"
298         "zone-suffix is given, the default will be \"e164.arpa\".\n"
299         "The result of this function will be a numeric ID that can\n"
300         "be used to retrieve the results using the ENUMRESULT function.\n",
301         .read = enum_query_read,
302 };
303
304 static struct ast_custom_function enum_result_function = {
305         .name = "ENUMRESULT",
306         .synopsis = "Retrieve results from a ENUMQUERY",
307         .syntax = "ENUMRESULT(id,resultnum)",
308         .desc = "This function will retrieve results from a previous use\n"
309         "of the ENUMQUERY function.\n"
310         "  id - This argument is the identifier returned by the ENUMQUERY function.\n"
311         "  resultnum - This is the number of the result that you want to retrieve.\n"
312         "       Results start at 1.  If this argument is specified as \"getnum\",\n"
313         "       then it will return the total number of results that are available.\n",
314         .read = enum_result_read,
315 };
316
317 static struct ast_custom_function enum_function = {
318         .name = "ENUMLOOKUP",
319         .synopsis =
320                 "General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers",
321         .syntax =
322                 "ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])",
323         .desc =
324                 "Option 'c' returns an integer count of the number of NAPTRs of a certain RR type.\n"
325                 "Combination of 'c' and Method-type of 'ALL' will return a count of all NAPTRs for the record.\n"
326                 "Defaults are: Method-type=sip, no options, record=1, zone-suffix=e164.arpa\n\n"
327                 "For more information, see doc/asterisk.pdf",
328         .read = function_enum,
329 };
330
331 static int function_txtcidname(struct ast_channel *chan, const char *cmd,
332                                char *data, char *buf, size_t len)
333 {
334         int res;
335         char tech[80];
336         char txt[256] = "";
337         char dest[80];
338
339         buf[0] = '\0';
340
341
342         if (ast_strlen_zero(data)) {
343                 ast_log(LOG_WARNING, "TXTCIDNAME requires an argument (number)\n");
344                 return -1;
345         }
346
347         res = ast_get_txt(chan, data, dest, sizeof(dest), tech, sizeof(tech), txt,
348                           sizeof(txt));
349
350         if (!ast_strlen_zero(txt))
351                 ast_copy_string(buf, txt, len);
352
353         return 0;
354 }
355
356 static struct ast_custom_function txtcidname_function = {
357         .name = "TXTCIDNAME",
358         .synopsis = "TXTCIDNAME looks up a caller name via DNS",
359         .syntax = "TXTCIDNAME(<number>)",
360         .desc =
361                 "This function looks up the given phone number in DNS to retrieve\n"
362                 "the caller id name.  The result will either be blank or be the value\n"
363                 "found in the TXT record in DNS.\n",
364         .read = function_txtcidname,
365 };
366
367 static int unload_module(void)
368 {
369         int res = 0;
370
371         res |= ast_custom_function_unregister(&enum_result_function);
372         res |= ast_custom_function_unregister(&enum_query_function);
373         res |= ast_custom_function_unregister(&enum_function);
374         res |= ast_custom_function_unregister(&txtcidname_function);
375
376         return res;
377 }
378
379 static int load_module(void)
380 {
381         int res = 0;
382
383         res |= ast_custom_function_register(&enum_result_function);
384         res |= ast_custom_function_register(&enum_query_function);
385         res |= ast_custom_function_register(&enum_function);
386         res |= ast_custom_function_register(&txtcidname_function);
387
388         return res;
389 }
390
391 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ENUM related dialplan functions");