static struct command_task command_task_struct;
static struct signal_task *signal_task;
-static enum play_mode current_play_mode;
-static char *current_mop; /* mode or playlist specifier. NULL means dummy mood */
+static enum play_mode current_play_mode, previous_play_mode;
+static char *current_mop, *previous_mop; /* NULL means dummy mood */
extern uint32_t afs_socket_cookie;
{
enum play_mode mode;
int ret;
- char *msg;
+ char *errmsg;
if (!arg) { /* load dummy mood */
- ret = mood_load(NULL, NULL, &msg);
+ ret = mood_load(NULL, NULL, &errmsg);
mode = PLAY_MODE_MOOD;
+ } else if (!strcmp(arg, "-")) { /* load previous mop */
+ char *mop = previous_mop? previous_mop + 2 : NULL;
+ if (previous_play_mode == PLAY_MODE_MOOD)
+ ret = mood_load(mop, NULL, &errmsg);
+ else
+ ret = playlist_load(mop, NULL, &errmsg);
+ mode = previous_play_mode;
} else if (!strncmp(arg, "p/", 2)) {
- ret = playlist_load(arg + 2, NULL, &msg);
+ ret = playlist_load(arg + 2, NULL, &errmsg);
mode = PLAY_MODE_PLAYLIST;
} else if (!strncmp(arg, "m/", 2)) {
- ret = mood_load(arg + 2, NULL, &msg);
+ ret = mood_load(arg + 2, NULL, &errmsg);
mode = PLAY_MODE_MOOD;
} else {
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- msg = make_message("%s: parse error\n", arg);
+ errmsg = make_message("%s: parse error\n", arg);
}
if (pb)
- para_printf(pb, "%s", msg);
- free(msg);
+ para_printf(pb, "%s", errmsg);
+ free(errmsg);
if (ret < 0)
return ret;
- current_play_mode = mode;
/*
* We get called with arg == current_mop from the signal dispatcher
* after SIGHUP and from the error path of the select command to
- * re-select the current mood or playlist. In this case the assignment
- * to current_mop below would result in a use-after-free condition.
+ * re-select the current mood or playlist. Don't update the four global
+ * mop variables in these cases.
*/
if (arg != current_mop) {
- free(current_mop);
- current_mop = arg? para_strdup(arg) : NULL;
+ previous_play_mode = current_play_mode;
+ current_play_mode = mode;
+ if (arg && !strcmp(arg, "-")) {
+ char *tmp = current_mop;
+ current_mop = previous_mop;
+ previous_mop = tmp;
+ } else {
+ free(previous_mop);
+ previous_mop = current_mop;
+ current_mop = arg? para_strdup(arg) : NULL;
+ }
}
/* Notify the server about the mood/playlist change. */
mutex_lock(mmd_mutex);
- strncpy(mmd->afs_mode_string, arg? arg: "dummy",
- sizeof(mmd->afs_mode_string));
+ snprintf(mmd->afs_mode_string, sizeof(mmd->afs_mode_string) - 1,
+ "%s", current_mop? current_mop : "dummy");
mmd->afs_mode_string[sizeof(mmd->afs_mode_string) - 1] = '\0';
mmd->events++;
mutex_unlock(mmd_mutex);
signal_shutdown(signal_task);
free_status_items();
free(current_mop);
+ free(previous_mop);
free_lpr();
if (ret < 0)
PARA_EMERG_LOG("%s\n", para_strerror(-ret));