diff --git a/command_mode.c b/command_mode.c
index a2a67a1..0278bb9 100644
--- a/command_mode.c
+++ b/command_mode.c
@@ -67,6 +67,45 @@ static char *cmd_history_filename;
 static char *history_search_text = NULL;
 static int arg_expand_cmd = -1;
 static int prev_view = -1;
+char *command_answer;
+
+enum {
+	GI_ARTIST,
+	GI_ALBUM,
+	GI_DISC,
+	GI_TRACK,
+	GI_TITLE,
+	GI_YEAR,
+	GI_GENRE,
+	GI_DURATION,
+	GI_PATHFILE,
+	GI_FILE,
+	GI_POSITION,
+	GI_VOLUME,
+	GI_CONTINUE,
+	GI_REPEAT,
+	GI_SHUFFLE,
+	NR_GIS
+};
+
+static struct format_option track_fopts[NR_GIS + 1] = {
+	DEF_FO_STR('a'),
+	DEF_FO_STR('l'),
+	DEF_FO_INT('D'),
+	DEF_FO_INT('n'),
+	DEF_FO_STR('t'),
+	DEF_FO_STR('y'),
+	DEF_FO_STR('g'),
+	DEF_FO_TIME('d'),
+	DEF_FO_STR('f'),
+	DEF_FO_STR('F'),
+	DEF_FO_TIME('p'),
+	DEF_FO_INT('v'),
+	DEF_FO_INT('C'),
+	DEF_FO_INT('R'),
+	DEF_FO_INT('S'),
+	DEF_FO_END
+};
 
 static char *get_home_dir(const char *username)
 {
@@ -2304,6 +2343,49 @@ static void expand_colorscheme(const char *str)
 
 /* tab exp }}} */
 
+static void cmd_getinfo(char *args)
+{
+	int pos = 0;
+	if(player_info.ti)
+	{
+		fill_track_fopts_track_info(player_info.ti, track_fopts);
+		fopt_set_time(&track_fopts[GI_POSITION], player_info.pos, player_info.pos == -1);
+	} else {
+		fopt_set_str(&track_fopts[GI_ARTIST], NULL);
+		fopt_set_str(&track_fopts[GI_ALBUM], NULL);
+		fopt_set_int(&track_fopts[GI_DISC], 0, 1);
+		fopt_set_int(&track_fopts[GI_TRACK], 0, 1);
+		fopt_set_str(&track_fopts[GI_TITLE], NULL);
+		fopt_set_str(&track_fopts[GI_YEAR], NULL);
+		fopt_set_str(&track_fopts[GI_GENRE], NULL);
+		fopt_set_time(&track_fopts[GI_DURATION], 0, 1);
+		fopt_set_str(&track_fopts[GI_PATHFILE], NULL);
+		fopt_set_str(&track_fopts[GI_FILE], NULL);
+		fopt_set_time(&track_fopts[GI_POSITION], -1, 1);
+	}
+	fopt_set_int(&track_fopts[GI_CONTINUE], player_cont, 0);
+	fopt_set_int(&track_fopts[GI_REPEAT], repeat, 0);
+	fopt_set_int(&track_fopts[GI_SHUFFLE], shuffle, 0);
+	if (soft_vol)
+		fopt_set_int(&track_fopts[GI_VOLUME], (soft_vol_l + soft_vol_r + 1) / 2, 0);
+	else if (!volume_max)
+		fopt_set_int(&track_fopts[GI_VOLUME], -1, 1);
+	else
+		fopt_set_int(&track_fopts[GI_VOLUME], (scale_to_percentage(volume_l, volume_max) + scale_to_percentage(volume_r, volume_max) + 1) / 2, 0);
+	format_print(command_answer, 1023, args, track_fopts);
+	while (command_answer[pos])
+	{
+		if (command_answer[pos++] != ' ')
+			continue;
+		else if (command_answer[pos] != ' ')
+			continue;
+		else {
+			command_answer[pos-1] = '\0';
+			break;
+		}
+	}
+}
+
 /* sort by name */
 struct command commands[] = {
 	{ "add",		cmd_add,	1, 1, expand_add,	  0, 0 },
@@ -2316,6 +2398,7 @@ struct command commands[] = {
 	{ "factivate",		cmd_factivate,	0, 1, expand_factivate,	  0, 0 },
 	{ "filter",		cmd_filter,	0, 1, NULL,		  0, 0 },
 	{ "fset",		cmd_fset,	1, 1, NULL,		  0, 0 },
+	{ "get-info",		cmd_getinfo,	1, 1, NULL,		  0, CMD_STRING },
 	{ "invert",		cmd_invert,	0, 0, NULL,		  0, 0 },
 	{ "load",		cmd_load,	1, 1, expand_load_save,	  0, 0 },
 	{ "lqueue",		cmd_lqueue,	0, 1, NULL,		  0, 0 },
@@ -2523,7 +2606,7 @@ static void reset_tab_expansion(void)
 int run_only_safe_commands;
 
 /* FIXME: parse all arguments */
-void run_command(const char *buf)
+char *run_command(const char *buf)
 {
 	char *cmd, *arg;
 	int cmd_start, cmd_end, cmd_len;
@@ -2535,7 +2618,7 @@ void run_command(const char *buf)
 		i++;
 
 	if (buf[i] == '#')
-		return;
+		return NULL;
 
 	cmd_start = i;
 	while (buf[i] && buf[i] != ' ')
@@ -2550,7 +2633,7 @@ void run_command(const char *buf)
 
 	cmd_len = cmd_end - cmd_start;
 	if (cmd_len == 0)
-		return;
+		return NULL;
 
 	cmd = xstrndup(buf + cmd_start, cmd_len);
 	if (arg_start == arg_end) {
@@ -2586,13 +2669,21 @@ void run_command(const char *buf)
 				d_print("trying to execute unsafe command over net\n");
 				break;
 			}
+			if (c->flags & CMD_STRING) {
+				command_answer = malloc(sizeof(char) * 1024);
+				memset(command_answer, '\0', 1024);
+			}
 			c->func(arg);
+			if (!(c->flags & CMD_STRING)) {
+				command_answer = NULL;
+			}
 			break;
 		}
 		i++;
 	}
 	free(arg);
 	free(cmd);
+	return command_answer;
 }
 
 static void reset_history_search(void)
@@ -2729,3 +2820,4 @@ void commands_exit(void)
 	free(cmd_history_filename);
 	tabexp_reset();
 }
