2 * Copyright 2005-2006 Timo Hirvonen
12 #include <sys/types.h>
13 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
24 static int raw_args
= 0;
27 static void gethostbyname_failed(void)
29 const char *error
= "Unknown error.";
34 error
= "Host not found.";
37 error
= "A non-recoverable name server error.";
40 error
= "A temporary error occurred on an authoritative name server.";
43 die("gethostbyname: %s\n", error
);
46 static void write_line(const char *line
)
48 if (write_all(sock
, line
, strlen(line
)) == -1)
52 static void send_cmd(const char *format
, ...)
58 vsnprintf(buf
, sizeof(buf
), format
, ap
);
64 static void remote_connect(const char *address
)
68 struct sockaddr_un un
;
69 struct sockaddr_in in
;
73 if (strchr(address
, '/')) {
75 warn("password ignored for unix connections\n");
78 addr
.sa
.sa_family
= AF_UNIX
;
79 strncpy(addr
.un
.sun_path
, address
, sizeof(addr
.un
.sun_path
) - 1);
81 addrlen
= sizeof(addr
.un
);
83 char *s
= strchr(address
, ':');
84 int port
= DEFAULT_PORT
;
88 die("password required for tcp/ip connection\n");
94 hent
= gethostbyname(address
);
96 gethostbyname_failed();
98 addr
.sa
.sa_family
= hent
->h_addrtype
;
99 switch (addr
.sa
.sa_family
) {
101 memcpy(&addr
.in
.sin_addr
, hent
->h_addr_list
[0], hent
->h_length
);
102 addr
.in
.sin_port
= htons(port
);
104 addrlen
= sizeof(addr
.in
);
107 die("unsupported address type\n");
111 sock
= socket(addr
.sa
.sa_family
, SOCK_STREAM
, 0);
115 if (connect(sock
, &addr
.sa
, addrlen
)) {
116 if (errno
== ENOENT
|| errno
== ECONNREFUSED
) {
117 /* "cmus-remote -C" can be used to check if cmus is running */
119 warn("cmus is not running\n");
122 die_errno("connect");
126 send_cmd("%s\n", passwd
);
129 static char *file_url_absolute(const char *str
)
133 if (strncmp(str
, "http://", 7) == 0)
136 absolute
= path_absolute(str
);
137 if (absolute
== NULL
)
138 die_errno("get_current_dir_name");
165 #define NR_FLAGS (FLAG_RAW + 1)
168 static struct option options
[NR_FLAGS
+ 1] = {
180 { 'R', "repeat", 0 },
181 { 'S', "shuffle", 0 },
182 { 'v', "volume", 1 },
185 { 'l', "library", 0 },
186 { 'P', "playlist", 0 },
194 static int flags
[NR_FLAGS
] = { 0, };
196 static const char *usage
=
197 "Usage: %s [OPTION]... [FILE|DIR|PLAYLIST]...\n"
198 " or: %s -C COMMAND...\n"
200 "Control cmus through socket.\n"
202 " --server ADDR connect using ADDR instead of ~/.cmus/socket\n"
203 " ADDR is either a UNIX socket or host[:port]\n"
204 " --passwd PASSWD password to use for TCP/IP connection\n"
205 " --help display this help and exit\n"
206 " --version " VERSION
"\n"
209 " -p, --play player-play\n"
210 " -u, --pause player-pause\n"
211 " -s, --stop player-stop\n"
212 " -n, --next player-next\n"
213 " -r, --prev player-prev\n"
214 " -f, --file player-play FILE\n"
215 " -R, --repeat toggle repeat\n"
216 " -S, --shuffle toggle shuffle\n"
217 " -v, --volume VOL vol VOL\n"
218 " -k, --seek SEEK seek SEEK\n"
220 " -l, --library modify library instead of playlist\n"
221 " -P, --playlist modify playlist (default)\n"
222 " -q, --queue modify play queue instead of playlist\n"
223 " -c, --clear clear playlist, library (-l) or play queue (-q)\n"
225 " Add FILE/DIR/PLAYLIST to playlist, library (-l) or play queue (-q).\n"
228 " -C, --raw treat arguments (instead of stdin) as raw commands\n"
230 " By default cmus-remote reads raw commands from stdin (one command per line).\n"
232 "Report bugs to <cmus-devel@lists.sourceforge.net>.\n";
234 int main(int argc
, char *argv
[])
236 char server_buf
[256];
238 char *play_file
= NULL
;
244 program_name
= argv
[0];
250 idx
= get_option(&argv
, options
, &arg
);
255 switch ((enum flags
)idx
) {
257 printf(usage
, program_name
, program_name
, program_name
);
260 printf("cmus " VERSION
"\nCopyright 2004-2006 Timo Hirvonen\n");
305 if (nr_cmds
&& raw_args
)
306 die("don't mix raw and cooked stuff\n");
308 if (server
== NULL
) {
309 const char *config_dir
= getenv("CMUS_HOME");
311 if (config_dir
&& config_dir
[0]) {
312 snprintf(server_buf
, sizeof(server_buf
), "%s/socket", config_dir
);
314 const char *home
= getenv("HOME");
317 die("error: environment variable HOME not set\n");
318 snprintf(server_buf
, sizeof(server_buf
), "%s/.cmus/socket", home
);
323 remote_connect(server
);
327 send_cmd("%s\n", *argv
++);
331 if (nr_cmds
== 0 && argv
[0] == NULL
) {
334 while (fgets(line
, sizeof(line
), stdin
))
339 if (flags
[FLAG_CLEAR
])
340 send_cmd("clear -%c\n", context
);
341 for (i
= 0; argv
[i
]; i
++) {
342 char *filename
= file_url_absolute(argv
[i
]);
344 send_cmd("add -%c %s\n", context
, filename
);
347 if (flags
[FLAG_REPEAT
])
348 send_cmd("toggle repeat\n");
349 if (flags
[FLAG_SHUFFLE
])
350 send_cmd("toggle shuffle\n");
351 if (flags
[FLAG_STOP
])
352 send_cmd("player-stop\n");
353 if (flags
[FLAG_NEXT
])
354 send_cmd("player-next\n");
355 if (flags
[FLAG_PREV
])
356 send_cmd("player-prev\n");
357 if (flags
[FLAG_PLAY
])
358 send_cmd("player-play\n");
359 if (flags
[FLAG_PAUSE
])
360 send_cmd("player-pause\n");
361 if (flags
[FLAG_FILE
])
362 send_cmd("player-play %s\n", file_url_absolute(play_file
));
364 send_cmd("vol %s\n", volume
);
366 send_cmd("seek %s\n", seek
);