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