+
diff --git a/command_mode.h b/command_mode.h
index fc98e3a..539403b 100644
--- a/command_mode.h
+++ b/command_mode.h
@@ -24,6 +24,8 @@
 
 /* executing command is disabled over net */
 #define CMD_UNSAFE 0x01
+/* this command has a string return */
+#define CMD_STRING 0x02
 
 struct command {
 	const char *name;
@@ -49,7 +51,7 @@ void command_mode_ch(uchar ch);
 void command_mode_key(int key);
 void commands_init(void);
 void commands_exit(void);
-void run_command(const char *buf);
+char *run_command(const char *buf);
 
 struct command *get_command(const char *str);
 
diff --git a/main.c b/main.c
index b68ba25..7e54354 100644
--- a/main.c
+++ b/main.c
@@ -45,8 +45,26 @@ static void gethostbyname_failed(void)
 
 static void write_line(const char *line)
 {
+	char *answer = xmalloc(sizeof(char) * 512);
+	int pos = 0;
 	if (write_all(sock, line, strlen(line)) == -1)
 		die_errno("write");
+	memset(answer, 0, 512);
+	do {
+		int rc = read(sock, answer + pos, 1);
+		if (rc == -1) {
+			if (errno == EINTR || errno == EAGAIN)
+				continue;
+			return;
+		}
+		if (rc == 0) {
+			break;
+		}
+		pos += rc;
+	} while ((answer + pos - 1)[0] != '\n' && pos < 512);
+	if (strcmp(answer, "\n"))
+		printf("%s", answer);
+	free(answer);
 }
 
 static void send_cmd(const char *format, ...)
@@ -161,6 +179,8 @@ enum flags {
 	FLAG_QUEUE,
 	FLAG_CLEAR,
 
+	FLAG_QUERY,
+
 	FLAG_RAW
 #define NR_FLAGS (FLAG_RAW + 1)
 };
@@ -187,6 +207,8 @@ static struct option options[NR_FLAGS + 1] = {
 	{ 'q', "queue", 0 },
 	{ 'c', "clear", 0 },
 
+	{ 'Q', "query", 1 },
+
 	{ 'C', "raw", 0 },
 	{ 0, NULL, 0 }
 };
@@ -225,6 +247,9 @@ static const char *usage =
 "\n"
 "  Add FILE/DIR/PLAYLIST to playlist, library (-l) or play queue (-q).\n"
 "\n"
+"  -Q, --query QUERY    query cmus for information\n"
+"                       (see manpage ,,Format Strings'')\n"
+"\n"
 "Raw mode:\n"
 "  -C, --raw            treat arguments (instead of stdin) as raw commands\n"
 "\n"
@@ -239,6 +264,7 @@ int main(int argc, char *argv[])
 	char *play_file = NULL;
 	char *volume = NULL;
 	char *seek = NULL;
+	char *query = NULL;
 	int i, nr_cmds = 0;
 	int context = 'p';
 
@@ -297,6 +323,10 @@ int main(int argc, char *argv[])
 		case FLAG_CLEAR:
 			nr_cmds++;
 			break;
+		case FLAG_QUERY:
+			nr_cmds++;
+			query = arg;
+			break;
 		case FLAG_RAW:
 			raw_args = 1;
 			break;
@@ -337,6 +367,8 @@ int main(int argc, char *argv[])
 		return 0;
 	}
 
