+struct scheduled_event {
+ time_t when;
+ struct kvp *actiondata;
+ char *id;
+};
+
+static int compare_event(const void *av, const void *bv) {
+ struct scheduled_event *a = (void *)av, *b = (void *)bv;
+
+ /* Primary sort key is the trigger time */
+ if(a->when < b->when)
+ return -1;
+ else if(a->when > b->when)
+ return 1;
+ /* For events that go off at the same time just sort by ID */
+ return strcmp(a->id, b->id);
+}
+
+static void cf_schedule_list(char attribute((unused)) **argv) {
+ char **ids;
+ int nids, n;
+ struct scheduled_event *events;
+ char tb[128];
+ const char *action, *key, *value, *priority;
+ int prichar;
+
+ /* Get all known events */
+ if(disorder_schedule_list(getclient(), &ids, &nids))
+ exit(EXIT_FAILURE);
+ events = xcalloc(nids, sizeof *events);
+ for(n = 0; n < nids; ++n) {
+ events[n].id = ids[n];
+ if(disorder_schedule_get(getclient(), ids[n], &events[n].actiondata))
+ exit(EXIT_FAILURE);
+ events[n].when = atoll(kvp_get(events[n].actiondata, "when"));
+ }
+ /* Sort by trigger time */
+ qsort(events, nids, sizeof *events, compare_event);
+ /* Display them */
+ for(n = 0; n < nids; ++n) {
+ strftime(tb, sizeof tb, "%Y-%m-%d %H:%M:%S %Z", localtime(&events[n].when));
+ action = kvp_get(events[n].actiondata, "action");
+ priority = kvp_get(events[n].actiondata, "priority");
+ if(!strcmp(priority, "junk"))
+ prichar = 'J';
+ else if(!strcmp(priority, "normal"))
+ prichar = 'N';
+ else
+ prichar = '?';
+ xprintf("%11s %-25s %c %-8s %s",
+ events[n].id, tb, prichar, kvp_get(events[n].actiondata, "who"),
+ action);
+ if(!strcmp(action, "play"))
+ xprintf(" %s",
+ nullcheck(utf82mb(kvp_get(events[n].actiondata, "track"))));
+ else if(!strcmp(action, "set-global")) {
+ key = kvp_get(events[n].actiondata, "key");
+ value = kvp_get(events[n].actiondata, "value");
+ if(value)
+ xprintf(" %s=%s",
+ nullcheck(utf82mb(key)),
+ nullcheck(utf82mb(value)));
+ else
+ xprintf(" %s unset",
+ nullcheck(utf82mb(key)));
+ }
+ xprintf("\n");
+ }
+}
+
+static void cf_schedule_del(char **argv) {
+ if(disorder_schedule_del(getclient(), argv[0]))
+ exit(EXIT_FAILURE);
+}
+
+static void cf_schedule_play(char **argv) {
+ if(disorder_schedule_add(getclient(),
+ dateparse(argv[0]),
+ argv[1],
+ "play",
+ argv[2]))
+ exit(EXIT_FAILURE);
+}
+
+static void cf_schedule_set_global(char **argv) {
+ if(disorder_schedule_add(getclient(),
+ dateparse(argv[0]),
+ argv[1],
+ "set-global",
+ argv[2],
+ argv[3]))
+ exit(EXIT_FAILURE);
+}
+
+static void cf_schedule_unset_global(char **argv) {
+ if(disorder_schedule_add(getclient(),
+ dateparse(argv[0]),
+ argv[1],
+ "set-global",
+ argv[2],
+ (char *)0))
+ exit(EXIT_FAILURE);
+}
+
+static void cf_adopt(char **argv) {
+ if(disorder_adopt(getclient(), argv[0]))
+ exit(EXIT_FAILURE);
+}
+
+static void cf_playlists(char attribute((unused)) **argv) {
+ char **vec;
+ int nvec;
+
+ if(disorder_playlists(getclient(), &vec, &nvec))
+ exit(EXIT_FAILURE);
+ for(int n = 0; n < nvec; ++n)
+ xprintf("%s\n", nullcheck(utf82mb(vec[n])));
+ free_strings(nvec, vec);
+}
+
+static void cf_playlist_del(char **argv) {
+ if(disorder_playlist_delete(getclient(), argv[0]))
+ exit(EXIT_FAILURE);
+}
+
+static void cf_playlist_get(char **argv) {
+ char **vec;
+ int nvec;
+
+ if(disorder_playlist_get(getclient(), argv[0], &vec, &nvec))
+ exit(EXIT_FAILURE);
+ for(int n = 0; n < nvec; ++n)
+ xprintf("%s\n", nullcheck(utf82mb(vec[n])));
+ free_strings(nvec, vec);
+}
+
+static void cf_playlist_set(char **argv) {
+ struct vector v[1];
+ FILE *input;
+ const char *tag;
+ char *l;
+
+ if(argv[1]) {
+ // Read track list from file
+ if(!(input = fopen(argv[1], "r")))
+ disorder_fatal(errno, "opening %s", argv[1]);
+ tag = argv[1];
+ } else {
+ // Read track list from standard input
+ input = stdin;
+ tag = "stdin";
+ }
+ vector_init(v);
+ while(!inputline(tag, input, &l, '\n')) {
+ if(!strcmp(l, "."))
+ break;
+ vector_append(v, l);
+ }
+ if(ferror(input))
+ disorder_fatal(errno, "reading %s", tag);
+ if(input != stdin)
+ fclose(input);
+ if(disorder_playlist_lock(getclient(), argv[0])
+ || disorder_playlist_set(getclient(), argv[0], v->vec, v->nvec)
+ || disorder_playlist_unlock(getclient()))
+ exit(EXIT_FAILURE);
+}
+