1 /*
2 * Copyright (c) 2003 MATPOCKuH. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <errno.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <libgen.h>
31 #include <sysexits.h>
32 #include <curses.h>
33 #include <signal.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "settings.h"
40 #include "acd.h"
41 #include "logger.h"
42 #include "version.h"
43
44 const char *progname = "acdplay";
45
46 int fd = -1;
47
48 static volatile sig_atomic_t nobreak = 1;
49
50 void
usage(char * argv[])51 usage(char *argv[])
52 {
53 logger("%s\n\
54 Usage: %s [-h] [-d device] [-s socket]\n\
55 -h\t\t- this help\n\
56 -d device\t- device\n\
57 -s socket\t- path to a control socket\n",
58 ver_getversionstring(), basename(argv[0]));
59
60 exit(EX_USAGE);
61 }
62
63 int
opendev()64 opendev()
65 {
66 int fd;
67
68 if((fd = acd_connect()) == -1) {
69 logger("Could not connect to daemon: %s\n", strerror(errno));
70 exit(EX_UNAVAILABLE);
71 }
72
73 return fd;
74 }
75
76 void
add2data(char ** data,char * add)77 add2data(char **data, char *add)
78 {
79 char *s;
80
81 if(data) {
82 asprintf(&s, "%s\n%s", *data, add);
83 free(*data);
84 } else
85 s = strdup(add);
86
87 *data = s;
88 }
89
90 int
execmd(int fd,char * cmd,char ** data)91 execmd(int fd, char *cmd, char **data)
92 {
93 char buf[BUFSIZE], *s, *s_end;
94 int i;
95
96 if(!cmd[0])
97 return 0;
98
99 *data = NULL;
100
101 asprintf(&s, "%s\n", cmd);
102 if(write(fd, s, strlen(s)) < 0) {
103 free(s);
104 return -1;
105 }
106
107 free(s);
108
109 while((i = read(fd, buf, sizeof(buf) - sizeof(char))) > 0) {
110 buf[i] = 0;
111 s = buf;
112
113 while((s_end = strchr(s, '\n'))) {
114 s_end[0] = 0;
115
116 if(!strcmp(s, "OK"))
117 return 0;
118
119 if(strstr(s, "ERROR: ") == s) {
120 *data = strdup(s);
121 return -1;
122 }
123
124 add2data(data, s);
125
126 s = s_end + 1;
127 }
128 }
129
130 if(i < 0)
131 return -1;
132
133 return 0;
134 }
135
136 void
mainwindow()137 mainwindow()
138 {
139 clear();
140
141 mvprintw(0, 0, " _____________________________________\n\
142 | |\n\
143 | %s - Quit |\n\
144 | __________ |\n\
145 | | | Play Stop |\n\
146 | | | SPC pause Eject +/- |\n\
147 | |__________| Rew Forward |\n\
148 |_____________________________________|\n", progname);
149
150 doupdate();
151 }
152
153 int
printstatus()154 printstatus()
155 {
156 int track, min, sec;
157 char *data = NULL, *sb, *se, *status;
158
159 if(execmd(fd, "STATUS", &data) == -1)
160 return -1;
161
162 if((status = strchr(data, '<')) == NULL) {
163 track = min = sec = 0;
164 status = "no cd";
165 } else {
166 if((++status)[0] == 0)
167 return -1;
168
169 if((se = strchr(status, '>')) == NULL)
170 return -1;
171
172 se++[0] = 0;
173
174 if((sb = strstr(se, " = ")) == NULL)
175 return -1;
176
177 if((se = strchr(sb += 3, ',')) == NULL)
178 return -1;
179
180 se++[0] = 0;
181 track = atoi(sb);
182
183 if((sb = strstr(se, " = ")) == NULL)
184 return -1;
185
186 if((se = strchr(sb += 3, ':')) == NULL)
187 return -1;
188
189 se++[0] = 0;
190 min = atoi(sb);
191
192 if((sb = strchr(se, '.')) == NULL)
193 return -1;
194
195 sb[0] = 0;
196 sec = atoi(se);
197 }
198
199 mvprintw(2, 13, "%-9s", status);
200 mvprintw(5, 5, "%02i %02i:%02i", track, min, sec);
201
202 free(data);
203
204 move(0, 0);
205 doupdate();
206
207 return 0;
208 }
209
210 void
sigterm_handler()211 sigterm_handler()
212 {
213 nobreak = 0;
214 }
215
216 int
main(int argc,char * argv[])217 main(int argc, char *argv[])
218 {
219 int ch;
220 char *s, *data;
221
222 while((ch = getopt(argc, argv, "hd:s:")) != -1) {
223 switch(ch) {
224 case 'd':
225 if(fd == -1)
226 fd = opendev();
227
228 asprintf(&s, "device %s", optarg);
229 if(execmd(fd, s, &data) == -1) {
230 logger("%s\n", data);
231 free(data);
232 free(s);
233
234 return EX_UNAVAILABLE;
235 }
236
237 free(s);
238 break;
239
240 case 's':
241 acd_setsocketpath(optarg);
242 break;
243
244 case 'h':
245 default:
246 usage(argv);
247 }
248 }
249
250 if(fd == -1)
251 fd = opendev();
252
253 if(argc != optind) {
254 close(fd);
255
256 usage(argv);
257 }
258
259 if(!initscr()) {
260 logger("initscr() failed: %s\n", strerror(errno));
261
262 close(fd);
263
264 return EX_UNAVAILABLE;
265 }
266
267 cbreak();
268 noecho();
269 timeout(1000);
270
271 signal(SIGTERM, &sigterm_handler);
272 signal(SIGINT, &sigterm_handler);
273
274 mainwindow();
275
276 while(nobreak) {
277 char *cmd = NULL;
278
279 if(printstatus() == -1)
280 break;;
281
282 switch(ch = getch()) {
283 case 'q':
284 case 'Q':
285 nobreak = 0;
286 break;
287
288 case 'p':
289 case 'P':
290 cmd = "PLAY";
291 break;
292
293 case ' ':
294 cmd = "PAUSE";
295 break;
296
297 case 'r':
298 case 'R':
299 cmd = "PREVIOUS";
300 break;
301
302 case 's':
303 case 'S':
304 cmd = "STOP";
305 break;
306
307 case 'e':
308 case 'E':
309 cmd = "EJECT";
310 break;
311
312 case 'f':
313 case 'F':
314 case 'n':
315 case 'N':
316 cmd = "NEXT";
317 break;
318
319 case '-':
320 cmd = "VOLUME -10";
321 break;
322
323 case '+':
324 cmd = "VOLUME +10";
325 break;
326 }
327
328 if(cmd != NULL)
329 if(execmd(fd, cmd, &data) == -1) {
330 free(data);
331 }
332 }
333
334 clear();
335 refresh();
336
337 endwin();
338 close(fd);
339
340 return EX_OK;
341 }
342