+	if (flags[FLAG_QUERY])
+		send_cmd("get-info %s\n", query);
 	if (flags[FLAG_CLEAR])
 		send_cmd("clear -%c\n", context);
 	for (i = 0; argv[i]; i++) {
diff --git a/server.c b/server.c
index 72aceeb..f72c65a 100644
--- a/server.c
+++ b/server.c
@@ -52,7 +52,7 @@ static void read_commands(int fd)
 	int authenticated = addr.sa.sa_family == AF_UNIX;
 
 	while (1) {
-		int rc, s, i;
+		int rc, wc, s, i;
 
 		rc = read(fd, buf + pos, sizeof(buf) - pos);
 		if (rc == -1) {
@@ -66,6 +66,7 @@ static void read_commands(int fd)
 		s = 0;
 		for (i = 0; i < pos; i++) {
 			const char *line;
+			char *ret;
 
 			if (buf[i] != '\n')
 				continue;
@@ -86,7 +87,15 @@ static void read_commands(int fd)
 				}
 				continue;
 			}
-			run_command(line);
+			ret = run_command(line);
+			if (ret != NULL) {
+				ret = realloc(ret, sizeof(char)*(strlen(ret)+2));
+				strcat(ret, "\n");
+				wc = write(fd, ret, strlen(ret));
+			} else {
+				wc = write(fd, "\n", 1);
+			}
+			free(ret);
 		}
 		memmove(buf, buf + s, pos - s);
 		pos -= s;
diff --git a/ui_curses.c b/ui_curses.c
index d451ce2..ccaaec2 100644
--- a/ui_curses.c
+++ b/ui_curses.c
@@ -440,7 +440,7 @@ static void print_tree(struct window *win, int row, struct iter *iter)
 	dump_print_buffer(tree_win_y + row + 1, tree_win_x);
 }
 
-static inline void fopt_set_str(struct format_option *fopt, const char *str)
+void fopt_set_str(struct format_option *fopt, const char *str)
 {
 	BUG_ON(fopt->type != FO_STR);
 	if (str) {
@@ -451,21 +451,21 @@ static inline void fopt_set_str(struct format_option *fopt, const char *str)
 	}
 }
 
-static inline void fopt_set_int(struct format_option *fopt, int value, int empty)
+void fopt_set_int(struct format_option *fopt, int value, int empty)
 {
 	BUG_ON(fopt->type != FO_INT);
 	fopt->fo_int = value;
 	fopt->empty = empty;
 }
 
-static inline void fopt_set_time(struct format_option *fopt, int value, int empty)
+void fopt_set_time(struct format_option *fopt, int value, int empty)
 {
 	BUG_ON(fopt->type != FO_TIME);
 	fopt->fo_time = value;
 	fopt->empty = empty;
 }
 
