Recently Written · git

sad

sad (2f30.org simple audio daemon) with a Cygwin/OSS port on branch cygwin

git clone https://github.com/equwal/sad

Log | Files | Refs


cmd.c (8890 bytes)

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 }