1 /*
2  * MOC - music on console
3  * Copyright (C) 2004-2005 Damian Pietras <daper@daper.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
22 #include <sys/time.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <getopt.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <locale.h>
31 #include <assert.h>
32 
33 #ifdef HAVE_UNAME_SYSCALL
34 #include <sys/utsname.h>
35 #endif
36 
37 #include "common.h"
38 #include "server.h"
39 #include "interface.h"
40 #include "options.h"
41 #include "protocol.h"
42 #include "log.h"
43 #include "compat.h"
44 #include "decoder.h"
45 #include "lists.h"
46 #include "files.h"
47 #include "rcc.h"
48 
49 struct parameters
50 {
51 	char *config_file;
52 	int debug;
53 	int only_server;
54 	int foreground;
55 	int append;
56 	int enqueue;
57 	int clear;
58 	int play;
59 	int dont_run_iface;
60 	int stop;
61 	int exit;
62 	int pause;
63 	int unpause;
64 	int next;
65 	int previous;
66 	int get_file_info;
67 	int toggle_pause;
68 	int playit;
69 	int seek_by;
70 	char jump_type;
71 	int jump_to;
72 	char *formatted_into_param;
73 	int get_formatted_info;
74 	char *adj_volume;
75 	char *toggle;
76 	char *on;
77 	char *off;
78 };
79 
80 
81 /* Connect to the server, return fd of the socket or -1 on error. */
server_connect()82 static int server_connect ()
83 {
84 	struct sockaddr_un sock_name;
85 	int sock;
86 
87 	/* Create a socket */
88 	if ((sock = socket (PF_LOCAL, SOCK_STREAM, 0)) == -1)
89 		 return -1;
90 
91 	sock_name.sun_family = AF_LOCAL;
92 	strcpy (sock_name.sun_path, socket_name());
93 
94 	if (connect(sock, (struct sockaddr *)&sock_name,
95 				SUN_LEN(&sock_name)) == -1) {
96 		close (sock);
97 		return -1;
98 	}
99 
100 	return sock;
101 }
102 
103 /* Ping the server.
104  * Return 1 if the server responds with EV_PONG, otherwise 1. */
ping_server(int sock)105 static int ping_server (int sock)
106 {
107 	int event;
108 
109 	send_int(sock, CMD_PING); /* ignore errors - the server could have
110 				     already closed the connection and sent
111 				     EV_BUSY */
112 	if (!get_int(sock, &event))
113 		fatal ("Error when receiving pong response!");
114 	return event == EV_PONG ? 1 : 0;
115 }
116 
117 /* Check if a directory ./.moc exists and create if needed. */
check_moc_dir()118 static void check_moc_dir ()
119 {
120 	char *dir_name = create_file_name ("");
121 	struct stat file_stat;
122 
123 	/* strip trailing slash */
124 	dir_name[strlen(dir_name)-1] = 0;
125 
126 	if (stat (dir_name, &file_stat) == -1) {
127 		if (errno == ENOENT) {
128 			if (mkdir (dir_name, 0700) == -1)
129 				fatal ("Can't create directory %s: %s",
130 						dir_name, strerror (errno));
131 		}
132 		else
133 			fatal ("Error trying to check for "CONFIG_DIR" directory: %s",
134 			        strerror (errno));
135 	}
136 	else {
137 		if (!S_ISDIR(file_stat.st_mode) || access (dir_name, W_OK))
138 			fatal ("%s is not a writable directory!", dir_name);
139 	}
140 }
141 
sig_chld(int sig ATTR_UNUSED)142 static void sig_chld (int sig ATTR_UNUSED)
143 {
144 	int saved_errno;
145 	pid_t rc;
146 
147 	log_signal (sig);
148 
149 	saved_errno = errno;
150 	do {
151 		rc = waitpid (-1, NULL, WNOHANG);
152 	} while (rc > 0);
153 	errno = saved_errno;
154 }
155 
156 /* Run client and the server if needed. */
start_moc(const struct parameters * params,lists_t_strs * args)157 static void start_moc (const struct parameters *params, lists_t_strs *args)
158 {
159 	int list_sock;
160 	int server_sock = -1;
161 
162 	if (!params->foreground && (server_sock = server_connect()) == -1) {
163 		int notify_pipe[2];
164 		int i = 0;
165 		ssize_t rc;
166 
167 		printf ("Running the server...\n");
168 
169 		/* To notify the client that the server socket is ready */
170 		if (pipe(notify_pipe))
171 			fatal ("pipe() failed: %s", strerror(errno));
172 
173 		switch (fork()) {
174 			case 0: /* child - start server */
175 				set_me_server ();
176 				list_sock = server_init (params->debug, params->foreground);
177 				rc = write (notify_pipe[1], &i, sizeof(i));
178 				if (rc < 0)
179 					fatal ("write() to notify pipe failed: %s",
180 					        strerror(errno));
181 				close (notify_pipe[0]);
182 				close (notify_pipe[1]);
183 				signal (SIGCHLD, sig_chld);
184 				server_loop (list_sock);
185 				options_free ();
186 				decoder_cleanup ();
187 				io_cleanup ();
188 				files_cleanup ();
189 				rcc_cleanup ();
190 				compat_cleanup ();
191 				exit (EXIT_SUCCESS);
192 			case -1:
193 				fatal ("fork() failed: %s", strerror(errno));
194 			default:
195 				close (notify_pipe[1]);
196 				if (read(notify_pipe[0], &i, sizeof(i)) != sizeof(i))
197 					fatal ("Server exited!");
198 				close (notify_pipe[0]);
199 				if ((server_sock = server_connect()) == -1) {
200 					perror ("server_connect()");
201 					fatal ("Can't connect to the server!");
202 				}
203 		}
204 	}
205 	else if (!params->foreground && params->only_server)
206 		fatal ("Server is already running!");
207 	else if (params->foreground && params->only_server) {
208 		set_me_server ();
209 		list_sock = server_init (params->debug, params->foreground);
210 		signal (SIGCHLD, sig_chld);
211 		server_loop (list_sock);
212 	}
213 
214 	if (!params->only_server) {
215 		signal (SIGPIPE, SIG_IGN);
216 		if (ping_server(server_sock)) {
217 			if (!params->dont_run_iface) {
218 				init_interface (server_sock, params->debug, args);
219 				interface_loop ();
220 				interface_end ();
221 				server_sock = -1;
222 			}
223 		}
224 		else
225 			fatal ("Can't connect to the server!");
226 	}
227 
228 	if (!params->foreground && params->only_server)
229 		send_int (server_sock, CMD_DISCONNECT);
230 
231 	if (server_sock != -1) {
232 		close (server_sock);
233 		server_sock = -1;
234 	}
235 }
236 
show_version()237 static void show_version ()
238 {
239 #ifdef HAVE_UNAME_SYSCALL
240 	int rc;
241 	struct utsname uts;
242 #endif
243 
244 	putchar ('\n');
245 	printf ("          This is : %s\n", PACKAGE_NAME);
246 	printf ("          Version : %s\n", PACKAGE_VERSION);
247 
248 #ifdef PACKAGE_REVISION
249 	printf ("         Revision : %s\n", PACKAGE_REVISION);
250 #endif
251 
252 	/* Show build time */
253 #ifdef __DATE__
254 	printf ("            Built : %s", __DATE__);
255 # ifdef __TIME__
256 	printf (" %s", __TIME__);
257 # endif
258 	putchar ('\n');
259 #endif
260 
261 	/* Show compiled-in components */
262 	printf ("    Compiled with :");
263 #ifdef HAVE_OSS
264 	printf (" OSS");
265 #endif
266 #ifdef HAVE_SNDIO
267 	printf (" SNDIO");
268 #endif
269 #ifdef HAVE_ALSA
270 	printf (" ALSA");
271 #endif
272 #ifdef HAVE_JACK
273 	printf (" JACK");
274 #endif
275 #ifndef NDEBUG
276 	printf (" DEBUG");
277 #endif
278 #ifdef HAVE_CURL
279 	printf (" Network streams");
280 #endif
281 #ifdef HAVE_SAMPLERATE
282 	printf (" resample");
283 #endif
284 	putchar ('\n');
285 
286 #ifdef HAVE_UNAME_SYSCALL
287 	rc = uname (&uts);
288 	if (rc == 0)
289 		printf ("       Running on : %s %s %s\n", uts.sysname, uts.release,
290 	                                                           uts.machine);
291 #endif
292 
293 	printf ("           Author : Damian Pietras\n");
294 	printf ("         Homepage : %s\n", PACKAGE_URL);
295 	printf ("           E-Mail : %s\n", PACKAGE_BUGREPORT);
296 	printf ("        Copyright : (C) 2003-2016 Damian Pietras and others\n");
297 	printf ("          License : GNU General Public License, version 2 or later\n");
298 	putchar ('\n');
299 }
300 
301 /* Show program usage. */
show_usage(const char * prg_name)302 static void show_usage (const char *prg_name) {
303 	printf ("%s (version %s", PACKAGE_NAME, PACKAGE_VERSION);
304 #ifdef PACKAGE_REVISION
305 	printf (", revision %s", PACKAGE_REVISION);
306 #endif
307 	printf (")\n");
308 	printf ("Usage:\n %s [OPTIONS]... [FILE]...\n%s", prg_name,
309 "-V --version           Print program version and exit\n"
310 "-h --help              Print usage and exit\n"
311 #ifndef NDEBUG
312 "-D --debug             Turn on logging to a file\n"
313 #endif
314 "-S --server            Only run the server\n"
315 "-F --foreground        Run server in foreground and log to stdout\n"
316 "-R --sound-driver LIST Use the first valid sound driver from LIST\n"
317 "                       (sndio, oss, alsa, jack, null)\n"
318 "-m --music-dir         Start in MusicDir\n"
319 "-a --append            Append the files/directories/playlists passed in\n"
320 "                       the command line to playlist and exit\n"
321 "-q --enqueue           Add the files given on command line to the queue\n"
322 "-c --clear             Clear the playlist and exit\n"
323 "-p --play              Start playing from the first item on the playlist\n"
324 "-l --playit            Play files given on the command line without modifying\n"
325 "                       the playlist\n"
326 "-s --stop              Stop playing\n"
327 "-f --next              Play the next song\n"
328 "-r --previous          Play the previous song\n"
329 "-x --exit              Shutdown the server\n"
330 "-T --theme theme       Use the selected theme file (read from ~/.moc/themes\n"
331 "                       if the path is not absolute)\n"
332 "-C --config FILE       Use the specified config file instead of the default\n"
333 "-O --set-option NAME=VALUE\n"
334 "                       Override the configuration option NAME with VALUE\n"
335 "-M --moc-dir DIR       Use the specified MOC directory instead of the default\n"
336 "-P --pause             Pause\n"
337 "-U --unpause           Unpause\n"
338 "-G --toggle-pause      Toggle between playing and paused\n"
339 "-v --volume (+/-)LEVEL Adjust the PCM volume\n"
340 "-y --sync              Synchronize the playlist with other clients\n"
341 "-n --nosync            Don't synchronize the playlist with other clients\n"
342 "-A --ascii             Use ASCII characters to draw lines\n"
343 "-i --info              Print information about the currently playing file\n"
344 "-Q --format FORMAT     Print formatted information about the currently\n"
345 "                       playing file\n"
346 "-e --recursively       Alias for -a\n"
347 "-k --seek N            Seek by N seconds (can be negative)\n"
348 "-j --jump N{%,s}       Jump to some position of the current track\n"
349 "-o --on <controls>     Turn on a control (shuffle, autonext, repeat)\n"
350 "-u --off <controls>    Turn off a control (shuffle, autonext, repeat)\n"
351 "-t --toggle <controls> Toggle a control (shuffle, autonext, repeat)\n");
352 }
353 
354 /* Send commands requested in params to the server. */
server_command(struct parameters * params,lists_t_strs * args)355 static void server_command (struct parameters *params, lists_t_strs *args)
356 {
357 	int sock;
358 
359 	if ((sock = server_connect()) == -1)
360 		fatal ("The server is not running!");
361 
362 	signal (SIGPIPE, SIG_IGN);
363 	if (ping_server(sock)) {
364 		if (params->playit)
365 			interface_cmdline_playit (sock, args);
366 		if (params->clear)
367 			interface_cmdline_clear_plist (sock);
368 		if (params->append)
369 			interface_cmdline_append (sock, args);
370 		if (params->enqueue)
371 			interface_cmdline_enqueue (sock, args);
372 		if (params->play)
373 			interface_cmdline_play_first (sock);
374 		if (params->get_file_info)
375 			interface_cmdline_file_info (sock);
376 		if (params->seek_by)
377 			interface_cmdline_seek_by (sock, params->seek_by);
378 		if (params->jump_type=='%')
379 			interface_cmdline_jump_to_percent (sock,params->jump_to);
380 		if (params->jump_type=='s')
381 			interface_cmdline_jump_to (sock,params->jump_to);
382 		if (params->get_formatted_info)
383 			interface_cmdline_formatted_info (sock,
384 					params->formatted_into_param);
385 		if (params->adj_volume)
386 			interface_cmdline_adj_volume (sock, params->adj_volume);
387 		if (params->toggle)
388 			interface_cmdline_set (sock, params->toggle, 2);
389 		if (params->on)
390 			interface_cmdline_set (sock, params->on, 1);
391 		if (params->off)
392 			interface_cmdline_set (sock, params->off, 0);
393 		if (params->exit) {
394 			if (!send_int(sock, CMD_QUIT))
395 				fatal ("Can't send command!");
396 		}
397 		else if (params->stop) {
398 			if (!send_int(sock, CMD_STOP)
399 					|| !send_int(sock, CMD_DISCONNECT))
400 				fatal ("Can't send commands!");
401 		}
402 		else if (params->pause) {
403 			if (!send_int(sock, CMD_PAUSE)
404 					|| !send_int(sock, CMD_DISCONNECT))
405 				fatal ("Can't send commands!");
406 		}
407 		else if (params->next) {
408 			if (!send_int(sock, CMD_NEXT)
409 					|| !send_int(sock, CMD_DISCONNECT))
410 				fatal ("Can't send commands!");
411 		}
412 		else if (params->previous) {
413 			if (!send_int(sock, CMD_PREV)
414 					|| !send_int(sock, CMD_DISCONNECT))
415 				fatal ("Can't send commands!");
416 		}
417 		else if (params->unpause) {
418 			if (!send_int(sock, CMD_UNPAUSE)
419 					|| !send_int(sock, CMD_DISCONNECT))
420 				fatal ("Can't send commands!");
421 		}
422 		else if (params->toggle_pause) {
423 			int state;
424 			int ev;
425 			int cmd = -1;
426 
427 			if (!send_int(sock, CMD_GET_STATE))
428 				fatal ("Can't send commands!");
429 			if (!get_int(sock, &ev) || ev != EV_DATA
430 					|| !get_int(sock, &state))
431 				fatal ("Can't get data from the server!");
432 
433 			if (state == STATE_PAUSE)
434 				cmd = CMD_UNPAUSE;
435 			else if (state == STATE_PLAY)
436 				cmd = CMD_PAUSE;
437 
438 			if (cmd != -1 && !send_int(sock, cmd))
439 				fatal ("Can't send commands!");
440 			if (!send_int(sock, CMD_DISCONNECT))
441 				fatal ("Can't send commands!");
442 		}
443 	}
444 	else
445 		fatal ("Can't connect to the server!");
446 
447 	close (sock);
448 }
449 
get_num_param(const char * p,const char ** last)450 static long get_num_param (const char *p,const char ** last)
451 {
452 	char *e;
453 	long val;
454 
455 	val = strtol (p, &e, 10);
456 	if ((*e&&last==NULL)||e==p)
457 		fatal ("The parameter should be a number!");
458 
459 	if (last)
460 		*last=e;
461 	return val;
462 }
463 
464 /* Log the command line which launched MOC. */
log_command_line(int argc,char * argv[])465 static void log_command_line (int argc, char *argv[])
466 {
467 	lists_t_strs *cmdline;
468 	char *str;
469 
470 	assert (argc >= 0);
471 	assert (argv != NULL);
472 	assert (argv[argc] == NULL);
473 
474 	cmdline = lists_strs_new (argc);
475 	if (lists_strs_load (cmdline, argv) > 0)
476 		str = lists_strs_fmt (cmdline, "%s ");
477 	else
478 		str = xstrdup ("No command line available");
479 	logit ("%s", str);
480 	free (str);
481 	lists_strs_free (cmdline);
482 }
483 
override_config_option(const char * optarg,lists_t_strs * deferred)484 static void override_config_option (const char *optarg, lists_t_strs *deferred)
485 {
486 	int len;
487 	bool append;
488 	char *ptr, *name, *value;
489 	enum option_type type;
490 
491 	assert (optarg != NULL);
492 
493 	ptr = strchr (optarg, '=');
494 	if (ptr == NULL)
495 		goto error;
496 
497 	/* Allow for list append operator ("+="). */
498 	append = (ptr > optarg && *(ptr - 1) == '+');
499 
500 	name = trim (optarg, ptr - optarg - (append ? 1 : 0));
501 	if (!name || !name[0])
502 		goto error;
503 	type = options_get_type (name);
504 
505 	if (type == OPTION_LIST) {
506 		if (deferred) {
507 			lists_strs_append (deferred, optarg);
508 			free (name);
509 			return;
510 		}
511 	}
512 	else if (append)
513 		goto error;
514 
515 	value = trim (ptr + 1, strlen (ptr + 1));
516 	if (!value || !value[0])
517 		goto error;
518 
519 	if (value[0] == '\'' || value[0] == '"') {
520 		len = strlen (value);
521 		if (value[0] != value[len - 1])
522 			goto error;
523 		if (strlen (value) < 2)
524 			goto error;
525 		memmove (value, value + 1, len - 2);
526 		value[len - 2] = 0x00;
527 	}
528 
529 	if (!options_set_pair (name, value, append))
530 		goto error;
531 	options_ignore_config (name);
532 
533 	free (name);
534 	free (value);
535 	return;
536 
537 error:
538 	fatal ("Malformed override option: %s", optarg);
539 }
540 
process_deferred_overrides(lists_t_strs * deferred)541 static void process_deferred_overrides (lists_t_strs *deferred)
542 {
543 	int ix;
544 	bool cleared;
545 	const char marker[] = "*Marker*";
546 	char **config_decoders;
547 	lists_t_strs *decoders_option;
548 
549 	/* We need to shuffle the PreferredDecoders list into the
550 	 * right order as we load any deferred overriding options. */
551 
552 	decoders_option = options_get_list ("PreferredDecoders");
553 	lists_strs_reverse (decoders_option);
554 	config_decoders = lists_strs_save (decoders_option);
555 	lists_strs_clear (decoders_option);
556 	lists_strs_append (decoders_option, marker);
557 
558 	for (ix = 0; ix < lists_strs_size (deferred); ix += 1)
559 		override_config_option (lists_strs_at (deferred, ix), NULL);
560 
561 	cleared = lists_strs_empty (decoders_option) ||
562 	          strcmp (lists_strs_at (decoders_option, 0), marker) != 0;
563 	lists_strs_reverse (decoders_option);
564 	if (!cleared) {
565 		char **override_decoders;
566 
567 		free (lists_strs_pop (decoders_option));
568 		override_decoders = lists_strs_save (decoders_option);
569 		lists_strs_clear (decoders_option);
570 		lists_strs_load (decoders_option, config_decoders);
571 		lists_strs_load (decoders_option, override_decoders);
572 		free (override_decoders);
573 	}
574 	free (config_decoders);
575 }
576 
577 /* Process the command line options and arguments. */
process_command_line(int argc,char * argv[],struct parameters * params,lists_t_strs * deferred)578 static lists_t_strs *process_command_line (int argc, char *argv[],
579                                            struct parameters *params,
580                                            lists_t_strs *deferred)
581 {
582 	int ret, opt_index = 0;
583 	const char *jump_type;
584 	lists_t_strs *result;
585 
586 	struct option long_options[] = {
587 		{ "version",		0, NULL, 'V' },
588 		{ "help",		0, NULL, 'h' },
589 #ifndef NDEBUG
590 		{ "debug",		0, NULL, 'D' },
591 #endif
592 		{ "server",		0, NULL, 'S' },
593 		{ "foreground",		0, NULL, 'F' },
594 		{ "sound-driver",	1, NULL, 'R' },
595 		{ "music-dir",		0, NULL, 'm' },
596 		{ "append",		0, NULL, 'a' },
597 		{ "enqueue",		0, NULL, 'q' },
598 		{ "clear", 		0, NULL, 'c' },
599 		{ "play", 		0, NULL, 'p' },
600 		{ "playit",		0, NULL, 'l' },
601 		{ "stop",		0, NULL, 's' },
602 		{ "next",		0, NULL, 'f' },
603 		{ "previous",		0, NULL, 'r' },
604 		{ "exit",		0, NULL, 'x' },
605 		{ "theme",		1, NULL, 'T' },
606 		{ "config",		1, NULL, 'C' },
607 		{ "set-option",		1, NULL, 'O' },
608 		{ "moc-dir",		1, NULL, 'M' },
609 		{ "pause",		0, NULL, 'P' },
610 		{ "unpause",		0, NULL, 'U' },
611 		{ "toggle-pause",	0, NULL, 'G' },
612 		{ "sync",		0, NULL, 'y' },
613 		{ "nosync",		0, NULL, 'n' },
614 		{ "ascii",		0, NULL, 'A' },
615 		{ "info",		0, NULL, 'i' },
616 		{ "recursively",	0, NULL, 'e' },
617 		{ "seek",		1, NULL, 'k' },
618 		{ "jump",		1, NULL, 'j' },
619 		{ "format",		1, NULL, 'Q' },
620 		{ "volume",		1, NULL, 'v' },
621 		{ "toggle",		1, NULL, 't' },
622 		{ "on",			1, NULL, 'o' },
623 		{ "off",		1, NULL, 'u' },
624 		{ 0, 0, 0, 0 }
625 	};
626 
627 	assert (argc >= 0);
628 	assert (argv != NULL);
629 	assert (argv[argc] == NULL);
630 	assert (params != NULL);
631 	assert (deferred != NULL);
632 
633 	while ((ret = getopt_long(argc, argv,
634 					"VhDSFR:macpsxT:C:O:M:PUynArfiGelk:j:v:t:o:u:Q:q",
635 					long_options, &opt_index)) != -1) {
636 		switch (ret) {
637 			case 'V':
638 				show_version ();
639 				exit (EXIT_SUCCESS);
640 			case 'h':
641 				show_usage (argv[0]);
642 				exit (EXIT_SUCCESS);
643 #ifndef NDEBUG
644 			case 'D':
645 				params->debug = 1;
646 				break;
647 #endif
648 			case 'S':
649 				params->only_server = 1;
650 				break;
651 			case 'F':
652 				params->foreground = 1;
653 				params->only_server = 1;
654 				break;
655 			case 'R':
656 				if (!options_check_list ("SoundDriver", optarg))
657 					fatal ("No such sound driver: %s", optarg);
658 				options_set_list ("SoundDriver", optarg, false);
659 				options_ignore_config ("SoundDriver");
660 				break;
661 			case 'm':
662 				options_set_int ("StartInMusicDir", 1);
663 				options_ignore_config ("StartInMusicDir");
664 				break;
665 			case 'a':
666 			case 'e':
667 				params->append = 1;
668 				params->dont_run_iface = 1;
669 				break;
670 			case 'q':
671 				params->enqueue = 1;
672 				params->dont_run_iface = 1;
673 				break;
674 			case 'c':
675 				params->clear = 1;
676 				params->dont_run_iface = 1;
677 				break;
678 			case 'i':
679 				params->get_file_info = 1;
680 				params->dont_run_iface = 1;
681 				break;
682 			case 'p':
683 				params->play = 1;
684 				params->dont_run_iface = 1;
685 				break;
686 			case 'l':
687 				params->playit = 1;
688 				params->dont_run_iface = 1;
689 				break;
690 			case 's':
691 				params->stop = 1;
692 				params->dont_run_iface = 1;
693 				break;
694 			case 'f':
695 				params->next = 1;
696 				params->dont_run_iface = 1;
697 				break;
698 			case 'r':
699 				params->previous = 1;
700 				params->dont_run_iface = 1;
701 				break;
702 			case 'x':
703 				params->exit = 1;
704 				params->dont_run_iface = 1;
705 				break;
706 			case 'P':
707 				params->pause = 1;
708 				params->dont_run_iface = 1;
709 				break;
710 			case 'U':
711 				params->unpause = 1;
712 				params->dont_run_iface = 1;
713 				break;
714 			case 'T':
715 				options_set_str ("ForceTheme", optarg);
716 				break;
717 			case 'C':
718 				params->config_file = xstrdup (optarg);
719 				break;
720 			case 'O':
721 				override_config_option (optarg, deferred);
722 				break;
723 			case 'M':
724 				options_set_str ("MOCDir", optarg);
725 				options_ignore_config ("MOCDir");
726 				break;
727 			case 'y':
728 				options_set_int ("SyncPlaylist", 1);
729 				options_ignore_config ("SyncPlaylist");
730 				break;
731 			case 'n':
732 				options_set_int ("SyncPlaylist", 0);
733 				options_ignore_config ("SyncPlaylist");
734 				break;
735 			case 'A':
736 				options_set_int ("ASCIILines", 1);
737 				options_ignore_config ("ASCIILines");
738 				break;
739 			case 'G':
740 				params->toggle_pause = 1;
741 				params->dont_run_iface = 1;
742 				break;
743 			case 'k':
744 				params->seek_by = get_num_param (optarg, NULL);
745 				params->dont_run_iface = 1;
746 				break;
747 			case 'j':
748 				params->jump_to = get_num_param (optarg, &jump_type);
749 				if (*jump_type)
750 					if (!jump_type[1])
751 						if (*jump_type == '%' || tolower (*jump_type) == 's') {
752 							params->jump_type = tolower (*jump_type);
753 							params->dont_run_iface = 1;
754 							break;
755 						}
756 				//TODO: Add message explaining the error
757 				show_usage (argv[0]);
758 				exit (EXIT_FAILURE);
759 			case 'v' :
760 				params->adj_volume = optarg;
761 				params->dont_run_iface = 1;
762 				break;
763 			case 't' :
764 				params->toggle = optarg;
765 				params->dont_run_iface = 1;
766 				break;
767 			case 'o' :
768 				params->on = optarg;
769 				params->dont_run_iface = 1;
770 				break;
771 			case 'u' :
772 				params->off = optarg;
773 				params->dont_run_iface = 1;
774 				break;
775 			case 'Q':
776 				params->formatted_into_param = optarg;
777 				params->get_formatted_info = 1;
778 				params->dont_run_iface = 1;
779 				break;
780 			default:
781 				show_usage (argv[0]);
782 				exit (EXIT_FAILURE);
783 		}
784 	}
785 
786 	result = lists_strs_new (argc - optind);
787 	lists_strs_load (result, argv + optind);
788 
789 	return result;
790 }
791 
main(int argc,char * argv[])792 int main (int argc, char *argv[])
793 {
794 	struct parameters params;
795 	lists_t_strs *deferred_overrides;
796 	lists_t_strs *args;
797 
798 #ifdef HAVE_UNAME_SYSCALL
799 	int rc;
800 	struct utsname uts;
801 #endif
802 
803 #ifdef PACKAGE_REVISION
804 	logit ("This is Music On Console (revision %s)", PACKAGE_REVISION);
805 #else
806 	logit ("This is Music On Console (version %s)", PACKAGE_VERSION);
807 #endif
808 
809 #ifdef CONFIGURATION
810 	logit ("Configured:%s", CONFIGURATION);
811 #endif
812 
813 #ifdef HAVE_UNAME_SYSCALL
814 	rc = uname (&uts);
815 	if (rc == 0)
816 		logit ("Running on: %s %s %s", uts.sysname, uts.release, uts.machine);
817 #endif
818 
819 	log_command_line (argc, argv);
820 
821 	files_init ();
822 
823 	if (get_home () == NULL)
824 		fatal ("Could not determine user's home directory!");
825 
826 	memset (&params, 0, sizeof(params));
827 	options_init ();
828 	deferred_overrides = lists_strs_new (4);
829 
830 	/* set locale according to the environment variables */
831 	if (!setlocale(LC_ALL, ""))
832 		logit ("Could not set locale!");
833 
834 	args = process_command_line (argc, argv, &params, deferred_overrides);
835 
836 	if (params.dont_run_iface && params.only_server)
837 		fatal ("-c, -a and -p options can't be used with --server!");
838 
839 	if (!params.config_file)
840 		params.config_file = xstrdup (create_file_name ("config"));
841 	options_parse (params.config_file);
842 	if (params.config_file)
843 		free (params.config_file);
844 	params.config_file = NULL;
845 
846 	process_deferred_overrides (deferred_overrides);
847 	lists_strs_free (deferred_overrides);
848 	deferred_overrides = NULL;
849 
850 	check_moc_dir ();
851 
852 	io_init ();
853 	rcc_init ();
854 	decoder_init (params.debug);
855 	srand (time(NULL));
856 
857 	if (!params.only_server && params.dont_run_iface)
858 		server_command (&params, args);
859 	else
860 		start_moc (&params, args);
861 
862 	lists_strs_free (args);
863 	options_free ();
864 	decoder_cleanup ();
865 	io_cleanup ();
866 	rcc_cleanup ();
867 	files_cleanup ();
868 	compat_cleanup ();
869 
870 	return EXIT_SUCCESS;
871 }
872