-static void fill_track_fopts_track_info(struct track_info *info)
+void fill_track_fopts_track_info(struct track_info *info, struct format_option *track_fopts_pointer)
 {
 	char *filename;
 	int num, disc;
@@ -479,25 +479,25 @@ static void fill_track_fopts_track_info(struct track_info *info)
 	disc = comments_get_int(info->comments, "discnumber");
 	num = comments_get_int(info->comments, "tracknumber");
 
-	fopt_set_str(&track_fopts[TF_ARTIST], comments_get_val(info->comments, "artist"));
-	fopt_set_str(&track_fopts[TF_ALBUM], comments_get_val(info->comments, "album"));
-	fopt_set_int(&track_fopts[TF_DISC], disc, disc == -1);
-	fopt_set_int(&track_fopts[TF_TRACK], num, num == -1);
-	fopt_set_str(&track_fopts[TF_TITLE], comments_get_val(info->comments, "title"));
-	fopt_set_str(&track_fopts[TF_YEAR], comments_get_val(info->comments, "date"));
-	fopt_set_str(&track_fopts[TF_GENRE], comments_get_val(info->comments, "genre"));
-	fopt_set_time(&track_fopts[TF_DURATION], info->duration, info->duration == -1);
-	fopt_set_str(&track_fopts[TF_PATHFILE], filename);
+	fopt_set_str(&track_fopts_pointer[TF_ARTIST], comments_get_val(info->comments, "artist"));
+	fopt_set_str(&track_fopts_pointer[TF_ALBUM], comments_get_val(info->comments, "album"));
+	fopt_set_int(&track_fopts_pointer[TF_DISC], disc, disc == -1);
+	fopt_set_int(&track_fopts_pointer[TF_TRACK], num, num == -1);
+	fopt_set_str(&track_fopts_pointer[TF_TITLE], comments_get_val(info->comments, "title"));
+	fopt_set_str(&track_fopts_pointer[TF_YEAR], comments_get_val(info->comments, "date"));
+	fopt_set_str(&track_fopts_pointer[TF_GENRE], comments_get_val(info->comments, "genre"));
+	fopt_set_time(&track_fopts_pointer[TF_DURATION], info->duration, info->duration == -1);
+	fopt_set_str(&track_fopts_pointer[TF_PATHFILE], filename);
 	if (is_url(info->filename)) {
-		fopt_set_str(&track_fopts[TF_FILE], filename);
+		fopt_set_str(&track_fopts_pointer[TF_FILE], filename);
 	} else {
 		const char *f;
 
 		f = strrchr(filename, '/');
 		if (f) {
-			fopt_set_str(&track_fopts[TF_FILE], f + 1);
+			fopt_set_str(&track_fopts_pointer[TF_FILE], f + 1);
 		} else {
-			fopt_set_str(&track_fopts[TF_FILE], filename);
+			fopt_set_str(&track_fopts_pointer[TF_FILE], filename);
 		}
 	}
 }
@@ -520,7 +520,7 @@ static void print_track(struct window *win, int row, struct iter *iter)
 		cursor_y = 1 + row;
 	}
 
-	fill_track_fopts_track_info(tree_track_info(track));
+	fill_track_fopts_track_info(tree_track_info(track), track_fopts);
 
 	if (track_info_has_tag(tree_track_info(track))) {
 		format_print(print_buffer, track_win_w, track_win_format, track_fopts);
@@ -557,7 +557,7 @@ static void print_editable(struct window *win, int row, struct iter *iter)
 
 	bkgdset(pairs[(active << 2) | (selected << 1) | current]);
 
-	fill_track_fopts_track_info(track->info);
+	fill_track_fopts_track_info(track->info, track_fopts);
 
 	if (track_info_has_tag(track->info)) {
 		format_print(print_buffer, COLS, list_win_format, track_fopts);
@@ -1127,7 +1127,7 @@ static void do_update_titleline(void)
 		int i, use_alt_format = 0;
 		char *wtitle;
 
-		fill_track_fopts_track_info(player_info.ti);
+		fill_track_fopts_track_info(player_info.ti, track_fopts);
 		if (is_url(player_info.ti->filename)) {
 			const char *title = get_stream_title();
 
diff --git a/ui_curses.h b/ui_curses.h
index 88762e5..7af3289 100644
--- a/ui_curses.h
+++ b/ui_curses.h
@@ -22,6 +22,8 @@
 
 #include "search.h"
 #include "compiler.h"
+#include "format_print.h"
+#include "track_info.h"
 
 enum ui_input_mode {
 	NORMAL_MODE,
@@ -38,6 +40,11 @@ extern struct searchable *searchable;
 extern char *lib_filename;
 extern char *pl_filename;
 
+void fopt_set_str(struct format_option *fopt, const char *str);
+void fopt_set_int(struct format_option *fopt, int value, int empty);
+void fopt_set_time(struct format_option *fopt, int value, int empty);
+void fill_track_fopts_track_info(struct track_info *info, struct format_option *track_fopts_pointer);
+
 void update_titleline(void);
 void update_statusline(void);
 void update_colors(void);
