ARI: Add subscription support
[asterisk/asterisk.git] / res / res_ari_applications.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.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 /*
20  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21  * !!!!!                               DO NOT EDIT                        !!!!!
22  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23  * This file is generated by a mustache template. Please see the original
24  * template in rest-api-templates/res_ari_resource.c.mustache
25  */
26
27 /*! \file
28  *
29  * \brief Stasis application resources
30  *
31  * \author David M. Lee, II <dlee@digium.com>
32  */
33
34 /*** MODULEINFO
35         <depend type="module">res_ari</depend>
36         <depend type="module">res_stasis</depend>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include "asterisk/app.h"
45 #include "asterisk/module.h"
46 #include "asterisk/stasis_app.h"
47 #include "ari/resource_applications.h"
48 #if defined(AST_DEVMODE)
49 #include "ari/ari_model_validators.h"
50 #endif
51
52 #define MAX_VALS 128
53
54 /*!
55  * \brief Parameter parsing callback for /applications.
56  * \param get_params GET parameters in the HTTP request.
57  * \param path_vars Path variables extracted from the request.
58  * \param headers HTTP headers.
59  * \param[out] response Response to the HTTP request.
60  */
61 static void ast_ari_get_applications_cb(
62         struct ast_variable *get_params, struct ast_variable *path_vars,
63         struct ast_variable *headers, struct ast_ari_response *response)
64 {
65         struct ast_get_applications_args args = {};
66 #if defined(AST_DEVMODE)
67         int is_valid;
68         int code;
69 #endif /* AST_DEVMODE */
70
71         ast_ari_get_applications(headers, &args, response);
72 #if defined(AST_DEVMODE)
73         code = response->response_code;
74
75         switch (code) {
76         case 0: /* Implementation is still a stub, or the code wasn't set */
77                 is_valid = response->message == NULL;
78                 break;
79         case 500: /* Internal Server Error */
80         case 501: /* Not Implemented */
81                 is_valid = 1;
82                 break;
83         default:
84                 if (200 <= code && code <= 299) {
85                         is_valid = ast_ari_validate_list(response->message,
86                                 ast_ari_validate_application_fn());
87                 } else {
88                         ast_log(LOG_ERROR, "Invalid error response %d for /applications\n", code);
89                         is_valid = 0;
90                 }
91         }
92
93         if (!is_valid) {
94                 ast_log(LOG_ERROR, "Response validation failed for /applications\n");
95                 ast_ari_response_error(response, 500,
96                         "Internal Server Error", "Response validation failed");
97         }
98 #endif /* AST_DEVMODE */
99
100 fin: __attribute__((unused))
101         return;
102 }
103 /*!
104  * \brief Parameter parsing callback for /applications/{applicationName}.
105  * \param get_params GET parameters in the HTTP request.
106  * \param path_vars Path variables extracted from the request.
107  * \param headers HTTP headers.
108  * \param[out] response Response to the HTTP request.
109  */
110 static void ast_ari_get_application_cb(
111         struct ast_variable *get_params, struct ast_variable *path_vars,
112         struct ast_variable *headers, struct ast_ari_response *response)
113 {
114         struct ast_get_application_args args = {};
115         struct ast_variable *i;
116 #if defined(AST_DEVMODE)
117         int is_valid;
118         int code;
119 #endif /* AST_DEVMODE */
120
121         for (i = path_vars; i; i = i->next) {
122                 if (strcmp(i->name, "applicationName") == 0) {
123                         args.application_name = (i->value);
124                 } else
125                 {}
126         }
127         ast_ari_get_application(headers, &args, response);
128 #if defined(AST_DEVMODE)
129         code = response->response_code;
130
131         switch (code) {
132         case 0: /* Implementation is still a stub, or the code wasn't set */
133                 is_valid = response->message == NULL;
134                 break;
135         case 500: /* Internal Server Error */
136         case 501: /* Not Implemented */
137         case 404: /* Application does not exist. */
138                 is_valid = 1;
139                 break;
140         default:
141                 if (200 <= code && code <= 299) {
142                         is_valid = ast_ari_validate_application(
143                                 response->message);
144                 } else {
145                         ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}\n", code);
146                         is_valid = 0;
147                 }
148         }
149
150         if (!is_valid) {
151                 ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}\n");
152                 ast_ari_response_error(response, 500,
153                         "Internal Server Error", "Response validation failed");
154         }
155 #endif /* AST_DEVMODE */
156
157 fin: __attribute__((unused))
158         return;
159 }
160 /*!
161  * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
162  * \param get_params GET parameters in the HTTP request.
163  * \param path_vars Path variables extracted from the request.
164  * \param headers HTTP headers.
165  * \param[out] response Response to the HTTP request.
166  */
167 static void ast_ari_application_subscribe_cb(
168         struct ast_variable *get_params, struct ast_variable *path_vars,
169         struct ast_variable *headers, struct ast_ari_response *response)
170 {
171         struct ast_application_subscribe_args args = {};
172         struct ast_variable *i;
173 #if defined(AST_DEVMODE)
174         int is_valid;
175         int code;
176 #endif /* AST_DEVMODE */
177
178         for (i = get_params; i; i = i->next) {
179                 if (strcmp(i->name, "eventSource") == 0) {
180                         /* Parse comma separated list */
181                         char *vals[MAX_VALS];
182                         size_t j;
183
184                         args.event_source_parse = ast_strdup(i->value);
185                         if (!args.event_source_parse) {
186                                 ast_ari_response_alloc_failed(response);
187                                 goto fin;
188                         }
189
190                         if (strlen(args.event_source_parse) == 0) {
191                                 /* ast_app_separate_args can't handle "" */
192                                 args.event_source_count = 1;
193                                 vals[0] = args.event_source_parse;
194                         } else {
195                                 args.event_source_count = ast_app_separate_args(
196                                         args.event_source_parse, ',', vals,
197                                         ARRAY_LEN(vals));
198                         }
199
200                         if (args.event_source_count == 0) {
201                                 ast_ari_response_alloc_failed(response);
202                                 goto fin;
203                         }
204
205                         if (args.event_source_count >= MAX_VALS) {
206                                 ast_ari_response_error(response, 400,
207                                         "Bad Request",
208                                         "Too many values for event_source");
209                                 goto fin;
210                         }
211
212                         args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
213                         if (!args.event_source) {
214                                 ast_ari_response_alloc_failed(response);
215                                 goto fin;
216                         }
217
218                         for (j = 0; j < args.event_source_count; ++j) {
219                                 args.event_source[j] = (vals[j]);
220                         }
221                 } else
222                 {}
223         }
224         for (i = path_vars; i; i = i->next) {
225                 if (strcmp(i->name, "applicationName") == 0) {
226                         args.application_name = (i->value);
227                 } else
228                 {}
229         }
230         ast_ari_application_subscribe(headers, &args, response);
231 #if defined(AST_DEVMODE)
232         code = response->response_code;
233
234         switch (code) {
235         case 0: /* Implementation is still a stub, or the code wasn't set */
236                 is_valid = response->message == NULL;
237                 break;
238         case 500: /* Internal Server Error */
239         case 501: /* Not Implemented */
240         case 400: /* Missing parameter. */
241         case 404: /* Application does not exist. */
242         case 422: /* Event source does not exist. */
243                 is_valid = 1;
244                 break;
245         default:
246                 if (200 <= code && code <= 299) {
247                         is_valid = ast_ari_validate_application(
248                                 response->message);
249                 } else {
250                         ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
251                         is_valid = 0;
252                 }
253         }
254
255         if (!is_valid) {
256                 ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
257                 ast_ari_response_error(response, 500,
258                         "Internal Server Error", "Response validation failed");
259         }
260 #endif /* AST_DEVMODE */
261
262 fin: __attribute__((unused))
263         ast_free(args.event_source_parse);
264         ast_free(args.event_source);
265         return;
266 }
267 /*!
268  * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
269  * \param get_params GET parameters in the HTTP request.
270  * \param path_vars Path variables extracted from the request.
271  * \param headers HTTP headers.
272  * \param[out] response Response to the HTTP request.
273  */
274 static void ast_ari_application_unsubscribe_cb(
275         struct ast_variable *get_params, struct ast_variable *path_vars,
276         struct ast_variable *headers, struct ast_ari_response *response)
277 {
278         struct ast_application_unsubscribe_args args = {};
279         struct ast_variable *i;
280 #if defined(AST_DEVMODE)
281         int is_valid;
282         int code;
283 #endif /* AST_DEVMODE */
284
285         for (i = get_params; i; i = i->next) {
286                 if (strcmp(i->name, "eventSource") == 0) {
287                         /* Parse comma separated list */
288                         char *vals[MAX_VALS];
289                         size_t j;
290
291                         args.event_source_parse = ast_strdup(i->value);
292                         if (!args.event_source_parse) {
293                                 ast_ari_response_alloc_failed(response);
294                                 goto fin;
295                         }
296
297                         if (strlen(args.event_source_parse) == 0) {
298                                 /* ast_app_separate_args can't handle "" */
299                                 args.event_source_count = 1;
300                                 vals[0] = args.event_source_parse;
301                         } else {
302                                 args.event_source_count = ast_app_separate_args(
303                                         args.event_source_parse, ',', vals,
304                                         ARRAY_LEN(vals));
305                         }
306
307                         if (args.event_source_count == 0) {
308                                 ast_ari_response_alloc_failed(response);
309                                 goto fin;
310                         }
311
312                         if (args.event_source_count >= MAX_VALS) {
313                                 ast_ari_response_error(response, 400,
314                                         "Bad Request",
315                                         "Too many values for event_source");
316                                 goto fin;
317                         }
318
319                         args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
320                         if (!args.event_source) {
321                                 ast_ari_response_alloc_failed(response);
322                                 goto fin;
323                         }
324
325                         for (j = 0; j < args.event_source_count; ++j) {
326                                 args.event_source[j] = (vals[j]);
327                         }
328                 } else
329                 {}
330         }
331         for (i = path_vars; i; i = i->next) {
332                 if (strcmp(i->name, "applicationName") == 0) {
333                         args.application_name = (i->value);
334                 } else
335                 {}
336         }
337         ast_ari_application_unsubscribe(headers, &args, response);
338 #if defined(AST_DEVMODE)
339         code = response->response_code;
340
341         switch (code) {
342         case 0: /* Implementation is still a stub, or the code wasn't set */
343                 is_valid = response->message == NULL;
344                 break;
345         case 500: /* Internal Server Error */
346         case 501: /* Not Implemented */
347         case 400: /* Missing parameter; event source scheme not recognized. */
348         case 404: /* Application does not exist. */
349         case 409: /* Application not subscribed to event source. */
350         case 422: /* Event source does not exist. */
351                 is_valid = 1;
352                 break;
353         default:
354                 if (200 <= code && code <= 299) {
355                         is_valid = ast_ari_validate_application(
356                                 response->message);
357                 } else {
358                         ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
359                         is_valid = 0;
360                 }
361         }
362
363         if (!is_valid) {
364                 ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
365                 ast_ari_response_error(response, 500,
366                         "Internal Server Error", "Response validation failed");
367         }
368 #endif /* AST_DEVMODE */
369
370 fin: __attribute__((unused))
371         ast_free(args.event_source_parse);
372         ast_free(args.event_source);
373         return;
374 }
375
376 /*! \brief REST handler for /api-docs/applications.{format} */
377 static struct stasis_rest_handlers applications_applicationName_subscription = {
378         .path_segment = "subscription",
379         .callbacks = {
380                 [AST_HTTP_POST] = ast_ari_application_subscribe_cb,
381                 [AST_HTTP_DELETE] = ast_ari_application_unsubscribe_cb,
382         },
383         .num_children = 0,
384         .children = {  }
385 };
386 /*! \brief REST handler for /api-docs/applications.{format} */
387 static struct stasis_rest_handlers applications_applicationName = {
388         .path_segment = "applicationName",
389         .is_wildcard = 1,
390         .callbacks = {
391                 [AST_HTTP_GET] = ast_ari_get_application_cb,
392         },
393         .num_children = 1,
394         .children = { &applications_applicationName_subscription, }
395 };
396 /*! \brief REST handler for /api-docs/applications.{format} */
397 static struct stasis_rest_handlers applications = {
398         .path_segment = "applications",
399         .callbacks = {
400                 [AST_HTTP_GET] = ast_ari_get_applications_cb,
401         },
402         .num_children = 1,
403         .children = { &applications_applicationName, }
404 };
405
406 static int load_module(void)
407 {
408         int res = 0;
409         stasis_app_ref();
410         res |= ast_ari_add_handler(&applications);
411         return res;
412 }
413
414 static int unload_module(void)
415 {
416         ast_ari_remove_handler(&applications);
417         stasis_app_unref();
418         return 0;
419 }
420
421 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Stasis application resources",
422         .load = load_module,
423         .unload = unload_module,
424         .nonoptreq = "res_ari,res_stasis",
425         );