ari: Add a copy operation for stored recordings
[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 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "asterisk/stasis_app_recording.h"
31 #include "resource_recordings.h"
32
33 void ast_ari_recordings_list_stored(struct ast_variable *headers,
34         struct ast_ari_recordings_list_stored_args *args,
35         struct ast_ari_response *response)
36 {
37         RAII_VAR(struct ao2_container *, recordings, NULL, ao2_cleanup);
38         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
39         struct ao2_iterator i;
40         void *obj;
41
42         recordings = stasis_app_stored_recording_find_all();
43
44         if (!recordings) {
45                 ast_ari_response_alloc_failed(response);
46                 return;
47         }
48
49         json = ast_json_array_create();
50         if (!json) {
51                 ast_ari_response_alloc_failed(response);
52                 return;
53         }
54
55         i = ao2_iterator_init(recordings, 0);
56         while ((obj = ao2_iterator_next(&i))) {
57                 RAII_VAR(struct stasis_app_stored_recording *, recording, obj,
58                         ao2_cleanup);
59
60                 int r = ast_json_array_append(
61                         json, stasis_app_stored_recording_to_json(recording));
62                 if (r != 0) {
63                         ast_ari_response_alloc_failed(response);
64                         ao2_iterator_destroy(&i);
65                         return;
66                 }
67         }
68         ao2_iterator_destroy(&i);
69
70         ast_ari_response_ok(response, ast_json_ref(json));
71 }
72
73 void ast_ari_recordings_get_stored(struct ast_variable *headers,
74         struct ast_ari_recordings_get_stored_args *args,
75         struct ast_ari_response *response)
76 {
77         RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
78                 ao2_cleanup);
79         struct ast_json *json;
80
81         recording = stasis_app_stored_recording_find_by_name(
82                 args->recording_name);
83         if (recording == NULL) {
84                 ast_ari_response_error(response, 404, "Not Found",
85                         "Recording not found");
86                 return;
87         }
88
89         json = stasis_app_stored_recording_to_json(recording);
90         if (json == NULL) {
91                 ast_ari_response_error(response, 500,
92                         "Internal Server Error", "Error building response");
93                 return;
94         }
95
96         ast_ari_response_ok(response, json);
97 }
98
99 void ast_ari_recordings_copy_stored(struct ast_variable *headers,
100         struct ast_ari_recordings_copy_stored_args *args,
101         struct ast_ari_response *response)
102 {
103         RAII_VAR(struct stasis_app_stored_recording *, src_recording, NULL,
104                 ao2_cleanup);
105         RAII_VAR(struct stasis_app_stored_recording *, dst_recording, NULL,
106                 ao2_cleanup);
107         struct ast_json *json;
108         int res;
109
110         src_recording = stasis_app_stored_recording_find_by_name(
111                 args->recording_name);
112         if (src_recording == NULL) {
113                 ast_ari_response_error(response, 404, "Not Found",
114                         "Recording not found");
115                 return;
116         }
117
118         dst_recording = stasis_app_stored_recording_find_by_name(
119                 args->destination_recording_name);
120         if (dst_recording) {
121                 ast_ari_response_error(response, 409, "Conflict",
122                         "A recording with the same name already exists on the system");
123                 return;
124         }
125
126         /* See if we got our name rejected */
127         switch (errno) {
128         case EINVAL:
129                 ast_ari_response_error(response, 400, "Bad request",
130                         "Invalid destination recording name");
131                 return;
132         case EACCES:
133                 ast_ari_response_error(response, 403, "Forbidden",
134                         "Destination file path is forbidden");
135                 return;
136         default:
137                 break;
138         }
139
140         res = stasis_app_stored_recording_copy(src_recording,
141                 args->destination_recording_name, &dst_recording);
142         if (res) {
143                 switch (errno) {
144                 case EACCES:
145                 case EPERM:
146                         ast_ari_response_error(response, 500,
147                                 "Internal Server Error",
148                                 "Copy failed");
149                         break;
150                 default:
151                         ast_log(LOG_WARNING,
152                                 "Unexpected error copying recording %s to %s: %s\n",
153                                 args->recording_name, args->destination_recording_name, strerror(errno));
154                         ast_ari_response_error(response, 500,
155                                 "Internal Server Error",
156                                 "Copy failed");
157                         break;
158                 }
159                 return;
160         }
161
162         json = stasis_app_stored_recording_to_json(dst_recording);
163         if (json == NULL) {
164                 ast_ari_response_error(response, 500,
165                         "Internal Server Error", "Error building response");
166                 return;
167         }
168
169         ast_ari_response_ok(response, json);
170 }
171
172 void ast_ari_recordings_delete_stored(struct ast_variable *headers,
173         struct ast_ari_recordings_delete_stored_args *args,
174         struct ast_ari_response *response)
175 {
176         RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
177                 ao2_cleanup);
178         int res;
179
180         recording = stasis_app_stored_recording_find_by_name(
181                 args->recording_name);
182         if (recording == NULL) {
183                 ast_ari_response_error(response, 404, "Not Found",
184                         "Recording not found");
185                 return;
186         }
187
188         res = stasis_app_stored_recording_delete(recording);
189
190         if (res != 0) {
191                 switch (errno) {
192                 case EACCES:
193                 case EPERM:
194                         ast_ari_response_error(response, 500,
195                                 "Internal Server Error",
196                                 "Delete failed");
197                         break;
198                 default:
199                         ast_log(LOG_WARNING,
200                                 "Unexpected error deleting recording %s: %s\n",
201                                 args->recording_name, strerror(errno));
202                         ast_ari_response_error(response, 500,
203                                 "Internal Server Error",
204                                 "Delete failed");
205                         break;
206                 }
207                 return;
208         }
209
210         ast_ari_response_no_content(response);
211 }
212
213 void ast_ari_recordings_get_live(struct ast_variable *headers,
214         struct ast_ari_recordings_get_live_args *args,
215         struct ast_ari_response *response)
216 {
217         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
218         struct ast_json *json;
219
220         recording = stasis_app_recording_find_by_name(args->recording_name);
221         if (recording == NULL) {
222                 ast_ari_response_error(response, 404, "Not Found",
223                         "Recording not found");
224                 return;
225         }
226
227         json = stasis_app_recording_to_json(recording);
228         if (json == NULL) {
229                 ast_ari_response_error(response, 500,
230                         "Internal Server Error", "Error building response");
231                 return;
232         }
233
234         ast_ari_response_ok(response, json);
235 }
236
237 static void control_recording(const char *name,
238         enum stasis_app_recording_media_operation operation,
239         struct ast_ari_response *response)
240 {
241         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
242         enum stasis_app_recording_oper_results res;
243
244         recording = stasis_app_recording_find_by_name(name);
245         if (recording == NULL) {
246                 ast_ari_response_error(response, 404, "Not Found",
247                         "Recording not found");
248                 return;
249         }
250
251         res = stasis_app_recording_operation(recording, operation);
252
253         switch (res) {
254         case STASIS_APP_RECORDING_OPER_OK:
255                 ast_ari_response_no_content(response);
256                 return;
257         case STASIS_APP_RECORDING_OPER_FAILED:
258                 ast_ari_response_error(response, 500,
259                         "Internal Server Error", "Recording operation failed");
260                 return;
261         case STASIS_APP_RECORDING_OPER_NOT_RECORDING:
262                 ast_ari_response_error(response, 409,
263                         "Conflict", "Recording not in session");
264         }
265 }
266
267 void ast_ari_recordings_cancel(struct ast_variable *headers,
268         struct ast_ari_recordings_cancel_args *args,
269         struct ast_ari_response *response)
270 {
271         control_recording(args->recording_name, STASIS_APP_RECORDING_CANCEL,
272                 response);
273 }
274
275 void ast_ari_recordings_stop(struct ast_variable *headers,
276         struct ast_ari_recordings_stop_args *args,
277         struct ast_ari_response *response)
278 {
279         control_recording(args->recording_name, STASIS_APP_RECORDING_STOP,
280                 response);
281 }
282
283 void ast_ari_recordings_pause(struct ast_variable *headers,
284         struct ast_ari_recordings_pause_args *args,
285         struct ast_ari_response *response)
286 {
287         control_recording(args->recording_name, STASIS_APP_RECORDING_PAUSE,
288                 response);
289 }
290
291 void ast_ari_recordings_unpause(struct ast_variable *headers,
292         struct ast_ari_recordings_unpause_args *args,
293         struct ast_ari_response *response)
294 {
295         control_recording(args->recording_name, STASIS_APP_RECORDING_UNPAUSE,
296                 response);
297 }
298
299 void ast_ari_recordings_mute(struct ast_variable *headers,
300         struct ast_ari_recordings_mute_args *args,
301         struct ast_ari_response *response)
302 {
303         control_recording(args->recording_name, STASIS_APP_RECORDING_MUTE,
304                 response);
305 }
306
307 void ast_ari_recordings_unmute(struct ast_variable *headers,
308         struct ast_ari_recordings_unmute_args *args,
309         struct ast_ari_response *response)
310 {
311         control_recording(args->recording_name, STASIS_APP_RECORDING_UNMUTE,
312                 response);
313 }