add :refresh command
[cmus.git] / main.c
blob12725add162de40a736f7899f1096fd7520f9f5e
1 /*
2 * Copyright 2005-2006 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include <config.h>
21 #include <prog.h>
22 #include <file.h>
23 #include <path.h>
24 #include <remote.h>
25 #include <xmalloc.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sys/un.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <errno.h>
37 static int sock;
38 static int raw_args = 0;
40 static void remote_connect(const char *server)
42 struct sockaddr_un addr;
44 sock = socket(PF_UNIX, SOCK_STREAM, 0);
45 if (sock == -1)
46 die_errno("socket");
47 addr.sun_family = AF_UNIX;
48 strncpy(addr.sun_path, server, sizeof(addr.sun_path) - 1);
49 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr))) {
50 if (errno == ENOENT || errno == ECONNREFUSED) {
51 /* "cmus-remote -C" can be used to check if cmus is running */
52 if (!raw_args)
53 warn(PACKAGE " is not running\n");
54 exit(1);
56 die_errno("connect");
60 static void write_line(const char *line)
62 if (write_all(sock, line, strlen(line)) == -1)
63 die_errno("write");
66 static void send_cmd(const char *format, ...)
68 char buf[512];
69 va_list ap;
71 va_start(ap, format);
72 vsnprintf(buf, sizeof(buf), format, ap);
73 va_end(ap);
75 write_line(buf);
78 enum flags {
79 FLAG_SERVER,
80 FLAG_HELP,
81 FLAG_VERSION,
83 FLAG_PLAY,
84 FLAG_PAUSE,
85 FLAG_STOP,
86 FLAG_NEXT,
87 FLAG_PREV,
88 FLAG_REPEAT,
89 FLAG_SHUFFLE,
90 FLAG_VOLUME,
91 FLAG_SEEK,
93 FLAG_LIBRARY,
94 FLAG_PLAYLIST,
95 FLAG_QUEUE,
96 FLAG_CLEAR,
98 FLAG_RAW
99 #define NR_FLAGS (FLAG_RAW + 1)
102 static struct option options[NR_FLAGS + 1] = {
103 { 0, "server", 1 },
104 { 0, "help", 0 },
105 { 0, "version", 0 },
107 { 'p', "play", 0 },
108 { 'u', "pause", 0 },
109 { 's', "stop", 0 },
110 { 'n', "next", 0 },
111 { 'r', "prev", 0 },
112 { 'R', "repeat", 0 },
113 { 'S', "shuffle", 0 },
114 { 'v', "volume", 1 },
115 { 'k', "seek", 1 },
117 { 'l', "library", 0 },
118 { 'P', "playlist", 0 },
119 { 'q', "queue", 0 },
120 { 'c', "clear", 0 },
122 { 'C', "raw", 0 },
123 { 0, NULL, 0 }
126 static int flags[NR_FLAGS] = { 0, };
128 static const char *usage =
129 "Usage: %s [OPTION]... [FILE|DIR|PLAYLIST]...\n"
130 " or: %s -C COMMAND...\n"
131 " or: %s\n"
132 "Control cmus through socket.\n"
133 "\n"
134 " --server SOCKET connect using socket SOCKET instead of /tmp/cmus-$USER\n"
135 " --help display this help and exit\n"
136 " --version " VERSION "\n"
137 "\n"
138 "Cooked mode:\n"
139 " -p, --play player-play\n"
140 " -u, --pause player-pause\n"
141 " -s, --stop player-stop\n"
142 " -n, --next player-next\n"
143 " -r, --prev player-prev\n"
144 " -R, --repeat toggle repeat\n"
145 " -S, --shuffle toggle shuffle\n"
146 " -v, --volume VOL vol VOL\n"
147 " -k, --seek SEEK seek SEEK\n"
148 "\n"
149 " -l, --library modify library instead of playlist\n"
150 " -P, --playlist modify playlist (default)\n"
151 " -q, --queue modify play queue instead of playlist\n"
152 " -c, --clear clear playlist, library (-l) or play queue (-q)\n"
153 "\n"
154 " Add FILE/DIR/PLAYLIST to playlist, library (-l) or play queue (-q).\n"
155 "\n"
156 "Raw mode:\n"
157 " -C, --raw treat arguments (instead of stdin) as raw commands\n"
158 "\n"
159 " By default cmus-remote reads raw commands from stdin (one command per line).\n"
160 "\n"
161 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
163 int main(int argc, char *argv[])
165 char server_buf[256];
166 char *server = NULL;
167 char *volume = NULL;
168 char *seek = NULL;
169 int i, nr_cmds = 0;
170 int context = 'p';
172 program_name = argv[0];
173 argv++;
174 while (1) {
175 int idx;
176 char *arg;
178 idx = get_option(&argv, options, &arg);
179 if (idx < 0)
180 break;
182 flags[idx] = 1;
183 switch ((enum flags)idx) {
184 case FLAG_HELP:
185 printf(usage, program_name, program_name, program_name);
186 return 0;
187 case FLAG_VERSION:
188 printf(PACKAGE " " VERSION "\nCopyright 2004-2006 Timo Hirvonen\n");
189 return 0;
190 case FLAG_SERVER:
191 server = arg;
192 break;
193 case FLAG_VOLUME:
194 volume = arg;
195 nr_cmds++;
196 break;
197 case FLAG_SEEK:
198 seek = arg;
199 nr_cmds++;
200 break;
201 case FLAG_LIBRARY:
202 context = 'l';
203 break;
204 case FLAG_PLAYLIST:
205 context = 'p';
206 break;
207 case FLAG_QUEUE:
208 context = 'q';
209 break;
210 case FLAG_PLAY:
211 case FLAG_PAUSE:
212 case FLAG_STOP:
213 case FLAG_NEXT:
214 case FLAG_PREV:
215 case FLAG_REPEAT:
216 case FLAG_SHUFFLE:
217 case FLAG_CLEAR:
218 nr_cmds++;
219 break;
220 case FLAG_RAW:
221 raw_args = 1;
222 break;
226 if (nr_cmds && raw_args)
227 die("don't mix raw and cooked stuff\n");
229 if (server == NULL) {
230 const char *user_name;
232 user_name = getenv("USER");
233 if (user_name == NULL || user_name[0] == 0) {
234 user_name = getenv("USERNAME");
235 if (user_name == NULL || user_name[0] == 0)
236 die("neither USER or USERNAME environment variable is set\n");
238 snprintf(server_buf, sizeof(server_buf), "/tmp/cmus-%s", user_name);
239 server = server_buf;
242 remote_connect(server);
244 if (raw_args) {
245 while (*argv)
246 send_cmd("%s\n", *argv++);
247 return 0;
250 if (nr_cmds == 0 && argv[0] == NULL) {
251 char line[512];
253 while (fgets(line, sizeof(line), stdin))
254 write_line(line);
255 return 0;
258 if (flags[FLAG_CLEAR])
259 send_cmd("clear -%c\n", context);
260 for (i = 0; argv[i]; i++) {
261 char *filename;
263 if (strncmp(argv[i], "http://", 7) == 0) {
264 filename = xstrdup(argv[i]);
265 } else {
266 filename = path_absolute(argv[i]);
267 if (filename == NULL) {
268 warn_errno("get_current_dir_name");
269 continue;
272 send_cmd("add -%c %s\n", context, filename);
273 free(filename);
275 if (flags[FLAG_REPEAT])
276 send_cmd("toggle repeat\n");
277 if (flags[FLAG_SHUFFLE])
278 send_cmd("toggle shuffle\n");
279 if (flags[FLAG_STOP])
280 send_cmd("player-stop\n");
281 if (flags[FLAG_NEXT])
282 send_cmd("player-next\n");
283 if (flags[FLAG_PREV])
284 send_cmd("player-prev\n");
285 if (flags[FLAG_PLAY])
286 send_cmd("player-play\n");
287 if (flags[FLAG_PAUSE])
288 send_cmd("player-pause\n");
289 if (volume)
290 send_cmd("vol %s\n", volume);
291 if (seek)
292 send_cmd("seek %s\n", seek);
293 return 0;