jkramer / shell-fm

Lightweight console-based radio player for Last.FM radio streams.

This URL has Read+Write access

shell-fm / source / main.c
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 1 /*
c3e3fb0a » jkramer 2009-01-28 Updated copyright notes for... 2 Copyright (C) 2006-2009 by Jonas Kramer
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 3 Published under the terms of the GNU General Public License (GPL).
4 */
5
6 #define _GNU_SOURCE
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <sys/wait.h>
16 #include <time.h>
50aa9f76 » jkr 2008-04-14 * 2008-04-14, jkramer 17 #include <sys/types.h>
18 #include <sys/stat.h>
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 19
3272c802 » jkr 2008-04-06 * &quot; is now converted t... 20 #include <dirent.h>
21
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 22 #include "hash.h"
23 #include "service.h"
24 #include "interface.h"
25 #include "settings.h"
26 #include "autoban.h"
27 #include "sckif.h"
28 #include "playlist.h"
29 #include "submit.h"
4277526e » jkr 2008-04-05 Now using readline instead ... 30 #include "readline.h"
e79f83e1 » jkramer 2008-10-07 Prompt for radio URI on sta... 31 #include "radio.h"
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 32
33 #include "globals.h"
34
35 #ifndef PATH_MAX
36 #define PATH_MAX 4096
37 #endif
38
6b4a0ec0 » chneukirchen 2008-08-01 Patches for NetBSD 39 #ifdef __NetBSD__
40 # ifndef WCONTINUED
41 # define WCONTINUED 0 /* not available on NetBSD */
42 # endif
43 # ifndef WIFCONTINUED
44 # define WIFCONTINUED(x) ((x) == 0x13) /* SIGCONT */
45 # endif
46 #endif
47
1b427c1b » jkramer 2009-02-28 Redefine some constants if ... 48 #if !defined(WCONTINUED) || !defined(WIFCONTINUED)
49 # undef WCONTINUED
50 # define WCONTINUED 0
51 # undef WIFCONTINUED
52 # define WIFCONTINUED(wstat) (0)
53 #endif
54
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 55 unsigned flags = RTP;
56 time_t changeTime = 0, pausetime = 0;
0c9f393d » jkr 2008-04-06 Added option "delay-change"... 57 char * nextstation = NULL;
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 58
28290572 » jkramer 2009-01-13 Added delayed quit ('q', wo... 59 int batch = 0, error = 0, delayquit = 0;
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 60
61 static void cleanup(void);
62 static void forcequit(int);
63 static void help(const char *, int);
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 64 static void playsig(int);
f151e238 » jkramer 2008-07-06 Fixed pause timer for "paus... 65 static void stopsig(int);
67dabd84 » jkramer 2008-09-25 Removing now-playing file a... 66 static void unlinknp(void);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 67
7a1b18df » jkramer 2008-05-20 Fixed cleanup of UNIX socket. 68 pid_t ppid = 0;
69
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 70 int main(int argc, char ** argv) {
71 int option, nerror = 0, background = 0, haveSocket = 0;
72 time_t pauselength = 0;
73 char * proxy;
74 opterr = 0;
33dfd4b8 » jkramer 2008-05-24 Automatically creating ~/.s... 75
76 /* Create directories. */
77 makercd();
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 78
79 /* Load settings from ~/.shell-fm/shell-fm.rc. */
80 settings(rcpath("shell-fm.rc"), !0);
81
0d2777f7 » jkr 2008-04-12 * 2008-04-12, jkramer 82 /* Enable discovery by default if it is set in configuration. */
83 if(haskey(& rc, "discovery"))
84 enable(DISCOVERY);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 85
4dd0d1c5 » jkramer 2009-05-05 "daemon" in the configurati... 86 /* If "daemon" is set in the configuration, enable daemon mode by default. */
87 if(haskey(& rc, "daemon"))
88 background = !0;
89
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 90 /* Get proxy environment variable. */
91 if((proxy = getenv("http_proxy")) != NULL)
92 set(& rc, "proxy", proxy);
93
94
95 /* Parse through command line options. */
96 while(-1 != (option = getopt(argc, argv, ":dbhi:p:D:y:")))
97 switch(option) {
98 case 'd': /* Daemonize. */
4dd0d1c5 » jkramer 2009-05-05 "daemon" in the configurati... 99 background = !background;
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 100 break;
101
102 case 'i': /* IP to bind network interface to. */
103 set(& rc, "bind", optarg);
104 break;
105
106 case 'p': /* Port to listen on. */
107 if(atoi(optarg))
108 set(& rc, "port", optarg);
109 else {
110 fputs("Invalid port.\n", stderr);
111 ++nerror;
112 }
113 break;
b8b5b890 » jkr 2008-02-02 - added two missing option... 114
115 case 'b': /* Batch mode */
116 batch = !0;
117 break;
118
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 119 case 'D': /* Path to audio device file. */
120 set(& rc, "device", optarg);
121 break;
122
123 case 'y': /* Proxy address. */
124 set(& rc, "proxy", optarg);
125 break;
126
127 case 'h': /* Print help text and exit. */
128 help(argv[0], 0);
129 break;
130
131 case ':':
132 fprintf(stderr, "Missing argument for option -%c.\n\n", optopt);
133 ++nerror;
134 break;
135
136 case '?':
137 default:
138 fprintf(stderr, "Unknown option -%c.\n", optopt);
139 ++nerror;
140 break;
141 }
142
143 /* The next argument, if present, is the lastfm:// URL we want to play. */
144 if(optind > 0 && optind < argc && argv[optind]) {
145 const char * station = argv[optind];
146
3eca42a8 » jkramer 2009-05-05 Don't require lastfm:// sch... 147 set(& rc, "default-radio", station);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 148 }
149
150
151 if(nerror)
152 help(argv[0], EXIT_FAILURE);
153
64a23344 » jkr 2008-04-10 * 2008-04-10, jkramer 154 #ifndef LIBAO
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 155 if(!haskey(& rc, "device"))
156 set(& rc, "device", "/dev/audio");
157 #endif
158
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 159 if(!background) {
b25261cc » jkramer 2009-02-04 Updated year in copyright n... 160 puts("Shell.FM v" PACKAGE_VERSION ", (C) 2006-2009 by Jonas Kramer");
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 161 puts("Published under the terms of the GNU General Public License (GPL).");
162
1b427c1b » jkramer 2009-02-28 Redefine some constants if ... 163 #ifndef TUXBOX
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 164 puts("\nPress ? for help.\n");
1b427c1b » jkramer 2009-02-28 Redefine some constants if ... 165 #else
166 puts("Compiled for the use with Shell.FM Wrapper.\n");
167 #endif
168 fflush(stdout);
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 169 }
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 170
171
172 /* Open a port so Shell.FM can be controlled over network. */
173 if(haskey(& rc, "bind")) {
174 int port = 54311;
175
176 if(haskey(& rc, "port"))
177 port = atoi(value(& rc, "port"));
178
19b3a40e » jkramer 2008-05-20 Added support for UNIX sock... 179 if(tcpsock(value(& rc, "bind"), (unsigned short) port))
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 180 haveSocket = !0;
181 }
182
183
19b3a40e » jkramer 2008-05-20 Added support for UNIX sock... 184 /* Open a UNIX socket for local "remote" control. */
185 if(haskey(& rc, "unix") && unixsock(value(& rc, "unix")))
186 haveSocket = !0;
187
188
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 189 /* We can't daemonize if there's no possibility left to control Shell.FM. */
190 if(background && !haveSocket) {
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 191 fputs("Can't daemonize without control socket.\n", stderr);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 192 exit(EXIT_FAILURE);
193 }
194
195
196 /* Ask for username/password if they weren't specified in the .rc file. */
197 if(!haskey(& rc, "password")) {
198 char * password;
199
200 if(!haskey(& rc, "username")) {
201 char username[256] = { 0 };
4277526e » jkr 2008-04-05 Now using readline instead ... 202
203 struct prompt prompt = {
204 .prompt = "Login: ",
205 .line = getenv("USER"), .history = NULL, .callback = NULL,
206 };
207
208 strncpy(username, readline(& prompt), 255);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 209
210 set(& rc, "username", username);
211 }
212
213 if(!(password = getpass("Password: ")))
214 exit(EXIT_FAILURE);
215
216 set(& rc, "password", password);
217 }
218
219
220 memset(& data, 0, sizeof(struct hash));
221 memset(& track, 0, sizeof(struct hash));
222 memset(& playlist, 0, sizeof(struct playlist));
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 223
224 /* Fork to background. */
225 if(background) {
f7a365e9 » be1 2008-09-21 Fixed daemonizing issue: tr... 226 int null;
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 227 pid_t pid = fork();
f7a365e9 » be1 2008-09-21 Fixed daemonizing issue: tr... 228
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 229 if(pid == -1) {
230 fputs("Failed to daemonize.\n", stderr);
231 exit(EXIT_FAILURE);
232 } else if(pid) {
233 exit(EXIT_SUCCESS);
234 }
f7a365e9 » be1 2008-09-21 Fixed daemonizing issue: tr... 235
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 236 enable(QUIET);
f7a365e9 » be1 2008-09-21 Fixed daemonizing issue: tr... 237
238 /* Detach from TTY */
239 setsid();
240 pid = fork();
241
242 if(pid > 0)
243 exit(EXIT_SUCCESS);
244
245 /* Close stdin out and err */
246 close(0);
247 close(1);
248 close(2);
249
250 /* Redirect stdin and out to /dev/null */
251 null = open("/dev/null", O_RDWR);
252 dup(null);
253 dup(null);
0a0080cc » jkramer 2008-05-20 Removed the HTTP indicator ... 254 }
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 255
7a1b18df » jkramer 2008-05-20 Fixed cleanup of UNIX socket. 256 ppid = getpid();
257
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 258 atexit(cleanup);
259 loadqueue(!0);
260
261 /* Set up signal handlers for communication with the playback process. */
262 signal(SIGINT, forcequit);
263
41a0adb8 » jkramer 2008-09-20 'stop' in daemon mode now s... 264 /* SIGUSR2 from playfork means it detected an error. */
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 265 signal(SIGUSR2, playsig);
266
f151e238 » jkramer 2008-07-06 Fixed pause timer for "paus... 267 /* Catch SIGTSTP to set pausetime when user suspends us with ^Z. */
268 signal(SIGTSTP, stopsig);
269
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 270
271 /* Authenticate to the Last.FM server. */
272 if(!authenticate(value(& rc, "username"), value(& rc, "password")))
273 exit(EXIT_FAILURE);
274
275 /* Store session key for use by external tools. */
276 if(haskey(& data, "session")) {
277 FILE * fd = fopen(rcpath("session"), "w");
278 if(fd) {
279 fprintf(fd, "%s\n", value(& data, "session"));
280 fclose(fd);
281 }
282 }
283
284
285 /* Play default radio, if specified. */
286 if(haskey(& rc, "default-radio"))
287 station(value(& rc, "default-radio"));
67a50eac » jkramer 2009-03-12 Don't prompt for stream URL... 288 else if(!background)
e79f83e1 » jkramer 2008-10-07 Prompt for radio URI on sta... 289 radioprompt("radio url> ");
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 290
291 /* The main loop. */
292 while(!0) {
293 pid_t child;
294 int status, playnext = 0;
295
296 /* Check if anything died (submissions fork or playback fork). */
297 while((child = waitpid(-1, & status, WNOHANG | WUNTRACED | WCONTINUED)) > 0) {
298 if(child == subfork)
299 subdead(WEXITSTATUS(status));
300 else if(child == playfork) {
f151e238 » jkramer 2008-07-06 Fixed pause timer for "paus... 301 if(WIFSTOPPED(status)) {
302 /* time(& pausetime); */
303 }
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 304 else {
f151e238 » jkramer 2008-07-06 Fixed pause timer for "paus... 305 if(WIFCONTINUED(status)) {
306 signal(SIGTSTP, stopsig);
307 if(pausetime != 0) {
308 pauselength += time(NULL) - pausetime;
309 }
310 }
311 else {
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 312 playnext = !0;
67dabd84 » jkramer 2008-09-25 Removing now-playing file a... 313 unlinknp();
28290572 » jkramer 2009-01-13 Added delayed quit ('q', wo... 314
315 if(delayquit) {
316 unlink(rcpath("session"));
317 exit(EXIT_SUCCESS);
318 }
f151e238 » jkramer 2008-07-06 Fixed pause timer for "paus... 319 }
41a0adb8 » jkramer 2008-09-20 'stop' in daemon mode now s... 320 pausetime = 0;
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 321 }
322 }
323 }
324
325 /*
326 Check if the playback process died. If so, submit the data
327 of the last played track. Then check if there are tracks left
328 in the playlist; if not, try to refresh the list and stop the
329 stream if there are no new tracks to fetch.
330 Also handle user stopping the stream here. We need to check for
331 playnext != 0 before handling enabled(STOPPED) anyway, otherwise
332 playfork would still be running.
333 */
334 if(playnext) {
08750ee5 » jkr 2008-04-02 * 2008-04-02, jkramer 335 playfork = 0;
336
337 if(enabled(RTP)) {
338 unsigned duration, played, minimum;
339
859f319b » jkramer 2009-02-06 Using seconds for duration ... 340 duration = atoi(value(& track, "duration"));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 341 played = time(NULL) - changeTime - pauselength;
342
08750ee5 » jkr 2008-04-02 * 2008-04-02, jkramer 343 /* Allow user to specify minimum playback length (min. 50%). */
344 if(haskey(& rc, "minimum")) {
345 unsigned percent = atoi(value(& rc, "minimum"));
346 if(percent < 50)
347 percent = 50;
348 minimum = duration * percent / 100;
349 }
350 else {
351 minimum = duration / 2;
352 }
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 353
08750ee5 » jkr 2008-04-02 * 2008-04-02, jkramer 354 if(duration >= 30 && (played >= 240 || played > minimum))
355 enqueue(& track);
356 }
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 357
358 submit(value(& rc, "username"), value(& rc, "password"));
359
360 /* Check if the user stopped the stream. */
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 361 if(enabled(STOPPED) || error) {
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 362 freelist(& playlist);
363 empty(& track);
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 364
365 if(error) {
366 fputs("Playback stopped with an error.\n", stderr);
367 error = 0;
368 }
369
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 370 disable(STOPPED);
41a0adb8 » jkramer 2008-09-20 'stop' in daemon mode now s... 371 disable(CHANGED);
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 372
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 373 continue;
374 }
375
376 shift(& playlist);
377 }
378
379
380 if(playnext || enabled(CHANGED)) {
0c9f393d » jkr 2008-04-06 Added option "delay-change"... 381 if(nextstation != NULL) {
382 playnext = 0;
383 disable(CHANGED);
384
fa0d6c73 » jkramer 2009-03-11 Fixed a seg. fault when a d... 385 if(!station(nextstation))
386 enable(STOPPED);
0c9f393d » jkr 2008-04-06 Added option "delay-change"... 387
388 free(nextstation);
389 nextstation = NULL;
390 }
391
fa0d6c73 » jkramer 2009-03-11 Fixed a seg. fault when a d... 392 if(!enabled(STOPPED) && !playlist.left) {
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 393 expand(& playlist);
394 if(!playlist.left) {
395 puts("No tracks left.");
396 playnext = 0;
397 disable(CHANGED);
398 continue;
399 }
400 }
401
402 if(!playfork) {
980ed52d » jkramer 2009-01-13 Added "gap" option for slee... 403 /*
404 If there was a track played before, and there is a gap
405 configured, wait that many seconds before playing the next
406 track.
407 */
6192d6d4 » jkramer 2009-02-06 Fixed interrupt detection a... 408 if(playnext && !enabled(INTERRUPTED) && haskey(& rc, "gap")) {
980ed52d » jkramer 2009-01-13 Added "gap" option for slee... 409 int gap = atoi(value(& rc, "gap"));
410
411 if(gap > 0)
412 sleep(gap);
413 }
414
c4e6e528 » jkramer 2009-02-05 No gap when track was skipp... 415 disable(INTERRUPTED);
416
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 417 if(play(& playlist)) {
418 time(& changeTime);
08750ee5 » jkr 2008-04-02 * 2008-04-02, jkramer 419 pauselength = 0;
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 420
421 set(& track, "stationURL", currentStation);
422
423 /* Print what's currently played. (Ondrej Novy) */
424 if(!background) {
425 if(enabled(CHANGED) && playlist.left > 0) {
42fa7071 » csabahenk 2008-12-25 fix dumping files when the ... 426 puts(meta("Receiving %s.", M_COLORED, & track));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 427 disable(CHANGED);
428 }
429
430 if(haskey(& rc, "title-format"))
42fa7071 » csabahenk 2008-12-25 fix dumping files when the ... 431 printf("%s\n", meta(value(& rc, "title-format"), M_COLORED, & track));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 432 else
42fa7071 » csabahenk 2008-12-25 fix dumping files when the ... 433 printf("%s\n", meta("Now playing \"%t\" by %a.", M_COLORED, & track));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 434 }
435
436
437 /* Write track data into a file. */
438 if(haskey(& rc, "np-file") && haskey(& rc, "np-file-format")) {
439 signed np;
440 const char
441 * file = value(& rc, "np-file"),
442 * fmt = value(& rc, "np-file-format");
443
444 unlink(file);
445 if(-1 != (np = open(file, O_WRONLY | O_CREAT, 0644))) {
0d2777f7 » jkr 2008-04-12 * 2008-04-12, jkramer 446 const char * output = meta(fmt, 0, & track);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 447 if(output)
448 write(np, output, strlen(output));
449 close(np);
450 }
451 }
452
453
852cb631 » jkramer 2008-09-12 Added "screen-format" optio... 454 if(haskey(& rc, "screen-format")) {
455 const char * term = getenv("TERM");
456 if(term != NULL && !strncmp(term, "screen", 6)) {
457 const char * output =
458 meta(value(& rc, "screen-format"), 0, & track);
459 printf("\x1Bk%s\x1B\\", output);
460 }
461 }
462
463
ee51ddb4 » jkramer 2008-09-12 When "term-format" is set t... 464 if(haskey(& rc, "term-format")) {
465 const char * output =
466 meta(value(& rc, "term-format"), 0, & track);
467 printf("\x1B]2;%s\a", output);
468 }
469
470
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 471 /* Run a command with our track data. */
472 if(haskey(& rc, "np-cmd"))
0865b83d » pioto 2009-02-13 Shell-escape metadata befor... 473 run(meta(value(& rc, "np-cmd"), M_SHELLESC, & track));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 474 } else
475 changeTime = 0;
476 }
477
478 if(banned(value(& track, "creator"))) {
42fa7071 » csabahenk 2008-12-25 fix dumping files when the ... 479 puts(meta("%a is banned.", M_COLORED, & track));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 480 rate("B");
481 fflush(stdout);
482 }
483 }
484
485 playnext = 0;
486
487 if(playfork && changeTime && haskey(& track, "duration") && !pausetime) {
488 unsigned duration;
489 signed remain;
490 char remstr[32];
491
859f319b » jkramer 2009-02-06 Using seconds for duration ... 492 duration = atoi(value(& track, "duration"));
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 493
494 remain = (changeTime + duration) - time(NULL) + pauselength;
495
496 snprintf(remstr, sizeof(remstr), "%d", remain);
497 set(& track, "remain", remstr);
498
499 if(!background) {
72bff1f2 » jkramer 2008-04-25 Applied another patch from ... 500 printf(
501 "%c%02d:%02d%c",
502 remain < 0 ? '-' : ' ',
503 (remain >= 0) ? (remain / 60) : (-remain / 60),
504 (remain >= 0) ? (remain % 60) : (-remain % 60),
505 batch ? '\n' : '\r'
506 );
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 507 fflush(stdout);
508 }
509 }
510
511 interface(!background);
512 if(haveSocket)
19b3a40e » jkramer 2008-05-20 Added support for UNIX sock... 513 sckif(background ? 2 : 0, -1);
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 514 }
515
516 return 0;
517 }
518
519
520 static void help(const char * argv0, int errorCode) {
521 fprintf(stderr,
b25261cc » jkramer 2009-02-04 Updated year in copyright n... 522 "Shell.FM v" PACKAGE_VERSION ", (C) 2006-2009 by Jonas Kramer\n"
8bd32e16 » jkr 2008-02-02 - fixed Makefile 523 "Published under the terms of the GNU General Public License (GPL).\n"
524 "\n"
525 "%s [options] [lastfm://url]\n"
526 "\n"
527 " -d daemon mode.\n"
528 " -i address to listen on.\n"
529 " -p port to listen on.\n"
530 " -b batch mode.\n"
531 " -D device to play on.\n"
532 " -y proxy url to connect through.\n"
533 " -h this help.\n",
534 argv0
535 );
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 536
537 exit(errorCode);
538 }
539
540
541 static void cleanup(void) {
542 canon(!0);
543 rmsckif();
544
7a1b18df » jkramer 2008-05-20 Fixed cleanup of UNIX socket. 545 if(haskey(& rc, "unix") && getpid() == ppid)
19b3a40e » jkramer 2008-05-20 Added support for UNIX sock... 546 unlink(value(& rc, "unix"));
547
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 548 empty(& data);
549 empty(& rc);
550 empty(& track);
551
552 freelist(& playlist);
553
554 if(currentStation) {
555 free(currentStation);
556 currentStation = NULL;
557 }
558
559 if(subfork)
560 waitpid(subfork, NULL, 0);
561
562 dumpqueue(!0);
563
3272c802 » jkr 2008-04-06 * &quot; is now converted t... 564 /* Clean cache. */
565 if(!access(rcpath("cache"), R_OK | W_OK | X_OK)) {
566 const char * cache = rcpath("cache");
567 DIR * directory = opendir(cache);
568
569 if(directory != NULL) {
7a1b18df » jkramer 2008-05-20 Fixed cleanup of UNIX socket. 570 time_t expiry = 24 * 60 * 60; /* Expiration after 24h. */
3272c802 » jkr 2008-04-06 * &quot; is now converted t... 571 struct dirent * entry;
572 struct stat status;
573 char path[PATH_MAX];
574
575 if(haskey(& rc, "expiry"))
576 expiry = atoi(value(& rc, "expiry"));
577
578 while((entry = readdir(directory)) != NULL) {
579 snprintf(path, sizeof(path), "%s/%s", cache, entry->d_name);
580
581 if(!stat(path, & status)) {
582 if(status.st_mtime < (time(NULL) - expiry)) {
583 unlink(path);
584 }
585 }
586 }
587
588 closedir(directory);
589 }
590 }
591
cfd9a613 » jkr 2008-02-02 Removed autoconf branch. 592 if(playfork)
593 kill(playfork, SIGUSR1);
594 }
595
596
597 static void forcequit(int sig) {
598 if(sig == SIGINT) {
599 fputs("Try to press Q next time you want to quit.\n", stderr);
600 exit(-1);
601 }
602 }
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 603
604
605 static void playsig(int sig) {
c4e6e528 » jkramer 2009-02-05 No gap when track was skipp... 606 if(sig == SIGUSR2) {
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 607 error = !0;
c4e6e528 » jkramer 2009-02-05 No gap when track was skipp... 608 enable(INTERRUPTED);
609 }
5533132e » jkr 2008-04-10 * 2008-04-10, jkramer 610 }
f151e238 » jkramer 2008-07-06 Fixed pause timer for "paus... 611
612
613 static void stopsig(int sig) {
614 if(sig == SIGTSTP) {
615 time(& pausetime);
616
617 signal(SIGTSTP, SIG_DFL);
618 raise(SIGTSTP);
619 }
620 }
67dabd84 » jkramer 2008-09-25 Removing now-playing file a... 621
622 static void unlinknp(void) {
623 /* Remove now-playing file. */
624 if(haskey(& rc, "np-file")) {
625 const char * np = value(& rc, "np-file");
626 if(np != NULL)
627 unlink(np);
628 }
629 }