sad

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

cmd.c (8890B)


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