Expand codec bitfield from 32 bits to 64 bits.
[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 /*** DOCUMENTATION
50         <function name="ENUMQUERY" language="en_US">
51                 <synopsis>
52                         Initiate an ENUM query.
53                 </synopsis>
54                 <syntax>
55                         <parameter name="number" required="true" />
56                         <parameter name="method-type">
57                                 <para>If no <replaceable>method-type</replaceable> is given, the default will be
58                                 <literal>sip</literal>.</para>
59                         </parameter>
60                         <parameter name="zone-suffix">
61                                 <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
62                                 <literal>e164.arpa</literal></para>
63                         </parameter>
64                 </syntax>
65                 <description>
66                         <para>This will do a ENUM lookup of the given phone number.</para>
67                 </description>
68         </function>
69         <function name="ENUMRESULT" language="en_US">
70                 <synopsis>
71                         Retrieve results from a ENUMQUERY.
72                 </synopsis>
73                 <syntax>
74                         <parameter name="id" required="true">
75                                 <para>The identifier returned by the ENUMQUERY function.</para>
76                         </parameter>
77                         <parameter name="resultnum" required="true">
78                                 <para>The number of the result that you want to retrieve.</para>
79                                 <para>Results start at <literal>1</literal>. If this argument is specified
80                                 as <literal>getnum</literal>, then it will return the total number of results 
81                                 that are available.</para>
82                         </parameter>
83                 </syntax>
84                 <description>
85                         <para>This function will retrieve results from a previous use
86                         of the ENUMQUERY function.</para>
87                 </description>
88         </function>     
89         <function name="ENUMLOOKUP" language="en_US">
90                 <synopsis>
91                         General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers.
92                 </synopsis>
93                 <syntax>
94                         <parameter name="number" required="true" />
95                         <parameter name="method-type">
96                                 <para>If no <replaceable>method-type</replaceable> is given, the default will be
97                                 <literal>sip</literal>.</para>
98                         </parameter>
99                         <parameter name="options">
100                                 <optionlist>
101                                         <option name="c">
102                                                 <para>Returns an integer count of the number of NAPTRs of a certain RR type.</para>
103                                                 <para>Combination of <literal>c</literal> and Method-type of <literal>ALL</literal> will
104                                                 return a count of all NAPTRs for the record.</para>
105                                         </option>
106                                         <option name="u">
107                                                 <para>Returns the full URI and does not strip off the URI-scheme.</para>
108                                         </option>
109                                         <option name="s">
110                                                 <para>Triggers ISN specific rewriting.</para>
111                                         </option>
112                                         <option name="i">
113                                                 <para>Looks for branches into an Infrastructure ENUM tree.</para>
114                                         </option>
115                                         <option name="d">
116                                                 <para>for a direct DNS lookup without any flipping of digits.</para>
117                                         </option>
118                                 </optionlist>   
119                         </parameter>
120                         <parameter name="record#">
121                                 <para>If no <replaceable>record#</replaceable> is given, 
122                                 defaults to <literal>1</literal>.</para>
123                         </parameter>
124                         <parameter name="zone-suffix">
125                                 <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
126                                 <literal>e164.arpa</literal></para>
127                         </parameter>
128                 </syntax>
129                 <description>
130                         <para>For more information see <filename>doc/asterisk.pdf</filename>.</para>
131                 </description>
132         </function>
133         <function name="TXTCIDNAME" language="en_US">
134                 <synopsis>
135                         TXTCIDNAME looks up a caller name via DNS.
136                 </synopsis>
137                 <syntax>
138                         <parameter name="number" required="true" />
139                         <parameter name="zone-suffix">
140                                 <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
141                                 <literal>e164.arpa</literal></para>
142                         </parameter>
143                 </syntax>
144                 <description>
145                         <para>This function looks up the given phone number in DNS to retrieve
146                         the caller id name.  The result will either be blank or be the value
147                         found in the TXT record in DNS.</para>
148                 </description>
149         </function>
150  ***/
151
152 static char *synopsis = "Syntax: ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])\n";
153
154 static int function_enum(struct ast_channel *chan, const char *cmd, char *data,
155                          char *buf, size_t len)
156 {
157         AST_DECLARE_APP_ARGS(args,
158                 AST_APP_ARG(number);
159                 AST_APP_ARG(tech);
160                 AST_APP_ARG(options);
161                 AST_APP_ARG(record);
162                 AST_APP_ARG(zone);
163         );
164         int res = 0;
165         char tech[80];
166         char dest[256] = "", tmp[2] = "", num[AST_MAX_EXTENSION] = "";
167         char *s, *p;
168         unsigned int record = 1;
169
170         buf[0] = '\0';
171
172         if (ast_strlen_zero(data)) {
173                 ast_log(LOG_WARNING, "%s", synopsis);
174                 return -1;
175         }
176
177         AST_STANDARD_APP_ARGS(args, data);
178
179         if (args.argc < 1) {
180                 ast_log(LOG_WARNING, "%s", synopsis);
181                 return -1;
182         }
183
184         if (args.tech && !ast_strlen_zero(args.tech)) {
185                 ast_copy_string(tech,args.tech, sizeof(tech));
186         } else {
187                 ast_copy_string(tech,"sip",sizeof(tech));
188         }
189
190         if (!args.zone) {
191                 args.zone = "e164.arpa";
192         }
193         if (!args.options) {
194                 args.options = "";
195         }
196         if (args.record) {
197                 record = atoi(args.record) ? atoi(args.record) : record;
198         }
199
200         /* strip any '-' signs from number */
201         for (s = p = args.number; *s; s++) {
202                 if (*s != '-') {
203                         snprintf(tmp, sizeof(tmp), "%c", *s);
204                         strncat(num, tmp, sizeof(num) - strlen(num) - 1);
205                 }
206
207         }
208         res = ast_get_enum(chan, num, dest, sizeof(dest), tech, sizeof(tech), args.zone, args.options, record, NULL);
209
210         p = strchr(dest, ':');
211         if (p && strcasecmp(tech, "ALL") && !strchr(args.options, 'u')) {
212                 ast_copy_string(buf, p + 1, len);
213         } else {
214                 ast_copy_string(buf, dest, len);
215         }
216         return 0;
217 }
218
219 static unsigned int enum_datastore_id;
220
221 struct enum_result_datastore {
222         struct enum_context *context;
223         unsigned int id;
224 };
225
226 static void erds_destroy(struct enum_result_datastore *data) 
227 {
228         int k;
229
230         for (k = 0; k < data->context->naptr_rrs_count; k++) {
231                 ast_free(data->context->naptr_rrs[k].result);
232                 ast_free(data->context->naptr_rrs[k].tech);
233         }
234
235         ast_free(data->context->naptr_rrs);
236         ast_free(data->context);
237         ast_free(data);
238 }
239
240 static void erds_destroy_cb(void *data) 
241 {
242         struct enum_result_datastore *erds = data;
243         erds_destroy(erds);
244 }
245
246 static const struct ast_datastore_info enum_result_datastore_info = {
247         .type = "ENUMQUERY",
248         .destroy = erds_destroy_cb,
249 }; 
250
251 static int enum_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
252 {
253         struct enum_result_datastore *erds;
254         struct ast_datastore *datastore;
255         char *parse, tech[128], dest[128];
256         int res = -1;
257
258         AST_DECLARE_APP_ARGS(args,
259                 AST_APP_ARG(number);
260                 AST_APP_ARG(tech);
261                 AST_APP_ARG(zone);
262         );
263
264         if (ast_strlen_zero(data)) {
265                 ast_log(LOG_WARNING, "ENUMQUERY requires at least a number as an argument...\n");
266                 goto finish;
267         }
268
269         parse = ast_strdupa(data);
270     
271         AST_STANDARD_APP_ARGS(args, parse);
272
273         if (!chan) {
274                 ast_log(LOG_ERROR, "ENUMQUERY cannot be used without a channel!\n");
275                 goto finish;
276         }
277
278         if (!args.zone)
279                 args.zone = "e164.zone";
280
281         ast_copy_string(tech, args.tech ? args.tech : "sip", sizeof(tech));
282
283         if (!(erds = ast_calloc(1, sizeof(*erds))))
284                 goto finish;
285
286         if (!(erds->context = ast_calloc(1, sizeof(*erds->context)))) {
287                 ast_free(erds);
288                 goto finish;
289         }
290
291         erds->id = ast_atomic_fetchadd_int((int *) &enum_datastore_id, 1);
292
293         snprintf(buf, len, "%u", erds->id);
294
295         if (!(datastore = ast_datastore_alloc(&enum_result_datastore_info, buf))) {
296                 ast_free(erds->context);
297                 ast_free(erds);
298                 goto finish;
299         }
300
301         ast_get_enum(chan, args.number, dest, sizeof(dest), tech, sizeof(tech), args.zone, "", 1, &erds->context);
302
303         datastore->data = erds;
304
305         ast_channel_lock(chan);
306         ast_channel_datastore_add(chan, datastore);
307         ast_channel_unlock(chan);
308    
309         res = 0;
310     
311 finish:
312
313         return res;
314 }
315
316 static int enum_result_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
317 {
318         struct enum_result_datastore *erds;
319         struct ast_datastore *datastore;
320         char *parse, *p;
321         unsigned int num;
322         int res = -1, k;
323         AST_DECLARE_APP_ARGS(args, 
324                 AST_APP_ARG(id);
325                 AST_APP_ARG(resultnum);
326         );
327
328         if (ast_strlen_zero(data)) {
329                 ast_log(LOG_WARNING, "ENUMRESULT requires two arguments (id and resultnum)\n");
330                 goto finish;
331         }
332
333         if (!chan) {
334                 ast_log(LOG_ERROR, "ENUMRESULT can not be used without a channel!\n");
335                 goto finish;
336         }
337    
338         parse = ast_strdupa(data);
339
340         AST_STANDARD_APP_ARGS(args, parse);
341
342         if (ast_strlen_zero(args.id)) {
343                 ast_log(LOG_ERROR, "A result ID must be provided to ENUMRESULT\n");
344                 goto finish;
345         }
346
347         if (ast_strlen_zero(args.resultnum)) {
348                 ast_log(LOG_ERROR, "A result number must be given to ENUMRESULT!\n");
349                 goto finish;
350         }
351
352         ast_channel_lock(chan);
353         datastore = ast_channel_datastore_find(chan, &enum_result_datastore_info, args.id);
354         ast_channel_unlock(chan);
355         if (!datastore) {
356                 ast_log(LOG_WARNING, "No ENUM results found for query id!\n");
357                 goto finish;
358         }
359
360         erds = datastore->data;
361
362         if (!strcasecmp(args.resultnum, "getnum")) {
363                 snprintf(buf, len, "%u", erds->context->naptr_rrs_count);
364                 res = 0;
365                 goto finish;
366         }
367
368         if (sscanf(args.resultnum, "%30u", &num) != 1) {
369                 ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to ENUMRESULT!\n", args.resultnum);
370                 goto finish;
371         }
372
373         if (!num || num > erds->context->naptr_rrs_count) {
374                 ast_log(LOG_WARNING, "Result number %u is not valid for ENUM query results for ID %s!\n", num, args.id);
375                 goto finish;
376         }
377
378         for (k = 0; k < erds->context->naptr_rrs_count; k++) {
379                 if (num - 1 != erds->context->naptr_rrs[k].sort_pos)
380                         continue;
381
382                 p = strchr(erds->context->naptr_rrs[k].result, ':');
383               
384                 if (p && strcasecmp(erds->context->naptr_rrs[k].tech, "ALL"))
385                         ast_copy_string(buf, p + 1, len);
386                 else
387                         ast_copy_string(buf, erds->context->naptr_rrs[k].result, len);
388
389                 break;
390         }
391
392         res = 0;
393
394 finish:
395
396         return res;
397 }
398
399 static struct ast_custom_function enum_query_function = {
400         .name = "ENUMQUERY",
401         .read = enum_query_read,
402 };
403
404 static struct ast_custom_function enum_result_function = {
405         .name = "ENUMRESULT",
406         .read = enum_result_read,
407 };
408
409 static struct ast_custom_function enum_function = {
410         .name = "ENUMLOOKUP",
411         .read = function_enum,
412 };
413
414 static int function_txtcidname(struct ast_channel *chan, const char *cmd,
415                                char *data, char *buf, size_t len)
416 {
417         int res;
418         AST_DECLARE_APP_ARGS(args,
419                 AST_APP_ARG(number);
420                 AST_APP_ARG(zone);
421         );
422
423         buf[0] = '\0';
424
425         if (ast_strlen_zero(data)) {
426                 ast_log(LOG_WARNING, "Syntax: TXTCIDNAME(number[,zone-suffix])\n");
427                 return -1;
428         }
429
430         AST_STANDARD_APP_ARGS(args, data);
431
432         if (args.argc < 1) {
433                 ast_log(LOG_WARNING, "Syntax: TXTCIDNAME(number[,zone-suffix])\n");
434                 return -1;
435         }
436
437         if (!args.zone) {
438                 args.zone = "e164.arpa";
439         }
440
441         res = ast_get_txt(chan, args.number, buf, len, args.zone);
442
443         return 0;
444 }
445
446 static struct ast_custom_function txtcidname_function = {
447         .name = "TXTCIDNAME",
448         .read = function_txtcidname,
449 };
450
451 static int unload_module(void)
452 {
453         int res = 0;
454
455         res |= ast_custom_function_unregister(&enum_result_function);
456         res |= ast_custom_function_unregister(&enum_query_function);
457         res |= ast_custom_function_unregister(&enum_function);
458         res |= ast_custom_function_unregister(&txtcidname_function);
459
460         return res;
461 }
462
463 static int load_module(void)
464 {
465         int res = 0;
466
467         res |= ast_custom_function_register(&enum_result_function);
468         res |= ast_custom_function_register(&enum_query_function);
469         res |= ast_custom_function_register(&enum_function);
470         res |= ast_custom_function_register(&txtcidname_function);
471
472         return res;
473 }
474
475 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ENUM related dialplan functions");