[asterisk-commits] dlee: trunk r393550 - in /trunk: ./ apps/ include/asterisk/ main/ res/ res/st...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Jul 3 12:58:54 CDT 2013
Author: dlee
Date: Wed Jul 3 12:58:45 2013
New Revision: 393550
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=393550
Log:
ARI - channel recording support
This patch is the first step in adding recording support to the
Asterisk REST Interface.
Recordings are stored in /var/spool/recording. Since recordings may be
destructive (overwriting existing files), the API rejects attempts to
escape the recording directory (avoiding issues if someone attempts to
record to ../../lib/sounds/greeting, for example).
(closes issue ASTERISK-21594)
(closes issue ASTERISK-21581)
Review: https://reviewboard.asterisk.org/r/2612/
Added:
trunk/include/asterisk/stasis_app_recording.h
- copied unchanged from r393549, team/dlee/record/include/asterisk/stasis_app_recording.h
trunk/res/res_stasis_recording.c
- copied unchanged from r393549, team/dlee/record/res/res_stasis_recording.c
trunk/res/res_stasis_recording.exports.in
- copied unchanged from r393549, team/dlee/record/res/res_stasis_recording.exports.in
Modified:
trunk/Makefile
trunk/apps/app_minivm.c
trunk/apps/app_voicemail.c
trunk/include/asterisk/app.h
trunk/include/asterisk/channel.h
trunk/include/asterisk/file.h
trunk/include/asterisk/paths.h
trunk/include/asterisk/utils.h
trunk/main/app.c
trunk/main/asterisk.c
trunk/main/channel.c
trunk/main/file.c
trunk/main/utils.c
trunk/res/res_stasis_http_bridges.c
trunk/res/res_stasis_http_channels.c
trunk/res/res_stasis_http_recordings.c
trunk/res/res_stasis_playback.c
trunk/res/stasis_http/resource_channels.c
trunk/res/stasis_http/resource_channels.h
trunk/res/stasis_http/resource_recordings.c
trunk/res/stasis_http/resource_recordings.h
trunk/rest-api-templates/asterisk_processor.py
trunk/rest-api-templates/swagger_model.py
trunk/rest-api/api-docs/channels.json
trunk/rest-api/api-docs/recordings.json
trunk/tests/test_utils.c
Modified: trunk/Makefile
URL: http://svnview.digium.com/svn/asterisk/trunk/Makefile?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/Makefile (original)
+++ trunk/Makefile Wed Jul 3 12:58:45 2013
@@ -536,7 +536,8 @@
INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTETCDIR)" "$(ASTVARRUNDIR)" \
"$(ASTSPOOLDIR)" "$(ASTSPOOLDIR)/dictate" "$(ASTSPOOLDIR)/meetme" \
"$(ASTSPOOLDIR)/monitor" "$(ASTSPOOLDIR)/system" "$(ASTSPOOLDIR)/tmp" \
- "$(ASTSPOOLDIR)/voicemail" "$(ASTHEADERDIR)" "$(ASTHEADERDIR)/doxygen" \
+ "$(ASTSPOOLDIR)/voicemail" "$(ASTSPOOLDIR)/recording" \
+ "$(ASTHEADERDIR)" "$(ASTHEADERDIR)/doxygen" \
"$(ASTLOGDIR)" "$(ASTLOGDIR)/cdr-csv" "$(ASTLOGDIR)/cdr-custom" \
"$(ASTLOGDIR)/cel-custom" "$(ASTDATADIR)" "$(ASTDATADIR)/documentation" \
"$(ASTDATADIR)/documentation/thirdparty" "$(ASTDATADIR)/firmware" \
Modified: trunk/apps/app_minivm.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_minivm.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/apps/app_minivm.c (original)
+++ trunk/apps/app_minivm.c Wed Jul 3 12:58:45 2013
@@ -1674,7 +1674,7 @@
ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
if (ast_test_flag(vmu, MVM_OPERATOR))
canceldtmf = "0";
- cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
+ cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
if (record_gain)
ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
if (cmd == -1) /* User has hung up, no options to give */
Modified: trunk/apps/app_voicemail.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_voicemail.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/apps/app_voicemail.c (original)
+++ trunk/apps/app_voicemail.c Wed Jul 3 12:58:45 2013
@@ -14684,7 +14684,7 @@
ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
if (ast_test_flag(vmu, VM_OPERATOR))
canceldtmf = "0";
- cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
+ cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
if (strchr(canceldtmf, cmd)) {
/* need this flag here to distinguish between pressing '0' during message recording or after */
canceleddtmf = 1;
Modified: trunk/include/asterisk/app.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/app.h?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/include/asterisk/app.h (original)
+++ trunk/include/asterisk/app.h Wed Jul 3 12:58:45 2013
@@ -691,8 +691,22 @@
int ast_play_and_wait(struct ast_channel *chan, const char *fn);
/*!
+ * Possible actions to take if a recording already exists
+ * \since 12
+ */
+enum ast_record_if_exists {
+ /*! Fail the recording. */
+ AST_RECORD_IF_EXISTS_FAIL,
+ /*! Overwrite the existing recording. */
+ AST_RECORD_IF_EXISTS_OVERWRITE,
+ /*! Append to the existing recording. */
+ AST_RECORD_IF_EXISTS_APPEND,
+};
+
+/*!
* \brief Record a file based on input from a channel
- * This function will play "auth-thankyou" upon successful recording.
+ * This function will play "auth-thankyou" upon successful recording if
+ * skip_confirmation_sound is false.
*
* \param chan the channel being recorded
* \param playfile Filename of sound to play before recording begins
@@ -706,13 +720,15 @@
* \param path Optional filesystem path to unlock
* \param acceptdtmf Character of DTMF to end and accept the recording
* \param canceldtmf Character of DTMF to end and cancel the recording
+ * \param skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps.
+ * \param if_exists Action to take if recording already exists.
*
* \retval -1 failure or hangup
* \retval 'S' Recording ended from silence timeout
* \retval 't' Recording ended from the message exceeding the maximum duration
* \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.
*/
-int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf);
+int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists);
/*!
* \brief Record a file based on input from a channel. Use default accept and cancel DTMF.
Modified: trunk/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/channel.h?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Wed Jul 3 12:58:45 2013
@@ -1602,6 +1602,18 @@
* \retval non-zero on failure
*/
int ast_answer(struct ast_channel *chan);
+
+/*!
+ * \brief Answer a channel, if it's not already answered.
+ *
+ * \param chan channel to answer
+ *
+ * \details See ast_answer()
+ *
+ * \retval 0 on success
+ * \retval non-zero on failure
+ */
+int ast_auto_answer(struct ast_channel *chan);
/*!
* \brief Answer a channel
Modified: trunk/include/asterisk/file.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/file.h?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/include/asterisk/file.h (original)
+++ trunk/include/asterisk/file.h Wed Jul 3 12:58:45 2013
@@ -64,8 +64,8 @@
*/
typedef void (ast_waitstream_fr_cb)(struct ast_channel *chan, long ms, enum ast_waitstream_fr_cb_values val);
-/*!
- * \brief Streams a file
+/*!
+ * \brief Streams a file
* \param c channel to stream the file to
* \param filename the name of the file you wish to stream, minus the extension
* \param preflang the preferred language you wish to have the file streamed to you in
@@ -86,12 +86,12 @@
*/
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits);
-/*!
- * \brief Stops a stream
+/*!
+ * \brief Stops a stream
*
* \param c The channel you wish to stop playback on
*
- * Stop playback of a stream
+ * Stop playback of a stream
*
* \retval 0 always
*
Modified: trunk/include/asterisk/paths.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/paths.h?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/include/asterisk/paths.h (original)
+++ trunk/include/asterisk/paths.h Wed Jul 3 12:58:45 2013
@@ -23,6 +23,7 @@
extern const char *ast_config_AST_MODULE_DIR;
extern const char *ast_config_AST_SPOOL_DIR;
extern const char *ast_config_AST_MONITOR_DIR;
+extern const char *ast_config_AST_RECORDING_DIR;
extern const char *ast_config_AST_VAR_DIR;
extern const char *ast_config_AST_DATA_DIR;
extern const char *ast_config_AST_LOG_DIR;
Modified: trunk/include/asterisk/utils.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/utils.h?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/include/asterisk/utils.h (original)
+++ trunk/include/asterisk/utils.h Wed Jul 3 12:58:45 2013
@@ -717,6 +717,19 @@
* Creates a directory path, creating parent directories as needed.
*/
int ast_mkdir(const char *path, int mode);
+
+/*!
+ * \brief Recursively create directory path, but only if it resolves within
+ * the given \a base_path.
+ *
+ * If \a base_path does not exist, it will not be created and this function
+ * returns \c EPERM.
+ *
+ * \param path The directory path to create
+ * \param mode The permissions with which to try to create the directory
+ * \return 0 on success or an error code otherwise
+ */
+int ast_safe_mkdir(const char *base_path, const char *path, int mode);
#define ARRAY_LEN(a) (size_t) (sizeof(a) / sizeof(0[a]))
Modified: trunk/main/app.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/app.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/main/app.c (original)
+++ trunk/main/app.c Wed Jul 3 12:58:45 2013
@@ -1169,7 +1169,7 @@
* \retval 't' Recording ended from the message exceeding the maximum duration, or via DTMF in prepend mode
* \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.
*/
-static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound)
+static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
{
int d = 0;
char *fmts;
@@ -1186,6 +1186,21 @@
struct ast_format rfmt;
struct ast_silence_generator *silgen = NULL;
char prependfile[PATH_MAX];
+ int ioflags; /* IO flags for writing output file */
+
+ ioflags = O_CREAT|O_WRONLY;
+
+ switch (if_exists) {
+ case AST_RECORD_IF_EXISTS_FAIL:
+ ioflags |= O_EXCL;
+ break;
+ case AST_RECORD_IF_EXISTS_OVERWRITE:
+ ioflags |= O_TRUNC;
+ break;
+ case AST_RECORD_IF_EXISTS_APPEND:
+ ioflags |= O_APPEND;
+ break;
+ }
ast_format_clear(&rfmt);
if (silencethreshold < 0) {
@@ -1239,7 +1254,7 @@
end = start = time(NULL); /* pre-initialize end to be same as start in case we never get into loop */
for (x = 0; x < fmtcnt; x++) {
- others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
+ others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, ioflags, 0, AST_FILE_MODE);
ast_verb(3, "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
if (!others[x]) {
@@ -1477,19 +1492,19 @@
static const char default_acceptdtmf[] = "#";
static const char default_canceldtmf[] = "";
-int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
-{
- return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), 0);
+int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
+{
+ return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), skip_confirmation_sound, if_exists);
}
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)
{
- return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0);
+ return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0, AST_RECORD_IF_EXISTS_OVERWRITE);
}
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence)
{
- return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1);
+ return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1, AST_RECORD_IF_EXISTS_OVERWRITE);
}
/* Channel group core functions */
Modified: trunk/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/asterisk.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/main/asterisk.c (original)
+++ trunk/main/asterisk.c Wed Jul 3 12:58:45 2013
@@ -373,6 +373,7 @@
char module_dir[PATH_MAX];
char spool_dir[PATH_MAX];
char monitor_dir[PATH_MAX];
+ char recording_dir[PATH_MAX];
char var_dir[PATH_MAX];
char data_dir[PATH_MAX];
char log_dir[PATH_MAX];
@@ -397,6 +398,7 @@
const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
+const char *ast_config_AST_RECORDING_DIR = cfg_paths.recording_dir;
const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
@@ -3306,6 +3308,7 @@
ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
+ snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir);
ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
@@ -3341,6 +3344,7 @@
} else if (!strcasecmp(v->name, "astspooldir")) {
ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
+ snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
} else if (!strcasecmp(v->name, "astvarlibdir")) {
ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
if (!found.dbdir)
Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Wed Jul 3 12:58:45 2013
@@ -3027,6 +3027,15 @@
int ast_answer(struct ast_channel *chan)
{
return __ast_answer(chan, 0);
+}
+
+inline int ast_auto_answer(struct ast_channel *chan)
+{
+ if (ast_channel_state(chan) == AST_STATE_UP) {
+ /* Already answered */
+ return 0;
+ }
+ return ast_answer(chan);
}
int ast_channel_get_duration(struct ast_channel *chan)
Modified: trunk/main/file.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/file.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/main/file.c (original)
+++ trunk/main/file.c Wed Jul 3 12:58:45 2013
@@ -1020,6 +1020,9 @@
* We close the stream in order to quit queuing frames now, because we might
* change the writeformat, which could result in a subsequent write error, if
* the format is different. */
+ if (f == NULL) {
+ return 0;
+ }
filestream_close(f);
ao2_ref(f, -1);
return 0;
Modified: trunk/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/utils.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/main/utils.c (original)
+++ trunk/main/utils.c Wed Jul 3 12:58:45 2013
@@ -2103,6 +2103,100 @@
return errno;
}
return 0;
+}
+
+static int safe_mkdir(const char *base_path, char *path, int mode)
+{
+ RAII_VAR(char *, absolute_path, NULL, free);
+
+ absolute_path = realpath(path, NULL);
+
+ if (absolute_path) {
+ /* Path exists, but is it in the right place? */
+ if (!ast_begins_with(absolute_path, base_path)) {
+ return EPERM;
+ }
+
+ /* It is in the right place! */
+ return 0;
+ } else {
+ /* Path doesn't exist. */
+
+ /* The slash terminating the subpath we're checking */
+ char *path_term = strchr(path, '/');
+ /* True indicates the parent path is within base_path */
+ int parent_is_safe = 0;
+ int res;
+
+ while (path_term) {
+ RAII_VAR(char *, absolute_subpath, NULL, free);
+
+ /* Truncate the path one past the slash */
+ char c = *(path_term + 1);
+ *(path_term + 1) = '\0';
+ absolute_subpath = realpath(path, NULL);
+
+ if (absolute_subpath) {
+ /* Subpath exists, but is it safe? */
+ parent_is_safe = ast_begins_with(
+ absolute_subpath, base_path);
+ } else if (parent_is_safe) {
+ /* Subpath does not exist, but parent is safe
+ * Create it */
+ res = mkdir(path, mode);
+ if (res != 0) {
+ ast_assert(errno != EEXIST);
+ return errno;
+ }
+ } else {
+ /* Subpath did not exist, parent was not safe
+ * Fail! */
+ errno = EPERM;
+ return errno;
+ }
+ /* Restore the path */
+ *(path_term + 1) = c;
+ /* Move on to the next slash */
+ path_term = strchr(path_term + 1, '/');
+ }
+
+ /* Now to build the final path, but only if it's safe */
+ if (!parent_is_safe) {
+ errno = EPERM;
+ return errno;
+ }
+
+ res = mkdir(path, mode);
+ if (res != 0 && errno != EEXIST) {
+ return errno;
+ }
+
+ return 0;
+ }
+}
+
+int ast_safe_mkdir(const char *base_path, const char *path, int mode)
+{
+ RAII_VAR(char *, absolute_base_path, NULL, free);
+ RAII_VAR(char *, p, NULL, ast_free);
+
+ if (base_path == NULL || path == NULL) {
+ errno = EFAULT;
+ return errno;
+ }
+
+ p = ast_strdup(path);
+ if (p == NULL) {
+ errno = ENOMEM;
+ return errno;
+ }
+
+ absolute_base_path = realpath(base_path, NULL);
+ if (absolute_base_path == NULL) {
+ return errno;
+ }
+
+ return safe_mkdir(absolute_base_path, p, mode);
}
int ast_utils_init(void)
Modified: trunk/res/res_stasis_http_bridges.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_stasis_http_bridges.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/res/res_stasis_http_bridges.c (original)
+++ trunk/res/res_stasis_http_bridges.c Wed Jul 3 12:58:45 2013
@@ -387,10 +387,10 @@
args.max_silence_seconds = atoi(i->value);
} else
if (strcmp(i->name, "append") == 0) {
- args.append = atoi(i->value);
+ args.append = ast_true(i->value);
} else
if (strcmp(i->name, "beep") == 0) {
- args.beep = atoi(i->value);
+ args.beep = ast_true(i->value);
} else
if (strcmp(i->name, "terminateOn") == 0) {
args.terminate_on = (i->value);
Modified: trunk/res/res_stasis_http_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_stasis_http_channels.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/res/res_stasis_http_channels.c (original)
+++ trunk/res/res_stasis_http_channels.c Wed Jul 3 12:58:45 2013
@@ -765,11 +765,11 @@
if (strcmp(i->name, "maxSilenceSeconds") == 0) {
args.max_silence_seconds = atoi(i->value);
} else
- if (strcmp(i->name, "append") == 0) {
- args.append = atoi(i->value);
+ if (strcmp(i->name, "ifExists") == 0) {
+ args.if_exists = (i->value);
} else
if (strcmp(i->name, "beep") == 0) {
- args.beep = atoi(i->value);
+ args.beep = ast_true(i->value);
} else
if (strcmp(i->name, "terminateOn") == 0) {
args.terminate_on = (i->value);
@@ -788,8 +788,9 @@
switch (code) {
case 500: /* Internal server error */
- case 404: /* Channel not found */
- case 409: /* Channel is not in a Stasis application, or the channel is currently bridged with other channels. */
+ case 400: /* Invalid parameters */
+ case 404: /* Channel not found */
+ case 409: /* Channel is not in a Stasis application; the channel is currently bridged with other channels; A recording with the same name is currently in progress. */
is_valid = 1;
break;
default:
Modified: trunk/res/res_stasis_http_recordings.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_stasis_http_recordings.c?view=diff&rev=393550&r1=393549&r2=393550
==============================================================================
--- trunk/res/res_stasis_http_recordings.c (original)
+++ trunk/res/res_stasis_http_recordings.c Wed Jul 3 12:58:45 2013
@@ -91,7 +91,7 @@
#endif /* AST_DEVMODE */
}
/*!
- * \brief Parameter parsing callback for /recordings/stored/{recordingId}.
+ * \brief Parameter parsing callback for /recordings/stored/{recordingName}.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -110,8 +110,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -128,20 +128,20 @@
is_valid = ari_validate_stored_recording(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingId}\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingId}\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/stored/{recordingId}.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/stored/{recordingName}.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -160,8 +160,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -178,13 +178,13 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingId}\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingId}\n");
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}\n");
stasis_http_response_error(response, 500,
"Internal Server Error", "Response validation failed");
}
@@ -233,7 +233,7 @@
#endif /* AST_DEVMODE */
}
/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}.
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -252,8 +252,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -270,20 +270,20 @@
is_valid = ari_validate_live_recording(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -302,8 +302,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -320,20 +320,20 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}/stop.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}/stop.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -352,8 +352,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -370,20 +370,20 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/stop\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/stop\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}/pause.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/stop\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/stop\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}/pause.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -402,8 +402,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -420,20 +420,20 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/pause\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/pause\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}/unpause.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/pause\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/pause\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}/unpause.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -452,8 +452,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -470,20 +470,20 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/unpause\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/unpause\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}/mute.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/unpause\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/unpause\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}/mute.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -502,8 +502,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -520,20 +520,20 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/mute\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/mute\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-/*!
- * \brief Parameter parsing callback for /recordings/live/{recordingId}/unmute.
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/mute\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/mute\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+/*!
+ * \brief Parameter parsing callback for /recordings/live/{recordingName}/unmute.
* \param get_params GET parameters in the HTTP request.
* \param path_vars Path variables extracted from the request.
* \param headers HTTP headers.
@@ -552,8 +552,8 @@
struct ast_variable *i;
for (i = path_vars; i; i = i->next) {
- if (strcmp(i->name, "recordingId") == 0) {
- args.recording_id = (i->value);
+ if (strcmp(i->name, "recordingName") == 0) {
+ args.recording_name = (i->value);
} else
{}
}
@@ -570,22 +570,22 @@
is_valid = ari_validate_void(
response->message);
} else {
- ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingId}/unmute\n", code);
- is_valid = 0;
- }
- }
-
- if (!is_valid) {
- ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingId}/unmute\n");
- stasis_http_response_error(response, 500,
- "Internal Server Error", "Response validation failed");
- }
-#endif /* AST_DEVMODE */
-}
-
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_stored_recordingId = {
- .path_segment = "recordingId",
+ ast_log(LOG_ERROR, "Invalid error response %d for /recordings/live/{recordingName}/unmute\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /recordings/live/{recordingName}/unmute\n");
+ stasis_http_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+}
+
+/*! \brief REST handler for /api-docs/recordings.{format} */
+static struct stasis_rest_handlers recordings_stored_recordingName = {
+ .path_segment = "recordingName",
.is_wildcard = 1,
.callbacks = {
[AST_HTTP_GET] = stasis_http_get_stored_recording_cb,
@@ -601,10 +601,10 @@
[AST_HTTP_GET] = stasis_http_get_stored_recordings_cb,
},
.num_children = 1,
- .children = { &recordings_stored_recordingId, }
-};
-/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingId_stop = {
+ .children = { &recordings_stored_recordingName, }
+};
+/*! \brief REST handler for /api-docs/recordings.{format} */
+static struct stasis_rest_handlers recordings_live_recordingName_stop = {
.path_segment = "stop",
.callbacks = {
[AST_HTTP_POST] = stasis_http_stop_recording_cb,
@@ -613,7 +613,7 @@
.children = { }
};
/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingId_pause = {
+static struct stasis_rest_handlers recordings_live_recordingName_pause = {
.path_segment = "pause",
.callbacks = {
[AST_HTTP_POST] = stasis_http_pause_recording_cb,
@@ -622,7 +622,7 @@
.children = { }
};
/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingId_unpause = {
+static struct stasis_rest_handlers recordings_live_recordingName_unpause = {
.path_segment = "unpause",
.callbacks = {
[AST_HTTP_POST] = stasis_http_unpause_recording_cb,
@@ -631,7 +631,7 @@
.children = { }
};
/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingId_mute = {
+static struct stasis_rest_handlers recordings_live_recordingName_mute = {
.path_segment = "mute",
.callbacks = {
[AST_HTTP_POST] = stasis_http_mute_recording_cb,
@@ -640,7 +640,7 @@
.children = { }
};
/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingId_unmute = {
+static struct stasis_rest_handlers recordings_live_recordingName_unmute = {
.path_segment = "unmute",
.callbacks = {
[AST_HTTP_POST] = stasis_http_unmute_recording_cb,
@@ -649,15 +649,15 @@
.children = { }
};
/*! \brief REST handler for /api-docs/recordings.{format} */
-static struct stasis_rest_handlers recordings_live_recordingId = {
- .path_segment = "recordingId",
[... 909 lines stripped ...]
More information about the asterisk-commits
mailing list