sad

simple audio daemon
git clone git://git.2f30.org/sad.git
Log | Files | Refs | LICENSE

cmd.c (8308B)


      1 #include <sys/select.h>
      2 
      3 #include <ctype.h>
      4 #include <err.h>
      5 #include <fcntl.h>
      6 #include <limits.h>
      7 #include <signal.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <unistd.h>
     12 
     13 #include "sad.h"
     14 
     15 static void
     16 cmdstatus(int fd, char *arg)
     17 {
     18 	Song *s;
     19 	int r = 0;
     20 
     21 	if (!arg[0]) {
     22 		dprintf(fd, "ERR expected argument\n");
     23 		return;
     24 	}
     25 
     26 	if (!strncmp(arg, "random", 7)) {
     27 		r = 1;
     28 		dprintf(fd, "random: %d\n", (getplaylistmode() & RANDOM) == 1);
     29 	} else if (!strncmp(arg, "repeat", 7)) {
     30 		r = 1;
     31 		dprintf(fd, "repeat: %d\n", (getplaylistmode() & REPEAT) == 1);
     32 	} else if (!strncmp(arg, "single", 7)) {
     33 		r = 1;
     34 		dprintf(fd, "single: %d\n", (getplaylistmode() & SINGLE) == 1);
     35 	} else if (!strncmp(arg, "songid", 7)) {
     36 		r = 1;
     37 		s = getcursong();
     38 
     39 		if (!s) {
     40 			dprintf(fd, "ERR no song is active\n");
     41 			return;
     42 		}
     43 
     44 		dprintf(fd, "songid: %d\n", s->id);
     45 	} else if (!strncmp(arg, "playback", 9)) {
     46 		r = 1;
     47 		s = getcursong();
     48 
     49 		dprintf(fd, "playback: ");
     50 
     51 		if (s)
     52 			switch (s->state) {
     53 			case PLAYING:
     54 				dprintf(fd, "play\n");
     55 				break;
     56 			case PAUSED:
     57 				dprintf(fd, "pause\n");
     58 				break;
     59 			case NONE:
     60 				dprintf(fd, "stop\n");
     61 				break;
     62 			}
     63 		else
     64 			dprintf(fd, "stop\n");
     65 	}
     66 
     67 	if (r) {
     68 		dprintf(fd, "OK\n");
     69 		return;
     70 	}
     71 
     72 	dprintf(fd, "ERR unknown command\n");
     73 }
     74 
     75 static void
     76 cmdrepeat(int fd, char *arg)
     77 {
     78 	if (arg[0]) {
     79 		dprintf(fd, "ERR unexpected argument\n");
     80 		return;
     81 	}
     82 
     83 	playlistmode(REPEAT);
     84 	dprintf(fd, "OK\n");
     85 }
     86 
     87 static void
     88 cmdrandom(int fd, char *arg)
     89 {
     90 	if (arg[0]) {
     91 		dprintf(fd, "ERR unexpected argument\n");
     92 		return;
     93 	}
     94 
     95 	playlistmode(RANDOM);
     96 	dprintf(fd, "OK\n");
     97 }
     98 
     99 static void
    100 cmdvolume(int fd, char *arg)
    101 {
    102 	int vol;
    103 	const char *errstr;
    104 
    105 	if (!arg[0]) {
    106 		dprintf(fd, "ERR expected volume\n");
    107 		return;
    108 	}
    109 
    110 	vol = strtonum(arg, 0, 100, &errstr);
    111 	if (errstr) {
    112 		dprintf(fd, "ERR volume should be between [0, 100]\n");
    113 		return;
    114 	}
    115 	if (setvol(vol) < 0) {
    116 		dprintf(fd, "ERR failed to change volume\n");
    117 		return;
    118 	}
    119 	dprintf(fd, "OK\n");
    120 }
    121 
    122 static void
    123 cmdnext(int fd, char *arg)
    124 {
    125 	Song *s;
    126 
    127 	if (arg[0]) {
    128 		dprintf(fd, "ERR unexpected argument\n");
    129 		return;
    130 	}
    131 
    132 	s = getcursong();
    133 	if (!s) {
    134 		dprintf(fd, "ERR playlist is empty\n");
    135 		return;
    136 	}
    137 
    138 	playsong(getnextsong());
    139 	dprintf(fd, "OK\n");
    140 }
    141 
    142 static void
    143 cmdpause(int fd, char *arg)
    144 {
    145 	Song *s;
    146 	int   pause;
    147 	const char *errstr;
    148 
    149 	if (!arg[0]) {
    150 		dprintf(fd, "ERR argument should be 0 or 1\n");
    151 		return;
    152 	}
    153 
    154 	pause = strtonum(arg, 0, 1, &errstr);
    155 	if (errstr) {
    156 		dprintf(fd, "ERR argument should be 0 or 1\n");
    157 		return;
    158 	}
    159 
    160 	s = getcursong();
    161 	if (!s) {
    162 		dprintf(fd, "ERR playlist is empty\n");
    163 		return;
    164 	}
    165 
    166 	switch (s->state) {
    167 	case PLAYING:
    168 		if (pause == 1)
    169 			s->state = PAUSED;
    170 		break;
    171 	case PAUSED:
    172 		if (pause == 0)
    173 			s->state = PLAYING;
    174 		break;
    175 	case NONE:
    176 		dprintf(fd, "ERR no song is active\n");
    177 		return;
    178 	}
    179 	dprintf(fd, "OK\n");
    180 }
    181 
    182 static void
    183 cmdplay(int fd, char *arg)
    184 {
    185 	Song *s, *cur;
    186 	int   id;
    187 	const char *errstr;
    188 
    189 	cur = getcursong();
    190 	if (!cur) {
    191 		dprintf(fd, "ERR playlist is empty\n");
    192 		return;
    193 	}
    194 
    195 	if (arg[0]) {
    196 		id = strtonum(arg, 0, INT_MAX, &errstr);
    197 		if (errstr) {
    198 			dprintf(fd, "ERR invalid song id\n");
    199 			return;
    200 		}
    201 
    202 		s = findsongid(id);
    203 		if (!s) {
    204 			dprintf(fd, "ERR cannot find song with given id\n");
    205 			return;
    206 		}
    207 	} else {
    208 		s = cur;
    209 	}
    210 
    211 	playsong(s);
    212 	dprintf(fd, "OK\n");
    213 }
    214 
    215 static void
    216 cmdprev(int fd, char *arg)
    217 {
    218 	Song *s;
    219 
    220 	if (arg[0]) {
    221 		dprintf(fd, "ERR unexpected argument\n");
    222 		return;
    223 	}
    224 
    225 	s = getcursong();
    226 	if (!s) {
    227 		dprintf(fd, "ERR playlist is empty\n");
    228 		return;
    229 	}
    230 
    231 	playsong(getprevsong());
    232 	dprintf(fd, "OK\n");
    233 }
    234 
    235 static void
    236 cmdstop(int fd, char *arg)
    237 {
    238 	Song *s;
    239 
    240 	if (arg[0]) {
    241 		dprintf(fd, "ERR unexpected argument\n");
    242 		return;
    243 	}
    244 
    245 	s = getcursong();
    246 	if (!s) {
    247 		dprintf(fd, "ERR playlist is empty\n");
    248 		return;
    249 	}
    250 
    251 	stopsong(s);
    252 	dprintf(fd, "OK\n");
    253 }
    254 
    255 static void
    256 cmdadd(int fd, char *arg)
    257 {
    258 	if (!arg[0]) {
    259 		dprintf(fd, "ERR expected file path\n");
    260 		return;
    261 	}
    262 
    263 	if (!addplaylist(arg)) {
    264 		dprintf(fd, "ERR cannot add song to playlist\n");
    265 		return;
    266 	}
    267 
    268 	dprintf(fd, "OK\n");
    269 }
    270 
    271 static void
    272 cmdclear(int fd, char *arg)
    273 {
    274 	if (arg[0]) {
    275 		dprintf(fd, "ERR unexpected argument\n");
    276 		return;
    277 	}
    278 
    279 	stopsong(getcursong());
    280 	clearplaylist();
    281 	dprintf(fd, "OK\n");
    282 }
    283 
    284 static void
    285 cmdremove(int fd, char *arg)
    286 {
    287 	Song *s;
    288 	const char *errstr;
    289 	int   id;
    290 
    291 	if (arg[0]) {
    292 		id = strtonum(arg, 0, INT_MAX, &errstr);
    293 		if (errstr) {
    294 			dprintf(fd, "ERR invalid song id\n");
    295 			return;
    296 		}
    297 		s = findsongid(id);
    298 		if (!s) {
    299 			dprintf(fd, "ERR cannot find song with given id\n");
    300 			return;
    301 		}
    302 	} else {
    303 		s = getcursong();
    304 		stopsong(s);
    305 	}
    306 
    307 	if (rmplaylist(s->id) < 0) {
    308 		dprintf(fd, "ERR failed to remove song\n");
    309 		return;
    310 	}
    311 	dprintf(fd, "OK\n");
    312 }
    313 
    314 static void
    315 cmdplaylist(int fd, char *arg)
    316 {
    317 	if (arg[0]) {
    318 		dprintf(fd, "ERR unexpected argument\n");
    319 		return;
    320 	}
    321 	dumpplaylist(fd);
    322 	dprintf(fd, "OK\n");
    323 }
    324 
    325 static void
    326 cmdclose(int fd, char *arg)
    327 {
    328 	if (arg[0]) {
    329 		dprintf(fd, "ERR unexpected argument\n");
    330 		return;
    331 	}
    332 
    333 	dprintf(fd, "OK\n");
    334 	FD_CLR(fd, &master);
    335 	close(fd);
    336 }
    337 
    338 static void
    339 cmdkill(int fd, char *arg)
    340 {
    341 	if (arg[0]) {
    342 		dprintf(fd, "ERR unexpected argument\n");
    343 		return;
    344 	}
    345 	dprintf(fd, "OK\n");
    346 	raise(SIGTERM);
    347 }
    348 
    349 static void
    350 cmdping(int fd, char *arg)
    351 {
    352 	if (arg[0]) {
    353 		dprintf(fd, "ERR unexpected argument\n");
    354 		return;
    355 	}
    356 	dprintf(fd, "pong\nOK\n");
    357 }
    358 
    359 static void
    360 cmdversion(int fd, char *arg)
    361 {
    362 	if (arg[0]) {
    363 		dprintf(fd, "ERR unexpected argument\n");
    364 		return;
    365 	}
    366 	dprintf(fd, "version 0.0\nOK\n");
    367 }
    368 
    369 static void
    370 cmdenable(int fd, char *arg)
    371 {
    372 	if (!arg[0]) {
    373 		dprintf(fd, "ERR expected output name\n");
    374 		return;
    375 	}
    376 	if (enableoutput(arg) < 0) {
    377 		dprintf(fd, "ERR failed to enable output %s\n", arg);
    378 		return;
    379 	}
    380 	dprintf(fd, "OK\n");
    381 }
    382 
    383 
    384 static void
    385 cmddisable(int fd, char *arg)
    386 {
    387 	if (!arg[0]) {
    388 		dprintf(fd, "ERR expected output name\n");
    389 		return;
    390 	}
    391 	if (disableoutput(arg) < 0) {
    392 		dprintf(fd, "ERR failed to disable output %s\n", arg);
    393 		return;
    394 	}
    395 	dprintf(fd, "OK\n");
    396 }
    397 
    398 static void
    399 cmdwait(int fd, char *arg)
    400 {
    401 	if (!arg[0]) {
    402 		dprintf(fd, "ERR expected event name\n");
    403 		return;
    404 	}
    405 
    406 	if (addsubscribername(fd, arg) < 0) {
    407 		dprintf(fd, "ERR unknown event type\n");
    408 		return;
    409 	}
    410 	dprintf(fd, "OK\n");
    411 }
    412 
    413 static Cmd cmds[] = {
    414 	{ "repeat",     cmdrepeat     },
    415 	{ "random",     cmdrandom     },
    416 	{ "status",     cmdstatus     },
    417 	{ "volume",     cmdvolume     },
    418 	{ "next",       cmdnext       },
    419 	{ "pause",      cmdpause      },
    420 	{ "play",       cmdplay       },
    421 	{ "prev",       cmdprev       },
    422 	{ "stop",       cmdstop       },
    423 	{ "add",        cmdadd        },
    424 	{ "clear",      cmdclear      },
    425 	{ "remove",     cmdremove     },
    426 	{ "playlist",   cmdplaylist   },
    427 	{ "close",      cmdclose      },
    428 	{ "kill",       cmdkill       },
    429 	{ "ping",       cmdping       },
    430 	{ "version",    cmdversion    },
    431 	{ "enable",     cmdenable     },
    432 	{ "disable",    cmddisable    },
    433 	{ "wait",       cmdwait       },
    434 };
    435 
    436 /* shamelessly taken from isakmpd ui.c */
    437 int
    438 docmd(int clifd)
    439 {
    440 	static  char *buf = 0;
    441 	static  char *p;
    442 	static  size_t sz;
    443 	static  size_t resid;
    444 	ssize_t n;
    445 	size_t  cmdlen, i;
    446 	char   *new_buf;
    447 	int     c;
    448 
    449 	/* If no buffer, set it up.  */
    450 	if (!buf) {
    451 		sz = BUFSIZ;
    452 		buf = malloc(sz);
    453 		if (!buf)
    454 			err(1, "malloc");
    455 		p = buf;
    456 		resid = sz;
    457 	}
    458 	/* If no place left in the buffer reallocate twice as large.  */
    459 	if (!resid) {
    460 		new_buf = realloc(buf, sz * 2);
    461 		if (!new_buf)
    462 			err(1, "realloc");
    463 		buf = new_buf;
    464 		p = buf + sz;
    465 		resid = sz;
    466 		sz *= 2;
    467 	}
    468 	n = read(clifd, p, resid);
    469 	if (n <= 0)
    470 		return -1;
    471 	resid -= n;
    472 	while (n--) {
    473 		/*
    474 		 * When we find a newline, cut off the line and feed it to the
    475 		 * command processor.  Then move the rest up-front.
    476 		 */
    477 		if (*p == '\n') {
    478 			*p = '\0';
    479 			for (i = 0; i < LEN(cmds); i++) {
    480 				cmdlen = strlen(cmds[i].name);
    481 				if (!strncmp(cmds[i].name, buf, cmdlen) &&
    482 				    (buf[cmdlen] == '\0' || isspace(buf[cmdlen]))) {
    483 					/* strip leading whitespace */
    484 					for (c = cmdlen; buf[c] && isspace(buf[c]); c++)
    485 						;
    486 					cmds[i].fn(clifd, &buf[c]);
    487 					break;
    488 				}
    489 			}
    490 			if (i == LEN(cmds))
    491 				dprintf(clifd, "ERR unknown command\n");
    492 			memmove(buf, p + 1, n);
    493 			p = buf;
    494 			resid = sz - n;
    495 			continue;
    496 		}
    497 		p++;
    498 	}
    499 	return 0;
    500 }