Merge "BuildSystem: Really do not pass unknown-warning options to the compiler."
[asterisk/asterisk.git] / funcs / func_sorcery.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Fairview 5 Engineering, LLC
5  *
6  * George Joseph <george.joseph@fairview5.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Get a field from a sorcery object
22  *
23  * \author \verbatim George Joseph <george.joseph@fairview5.com> \endverbatim
24  *
25  * \ingroup functions
26  *
27  */
28
29 /*** MODULEINFO
30         <support_level>core</support_level>
31  ***/
32
33 #include "asterisk.h"
34
35 #include "asterisk/app.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/module.h"
38 #include "asterisk/sorcery.h"
39
40 /*** DOCUMENTATION
41         <function name="AST_SORCERY" language="en_US">
42                 <synopsis>
43                         Get a field from a sorcery object
44                 </synopsis>
45                 <syntax>
46                         <parameter name="module_name" required="true">
47                                 <para>The name of the module owning the sorcery instance.</para>
48                         </parameter>
49                         <parameter name="object_type" required="true">
50                                 <para>The type of object to query.</para>
51                         </parameter>
52                         <parameter name="object_id" required="true">
53                                 <para>The id of the object to query.</para>
54                         </parameter>
55                         <parameter name="field_name" required="true">
56                                 <para>The name of the field.</para>
57                         </parameter>
58                         <parameter name="retrieval_method" required="false">
59                                 <para>Fields that have multiple occurrences may be retrieved in two ways.</para>
60                                 <enumlist>
61                                         <enum name="concat"><para>Returns all matching fields concatenated
62                                         in a single string separated by <replaceable>separator</replaceable>
63                                         which defaults to <literal>,</literal>.</para></enum>
64
65                                         <enum name="single"><para>Returns the nth occurrence of the field
66                                         as specified by <replaceable>occurrence_number</replaceable> which defaults to <literal>1</literal>.
67                                         </para></enum>
68                                 </enumlist>
69                                 <para>The default is <literal>concat</literal> with separator <literal>,</literal>.</para>
70                         </parameter>
71                         <parameter name="retrieval_details" required="false">
72                                 <para>Specifies either the separator for <literal>concat</literal>
73                                 or the occurrence number for <literal>single</literal>.</para>
74                         </parameter>
75                 </syntax>
76         </function>
77 ***/
78
79 static int sorcery_function_read(struct ast_channel *chan,
80         const char *cmd, char *data, struct ast_str **buf, ssize_t len)
81 {
82         char *parsed_data = ast_strdupa(data);
83         RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
84         RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup);
85         struct ast_variable *change_set;
86         struct ast_variable *it_change_set;
87         int found, field_number = 1, ix, method;
88         char *separator = ",";
89
90         enum methods {
91                 CONCAT,
92                 SINGLE,
93         };
94
95         AST_DECLARE_APP_ARGS(args,
96                 AST_APP_ARG(module_name);
97                 AST_APP_ARG(object_type);
98                 AST_APP_ARG(object_id);
99                 AST_APP_ARG(field_name);
100                 AST_APP_ARG(method);
101                 AST_APP_ARG(method_arg);
102         );
103
104         /* Check for zero arguments */
105         if (ast_strlen_zero(parsed_data)) {
106                 ast_log(AST_LOG_ERROR, "Cannot call %s without arguments\n", cmd);
107                 return -1;
108         }
109
110         AST_STANDARD_APP_ARGS(args, parsed_data);
111
112         if (ast_strlen_zero(args.module_name)) {
113                 ast_log(AST_LOG_ERROR, "Cannot call %s without a module name to query\n", cmd);
114                 return -1;
115         }
116
117         if (ast_strlen_zero(args.object_type)) {
118                 ast_log(AST_LOG_ERROR, "Cannot call %s with an empty object type\n", cmd);
119                 return -1;
120         }
121
122         if (ast_strlen_zero(args.object_id)) {
123                 ast_log(AST_LOG_ERROR, "Cannot call %s with an empty object name\n", cmd);
124                 return -1;
125         }
126
127         if (ast_strlen_zero(args.field_name)) {
128                 ast_log(AST_LOG_ERROR, "Cannot call %s with an empty field name\n", cmd);
129                 return -1;
130         }
131
132         if (ast_strlen_zero(args.method)) {
133                 method = CONCAT;
134         } else {
135                 if (strcmp(args.method, "concat") == 0) {
136                         method = CONCAT;
137                         if (ast_strlen_zero(args.method_arg)) {
138                                 separator = ",";
139                         } else {
140                                 separator = args.method_arg;
141                         }
142
143                 } else if (strcmp(args.method, "single") == 0) {
144                         method = SINGLE;
145                         if (!ast_strlen_zero(args.method_arg)) {
146                                 if (sscanf(args.method_arg, "%30d", &field_number) <= 0 || field_number <= 0 ) {
147                                         ast_log(AST_LOG_ERROR, "occurrence_number must be a positive integer\n");
148                                         return -1;
149                                 }
150                         }
151                 } else {
152                         ast_log(AST_LOG_ERROR, "Retrieval method must be 'concat' or 'single'\n");
153                         return -1;
154                 }
155         }
156
157         sorcery = ast_sorcery_retrieve_by_module_name(args.module_name);
158         if (!sorcery) {
159                 ast_log(AST_LOG_ERROR, "Failed to retrieve sorcery instance for module %s\n", args.module_name);
160                 return -1;
161         }
162
163         sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args.object_type, args.object_id);
164         if (!sorcery_obj) {
165                 return -1;
166         }
167
168         change_set = ast_sorcery_objectset_create(sorcery, sorcery_obj);
169         if (!change_set) {
170                 return -1;
171         }
172
173         ix=1;
174         found = 0;
175         for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) {
176
177                 if (method == CONCAT && strcmp(it_change_set->name, args.field_name) == 0) {
178                         ast_str_append(buf, 0, "%s%s", it_change_set->value, separator);
179                         found = 1;
180                         continue;
181                 }
182
183                 if (method == SINGLE && strcmp(it_change_set->name, args.field_name) == 0  && ix++ == field_number) {
184                         ast_str_set(buf, len, "%s", it_change_set->value);
185                         found = 1;
186                         break;
187                 }
188         }
189
190         ast_variables_destroy(change_set);
191
192         if (!found) {
193                 return -1;
194         }
195
196         if (method == CONCAT) {
197                 ast_str_truncate(*buf, -1);
198         }
199
200         return 0;
201 }
202
203 static struct ast_custom_function sorcery_function = {
204         .name = "AST_SORCERY",
205         .read2 = sorcery_function_read,
206 };
207
208 static int unload_module(void)
209 {
210         return ast_custom_function_unregister(&sorcery_function);
211 }
212
213 static int load_module(void)
214 {
215         return ast_custom_function_register(&sorcery_function);
216 }
217
218 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get a field from a sorcery object");