channels: Allow updating variable value
[asterisk/asterisk.git] / res / ari / resource_recordings.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 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 /*! \file
20  *
21  * \brief /api-docs/recordings.{format} implementation- Recording resources
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/stasis_app_recording.h"
33 #include "resource_recordings.h"
34
35 void ast_ari_recordings_list_stored(struct ast_variable *headers,
36         struct ast_ari_recordings_list_stored_args *args,
37         struct ast_ari_response *response)
38 {
39         RAII_VAR(struct ao2_container *, recordings, NULL, ao2_cleanup);
40         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
41         struct ao2_iterator i;
42         void *obj;
43
44         recordings = stasis_app_stored_recording_find_all();
45
46         if (!recordings) {
47                 ast_ari_response_alloc_failed(response);
48                 return;
49         }
50
51         json = ast_json_array_create();
52         if (!json) {
53                 ast_ari_response_alloc_failed(response);
54                 return;
55         }
56
57         i = ao2_iterator_init(recordings, 0);
58         while ((obj = ao2_iterator_next(&i))) {
59                 RAII_VAR(struct stasis_app_stored_recording *, recording, obj,
60                         ao2_cleanup);
61
62                 int r = ast_json_array_append(
63                         json, stasis_app_stored_recording_to_json(recording));
64                 if (r != 0) {
65                         ast_ari_response_alloc_failed(response);
66                         ao2_iterator_destroy(&i);
67                         return;
68                 }
69         }
70         ao2_iterator_destroy(&i);
71
72         ast_ari_response_ok(response, ast_json_ref(json));
73 }
74
75 void ast_ari_recordings_get_stored(struct ast_variable *headers,
76         struct ast_ari_recordings_get_stored_args *args,
77         struct ast_ari_response *response)
78 {
79         RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
80                 ao2_cleanup);
81         struct ast_json *json;
82
83         recording = stasis_app_stored_recording_find_by_name(
84                 args->recording_name);
85         if (recording == NULL) {
86                 ast_ari_response_error(response, 404, "Not Found",
87                         "Recording not found");
88                 return;
89         }
90
91         json = stasis_app_stored_recording_to_json(recording);
92         if (json == NULL) {
93                 ast_ari_response_error(response, 500,
94                         "Internal Server Error", "Error building response");
95                 return;
96         }
97
98         ast_ari_response_ok(response, json);
99 }
100
101 void ast_ari_recordings_get_stored_file(struct ast_tcptls_session_instance *ser,
102         struct ast_variable *headers, struct ast_ari_recordings_get_stored_file_args *args,
103         struct ast_ari_response *response)
104 {
105         RAII_VAR(struct stasis_app_stored_recording *, recording,
106                 stasis_app_stored_recording_find_by_name(args->recording_name),
107                 ao2_cleanup);
108         static const char *format_type_names[AST_MEDIA_TYPE_TEXT + 1] = {
109                 [AST_MEDIA_TYPE_UNKNOWN] = "binary",
110                 [AST_MEDIA_TYPE_AUDIO] = "audio",
111                 [AST_MEDIA_TYPE_VIDEO] = "video",
112                 [AST_MEDIA_TYPE_IMAGE] = "image",
113                 [AST_MEDIA_TYPE_TEXT] = "text",
114         };
115         struct ast_format *format;
116
117         response->message = ast_json_null();
118
119         if (!recording) {
120                 ast_ari_response_error(response, 404, "Not Found",
121                         "Recording not found");
122                 return;
123         }
124
125         format = ast_get_format_for_file_ext(stasis_app_stored_recording_get_extension(recording));
126         if (!format) {
127                 ast_ari_response_error(response, 500, "Internal Server Error",
128                         "Format specified by recording not available or loaded");
129                 return;
130         }
131
132         response->fd = open(stasis_app_stored_recording_get_filename(recording), O_RDONLY);
133         if (response->fd < 0) {
134                 ast_ari_response_error(response, 403, "Forbidden",
135                         "Recording could not be opened");
136                 return;
137         }
138
139         ast_str_append(&response->headers, 0, "Content-Type: %s/%s\r\n",
140                 format_type_names[ast_format_get_type(format)],
141                 stasis_app_stored_recording_get_extension(recording));
142         ast_ari_response_ok(response, ast_json_null());
143 }
144
145 void ast_ari_recordings_copy_stored(struct ast_variable *headers,
146         struct ast_ari_recordings_copy_stored_args *args,
147         struct ast_ari_response *response)
148 {
149         RAII_VAR(struct stasis_app_stored_recording *, src_recording, NULL,
150                 ao2_cleanup);
151         RAII_VAR(struct stasis_app_stored_recording *, dst_recording, NULL,
152                 ao2_cleanup);
153         struct ast_json *json;
154         int res;
155
156         src_recording = stasis_app_stored_recording_find_by_name(
157                 args->recording_name);
158         if (src_recording == NULL) {
159                 ast_ari_response_error(response, 404, "Not Found",
160                         "Recording not found");
161                 return;
162         }
163
164         dst_recording = stasis_app_stored_recording_find_by_name(
165                 args->destination_recording_name);
166         if (dst_recording) {
167                 ast_ari_response_error(response, 409, "Conflict",
168                         "A recording with the same name already exists on the system");
169                 return;
170         }
171
172         /* See if we got our name rejected */
173         switch (errno) {
174         case EINVAL:
175                 ast_ari_response_error(response, 400, "Bad request",
176                         "Invalid destination recording name");
177                 return;
178         case EACCES:
179                 ast_ari_response_error(response, 403, "Forbidden",
180                         "Destination file path is forbidden");
181                 return;
182         default:
183                 break;
184         }
185
186         res = stasis_app_stored_recording_copy(src_recording,
187                 args->destination_recording_name, &dst_recording);
188         if (res) {
189                 switch (errno) {
190                 case EACCES:
191                 case EPERM:
192                         ast_ari_response_error(response, 500,
193                                 "Internal Server Error",
194                                 "Copy failed");
195                         break;
196                 default:
197                         ast_log(LOG_WARNING,
198                                 "Unexpected error copying recording %s to %s: %s\n",
199                                 args->recording_name, args->destination_recording_name, strerror(errno));
200                         ast_ari_response_error(response, 500,
201                                 "Internal Server Error",
202                                 "Copy failed");
203                         break;
204                 }
205                 return;
206         }
207
208         json = stasis_app_stored_recording_to_json(dst_recording);
209         if (json == NULL) {
210                 ast_ari_response_error(response, 500,
211                         "Internal Server Error", "Error building response");
212                 return;
213         }
214
215         ast_ari_response_ok(response, json);
216 }
217
218 void ast_ari_recordings_delete_stored(struct ast_variable *headers,
219         struct ast_ari_recordings_delete_stored_args *args,
220         struct ast_ari_response *response)
221 {
222         RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
223                 ao2_cleanup);
224         int res;
225
226         recording = stasis_app_stored_recording_find_by_name(
227                 args->recording_name);
228         if (recording == NULL) {
229                 ast_ari_response_error(response, 404, "Not Found",
230                         "Recording not found");
231                 return;
232         }
233
234         res = stasis_app_stored_recording_delete(recording);
235
236         if (res != 0) {
237                 switch (errno) {
238                 case EACCES:
239                 case EPERM:
240                         ast_ari_response_error(response, 500,
241                                 "Internal Server Error",
242                                 "Delete failed");
243                         break;
244                 default:
245                         ast_log(LOG_WARNING,
246                                 "Unexpected error deleting recording %s: %s\n",
247                                 args->recording_name, strerror(errno));
248                         ast_ari_response_error(response, 500,
249                                 "Internal Server Error",
250                                 "Delete failed");
251                         break;
252                 }
253                 return;
254         }
255
256         ast_ari_response_no_content(response);
257 }
258
259 void ast_ari_recordings_get_live(struct ast_variable *headers,
260         struct ast_ari_recordings_get_live_args *args,
261         struct ast_ari_response *response)
262 {
263         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
264         struct ast_json *json;
265
266         recording = stasis_app_recording_find_by_name(args->recording_name);
267         if (recording == NULL) {
268                 ast_ari_response_error(response, 404, "Not Found",
269                         "Recording not found");
270                 return;
271         }
272
273         json = stasis_app_recording_to_json(recording);
274         if (json == NULL) {
275                 ast_ari_response_error(response, 500,
276                         "Internal Server Error", "Error building response");
277                 return;
278         }
279
280         ast_ari_response_ok(response, json);
281 }
282
283 static void control_recording(const char *name,
284         enum stasis_app_recording_media_operation operation,
285         struct ast_ari_response *response)
286 {
287         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
288         enum stasis_app_recording_oper_results res;
289
290         recording = stasis_app_recording_find_by_name(name);
291         if (recording == NULL) {
292                 ast_ari_response_error(response, 404, "Not Found",
293                         "Recording not found");
294                 return;
295         }
296
297         res = stasis_app_recording_operation(recording, operation);
298
299         switch (res) {
300         case STASIS_APP_RECORDING_OPER_OK:
301                 ast_ari_response_no_content(response);
302                 return;
303         case STASIS_APP_RECORDING_OPER_FAILED:
304                 ast_ari_response_error(response, 500,
305                         "Internal Server Error", "Recording operation failed");
306                 return;
307         case STASIS_APP_RECORDING_OPER_NOT_RECORDING:
308                 ast_ari_response_error(response, 409,
309                         "Conflict", "Recording not in session");
310         }
311 }
312
313 void ast_ari_recordings_cancel(struct ast_variable *headers,
314         struct ast_ari_recordings_cancel_args *args,
315         struct ast_ari_response *response)
316 {
317         control_recording(args->recording_name, STASIS_APP_RECORDING_CANCEL,
318                 response);
319 }
320
321 void ast_ari_recordings_stop(struct ast_variable *headers,
322         struct ast_ari_recordings_stop_args *args,
323         struct ast_ari_response *response)
324 {
325         control_recording(args->recording_name, STASIS_APP_RECORDING_STOP,
326                 response);
327 }
328
329 void ast_ari_recordings_pause(struct ast_variable *headers,
330         struct ast_ari_recordings_pause_args *args,
331         struct ast_ari_response *response)
332 {
333         control_recording(args->recording_name, STASIS_APP_RECORDING_PAUSE,
334                 response);
335 }
336
337 void ast_ari_recordings_unpause(struct ast_variable *headers,
338         struct ast_ari_recordings_unpause_args *args,
339         struct ast_ari_response *response)
340 {
341         control_recording(args->recording_name, STASIS_APP_RECORDING_UNPAUSE,
342                 response);
343 }
344
345 void ast_ari_recordings_mute(struct ast_variable *headers,
346         struct ast_ari_recordings_mute_args *args,
347         struct ast_ari_response *response)
348 {
349         control_recording(args->recording_name, STASIS_APP_RECORDING_MUTE,
350                 response);
351 }
352
353 void ast_ari_recordings_unmute(struct ast_variable *headers,
354         struct ast_ari_recordings_unmute_args *args,
355         struct ast_ari_response *response)
356 {
357         control_recording(args->recording_name, STASIS_APP_RECORDING_UNMUTE,
358                 response);
359 }