client: Add readline support to empire client
Readline provides fancy command line editing such as <Arrow Up> for previous commands and CTRL+A to jump to the beginning of the line. This patch does not add any completion on <tab> key, a TODO, if you will. A new command line flag, -H, turns on saving the history to disk. This may have security implications on shared computers, as all commands are saved as-is. Thus "change re 1234" would be logged directly to the file. Signed-off-by: Martin Haukeli <martin.haukeli@gmail.com> Rebase on top of preparatory work, fix a few bugs, and tidy up: * Update the standalone client build, too. * Fix the Windows build. * Keep command line options sorted case-insensitively. * Error out when $HOME is unset and getpwuid() fails, just like we do for $LOGNAME. * Give @input_from_rl, @has_rl_input static linkage. * @has_rl_input is a flag, not a counter, set and test it accordingly. * Save all input in history, not just commands. Martin's attempt to recognize commands works only as long as the server sends prompts faster than the user sends input. Drop that part, and update commit message accordingly. * Fix recv_input() not to truncate value of strlen() to int, and to use memmove() for updating @input_from_rl in place. * Clean up whitespace in a few places. * Tweak commit message. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
parent
594cd20f76
commit
f1fc0df03d
9 changed files with 256 additions and 14 deletions
2
Make.mk
2
Make.mk
|
@ -432,5 +432,5 @@ $(srcdir)/src/client/config.h.in: src/client/configure.ac src/client/aclocal.m4
|
||||||
cd $(dir $@) && autoheader
|
cd $(dir $@) && autoheader
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(srcdir)/src/client/aclocal.m4: m4/ax_lib_socket_nsl.m4 m4/my_terminfo.m4 m4/my_windows_api.m4
|
$(srcdir)/src/client/aclocal.m4: m4/ax_lib_readline.m4 m4/ax_lib_socket_nsl.m4 m4/my_terminfo.m4 m4/my_windows_api.m4
|
||||||
cat $^ >$@
|
cat $^ >$@
|
||||||
|
|
|
@ -73,6 +73,7 @@ LIBS_util="$LIBS"
|
||||||
LIBS="$LIBS_SOCKETS $LIBS"
|
LIBS="$LIBS_SOCKETS $LIBS"
|
||||||
AX_LIB_SOCKET_NSL
|
AX_LIB_SOCKET_NSL
|
||||||
LIBS_server="$LIBS"
|
LIBS_server="$LIBS"
|
||||||
|
AX_LIB_READLINE
|
||||||
|
|
||||||
|
|
||||||
### Checks for header files
|
### Checks for header files
|
||||||
|
|
107
m4/ax_lib_readline.m4
Normal file
107
m4/ax_lib_readline.m4
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_lib_readline.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_LIB_READLINE
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Searches for a readline compatible library. If found, defines
|
||||||
|
# `HAVE_LIBREADLINE'. If the found library has the `add_history' function,
|
||||||
|
# sets also `HAVE_READLINE_HISTORY'. Also checks for the locations of the
|
||||||
|
# necessary include files and sets `HAVE_READLINE_H' or
|
||||||
|
# `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or
|
||||||
|
# 'HAVE_HISTORY_H' if the corresponding include files exists.
|
||||||
|
#
|
||||||
|
# The libraries that may be readline compatible are `libedit',
|
||||||
|
# `libeditline' and `libreadline'. Sometimes we need to link a termcap
|
||||||
|
# library for readline to work, this macro tests these cases too by trying
|
||||||
|
# to link with `libtermcap', `libcurses' or `libncurses' before giving up.
|
||||||
|
#
|
||||||
|
# Here is an example of how to use the information provided by this macro
|
||||||
|
# to perform the necessary includes or declarations in a C file:
|
||||||
|
#
|
||||||
|
# #ifdef HAVE_LIBREADLINE
|
||||||
|
# # if defined(HAVE_READLINE_READLINE_H)
|
||||||
|
# # include <readline/readline.h>
|
||||||
|
# # elif defined(HAVE_READLINE_H)
|
||||||
|
# # include <readline.h>
|
||||||
|
# # else /* !defined(HAVE_READLINE_H) */
|
||||||
|
# extern char *readline ();
|
||||||
|
# # endif /* !defined(HAVE_READLINE_H) */
|
||||||
|
# char *cmdline = NULL;
|
||||||
|
# #else /* !defined(HAVE_READLINE_READLINE_H) */
|
||||||
|
# /* no readline */
|
||||||
|
# #endif /* HAVE_LIBREADLINE */
|
||||||
|
#
|
||||||
|
# #ifdef HAVE_READLINE_HISTORY
|
||||||
|
# # if defined(HAVE_READLINE_HISTORY_H)
|
||||||
|
# # include <readline/history.h>
|
||||||
|
# # elif defined(HAVE_HISTORY_H)
|
||||||
|
# # include <history.h>
|
||||||
|
# # else /* !defined(HAVE_HISTORY_H) */
|
||||||
|
# extern void add_history ();
|
||||||
|
# extern int write_history ();
|
||||||
|
# extern int read_history ();
|
||||||
|
# # endif /* defined(HAVE_READLINE_HISTORY_H) */
|
||||||
|
# /* no history */
|
||||||
|
# #endif /* HAVE_READLINE_HISTORY */
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Ville Laurikari <vl@iki.fi>
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 6
|
||||||
|
|
||||||
|
AU_ALIAS([VL_LIB_READLINE], [AX_LIB_READLINE])
|
||||||
|
AC_DEFUN([AX_LIB_READLINE], [
|
||||||
|
AC_CACHE_CHECK([for a readline compatible library],
|
||||||
|
ax_cv_lib_readline, [
|
||||||
|
ORIG_LIBS="$LIBS"
|
||||||
|
for readline_lib in readline edit editline; do
|
||||||
|
for termcap_lib in "" termcap curses ncurses; do
|
||||||
|
if test -z "$termcap_lib"; then
|
||||||
|
TRY_LIB="-l$readline_lib"
|
||||||
|
else
|
||||||
|
TRY_LIB="-l$readline_lib -l$termcap_lib"
|
||||||
|
fi
|
||||||
|
LIBS="$ORIG_LIBS $TRY_LIB"
|
||||||
|
AC_TRY_LINK_FUNC(readline, ax_cv_lib_readline="$TRY_LIB")
|
||||||
|
if test -n "$ax_cv_lib_readline"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "$ax_cv_lib_readline"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -z "$ax_cv_lib_readline"; then
|
||||||
|
ax_cv_lib_readline="no"
|
||||||
|
fi
|
||||||
|
LIBS="$ORIG_LIBS"
|
||||||
|
])
|
||||||
|
|
||||||
|
if test "$ax_cv_lib_readline" != "no"; then
|
||||||
|
LIBS="$LIBS $ax_cv_lib_readline"
|
||||||
|
AC_DEFINE(HAVE_LIBREADLINE, 1,
|
||||||
|
[Define if you have a readline compatible library])
|
||||||
|
AC_CHECK_HEADERS(readline.h readline/readline.h)
|
||||||
|
AC_CACHE_CHECK([whether readline supports history],
|
||||||
|
ax_cv_lib_readline_history, [
|
||||||
|
ax_cv_lib_readline_history="no"
|
||||||
|
AC_TRY_LINK_FUNC(add_history, ax_cv_lib_readline_history="yes")
|
||||||
|
])
|
||||||
|
if test "$ax_cv_lib_readline_history" = "yes"; then
|
||||||
|
AC_DEFINE(HAVE_READLINE_HISTORY, 1,
|
||||||
|
[Define if your readline library has \`add_history'])
|
||||||
|
AC_CHECK_HEADERS(history.h readline/history.h)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])dnl
|
|
@ -39,6 +39,11 @@ Use UTF-8 rather than ASCII character set.
|
||||||
This requires server version 4.2.21 or later, and a terminal that
|
This requires server version 4.2.21 or later, and a terminal that
|
||||||
understands UTF-8.
|
understands UTF-8.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-H
|
||||||
|
Save readline command history to file.
|
||||||
|
.IP
|
||||||
|
Only available when compiled with readline and history support.
|
||||||
|
.TP
|
||||||
.B \-v
|
.B \-v
|
||||||
Print version information and exit.
|
Print version information and exit.
|
||||||
.TP
|
.TP
|
||||||
|
|
|
@ -58,6 +58,7 @@ if test "$Windows_API" = yes; then
|
||||||
AC_LIBOBJ([w32/w32io])
|
AC_LIBOBJ([w32/w32io])
|
||||||
AC_LIBOBJ([w32/w32sockets])
|
AC_LIBOBJ([w32/w32sockets])
|
||||||
fi
|
fi
|
||||||
|
AX_LIB_READLINE
|
||||||
|
|
||||||
|
|
||||||
### Checks for header files.
|
### Checks for header files.
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <shlobj.h>
|
||||||
#include "sys/socket.h"
|
#include "sys/socket.h"
|
||||||
#else
|
#else
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
|
|
||||||
struct passwd {
|
struct passwd {
|
||||||
char *pw_name;
|
char *pw_name;
|
||||||
|
char *pw_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct passwd *w32_getpw(void);
|
static struct passwd *w32_getpw(void);
|
||||||
|
@ -72,6 +74,9 @@ print_usage(char *program_name)
|
||||||
" -r Restricted mode, no redirections\n"
|
" -r Restricted mode, no redirections\n"
|
||||||
" -s [HOST:]PORT Specify server HOST and PORT\n"
|
" -s [HOST:]PORT Specify server HOST and PORT\n"
|
||||||
" -u Use UTF-8\n"
|
" -u Use UTF-8\n"
|
||||||
|
#ifdef HAVE_READLINE_HISTORY
|
||||||
|
" -H Save readline command history to file\n"
|
||||||
|
#endif /* HAVE_READLINE_HISTORY */
|
||||||
" -h display this help and exit\n"
|
" -h display this help and exit\n"
|
||||||
" -v display version information and exit\n",
|
" -v display version information and exit\n",
|
||||||
program_name);
|
program_name);
|
||||||
|
@ -82,6 +87,7 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
char *auxfname = NULL;
|
char *auxfname = NULL;
|
||||||
|
int use_history_file = 0;
|
||||||
int send_kill = 0;
|
int send_kill = 0;
|
||||||
char *host = NULL;
|
char *host = NULL;
|
||||||
char *port = NULL;
|
char *port = NULL;
|
||||||
|
@ -90,14 +96,20 @@ main(int argc, char **argv)
|
||||||
char *country;
|
char *country;
|
||||||
char *passwd;
|
char *passwd;
|
||||||
char *uname;
|
char *uname;
|
||||||
|
char *udir;
|
||||||
char *colon;
|
char *colon;
|
||||||
int sock;
|
int sock;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "2:krs:uhv")) != EOF) {
|
while ((opt = getopt(argc, argv, "2:krs:uHhv")) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case '2':
|
case '2':
|
||||||
auxfname = optarg;
|
auxfname = optarg;
|
||||||
break;
|
break;
|
||||||
|
#ifdef HAVE_READLINE_HISTORY
|
||||||
|
case 'H':
|
||||||
|
use_history_file = 1;
|
||||||
|
break;
|
||||||
|
#endif /* HAVE_READLINE_HISTORY */
|
||||||
case 'k':
|
case 'k':
|
||||||
send_kill = 1;
|
send_kill = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -146,7 +158,8 @@ main(int argc, char **argv)
|
||||||
if (!host)
|
if (!host)
|
||||||
host = empirehost;
|
host = empirehost;
|
||||||
uname = getenv("LOGNAME");
|
uname = getenv("LOGNAME");
|
||||||
if (uname == NULL) {
|
udir = getenv("HOME");
|
||||||
|
if (!uname || !udir) {
|
||||||
struct passwd *pwd;
|
struct passwd *pwd;
|
||||||
|
|
||||||
pwd = getpwuid(getuid());
|
pwd = getpwuid(getuid());
|
||||||
|
@ -154,7 +167,10 @@ main(int argc, char **argv)
|
||||||
fprintf(stderr, "You don't exist. Go away\n");
|
fprintf(stderr, "You don't exist. Go away\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if (!uname)
|
||||||
uname = pwd->pw_name;
|
uname = pwd->pw_name;
|
||||||
|
if (!udir)
|
||||||
|
udir = pwd->pw_dir;
|
||||||
}
|
}
|
||||||
if (*ap) {
|
if (*ap) {
|
||||||
fprintf(stderr, "%s: extra operand %s\n", argv[0], *ap);
|
fprintf(stderr, "%s: extra operand %s\n", argv[0], *ap);
|
||||||
|
@ -172,6 +188,12 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
sock = tcp_connect(host, port);
|
sock = tcp_connect(host, port);
|
||||||
|
|
||||||
|
if (use_history_file) {
|
||||||
|
history_file = malloc(1024);
|
||||||
|
strncpy(history_file, udir, 1000);
|
||||||
|
strcat(history_file, "/.empire.history");
|
||||||
|
}
|
||||||
|
|
||||||
if (!login(sock, uname, country, passwd, send_kill, utf8))
|
if (!login(sock, uname, country, passwd, send_kill, utf8))
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
|
@ -183,12 +205,13 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/*
|
/*
|
||||||
* Get Windows user name
|
* Get Windows user name and directory
|
||||||
*/
|
*/
|
||||||
static struct passwd *
|
static struct passwd *
|
||||||
w32_getpw(void)
|
w32_getpw(void)
|
||||||
{
|
{
|
||||||
static char unamebuf[128];
|
static char unamebuf[128];
|
||||||
|
static char udirbuf[MAX_PATH];
|
||||||
static struct passwd pwd;
|
static struct passwd pwd;
|
||||||
DWORD unamesize;
|
DWORD unamesize;
|
||||||
|
|
||||||
|
@ -199,6 +222,9 @@ w32_getpw(void)
|
||||||
pwd.pw_name = "nobody";
|
pwd.pw_name = "nobody";
|
||||||
} else
|
} else
|
||||||
pwd.pw_name = "nobody";
|
pwd.pw_name = "nobody";
|
||||||
|
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, udirbuf))
|
||||||
|
&& strlen(udirbuf) == 0)
|
||||||
|
pwd.pw_dir = udirbuf;
|
||||||
return &pwd;
|
return &pwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ extern char empireport[];
|
||||||
extern int eight_bit_clean;
|
extern int eight_bit_clean;
|
||||||
extern FILE *auxfp;
|
extern FILE *auxfp;
|
||||||
extern int restricted;
|
extern int restricted;
|
||||||
|
extern char *history_file;
|
||||||
|
|
||||||
#ifdef HAVE_CURSES_TERMINFO
|
#ifdef HAVE_CURSES_TERMINFO
|
||||||
void getsose(void);
|
void getsose(void);
|
||||||
|
|
|
@ -51,6 +51,28 @@
|
||||||
#include "ringbuf.h"
|
#include "ringbuf.h"
|
||||||
#include "secure.h"
|
#include "secure.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
# if defined(HAVE_READLINE_READLINE_H)
|
||||||
|
# include <readline/readline.h>
|
||||||
|
# elif defined(HAVE_READLINE_H)
|
||||||
|
# include <readline.h>
|
||||||
|
# else /* !defined(HAVE_READLINE_H) */
|
||||||
|
extern char *readline ();
|
||||||
|
# endif /* !defined(HAVE_READLINE_H) */
|
||||||
|
#endif /* HAVE_LIBREADLINE */
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE_HISTORY
|
||||||
|
# if defined(HAVE_READLINE_HISTORY_H)
|
||||||
|
# include <readline/history.h>
|
||||||
|
# elif defined(HAVE_HISTORY_H)
|
||||||
|
# include <history.h>
|
||||||
|
# else /* !defined(HAVE_HISTORY_H) */
|
||||||
|
extern void add_history ();
|
||||||
|
extern int write_history ();
|
||||||
|
extern int read_history ();
|
||||||
|
# endif /* !defined(HAVE_HISTORY_H) */
|
||||||
|
#endif /* HAVE_READLINE_HISTORY */
|
||||||
|
|
||||||
#define EOF_COOKIE "ctld\n"
|
#define EOF_COOKIE "ctld\n"
|
||||||
#define INTR_COOKIE "aborted\n"
|
#define INTR_COOKIE "aborted\n"
|
||||||
|
|
||||||
|
@ -414,6 +436,24 @@ recv_output(int sock)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *history_file = NULL;
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
static char *input_from_rl;
|
||||||
|
static int has_rl_input;
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_handler(char *line)
|
||||||
|
{
|
||||||
|
input_from_rl = line;
|
||||||
|
has_rl_input = 1;
|
||||||
|
rl_already_prompted = 1;
|
||||||
|
#ifdef HAVE_READLINE_HISTORY
|
||||||
|
if (line && *line)
|
||||||
|
add_history(line);
|
||||||
|
#endif /* HAVE_READLINE_HISTORY */
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LIBREADLINE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Receive player input from @fd into @inbuf.
|
* Receive player input from @fd into @inbuf.
|
||||||
* Return 1 on receipt of input, zero on EOF, -1 on error.
|
* Return 1 on receipt of input, zero on EOF, -1 on error.
|
||||||
|
@ -423,7 +463,32 @@ recv_input(int fd, struct ring *inbuf)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
int res = 1;
|
int res = 1;
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (fd == 0) {
|
||||||
|
if (!has_rl_input)
|
||||||
|
rl_callback_read_char();
|
||||||
|
if (!has_rl_input)
|
||||||
|
return 1;
|
||||||
|
if (input_from_rl) {
|
||||||
|
len = strlen(input_from_rl);
|
||||||
|
n = ring_space(inbuf);
|
||||||
|
assert(n);
|
||||||
|
if (len >= (size_t)n) {
|
||||||
|
ring_putm(inbuf, input_from_rl, n);
|
||||||
|
memmove(input_from_rl, input_from_rl + n, len - n + 1);
|
||||||
|
} else {
|
||||||
|
ring_putm(inbuf, input_from_rl, len);
|
||||||
|
ring_putc(inbuf, '\n');
|
||||||
|
free(input_from_rl);
|
||||||
|
has_rl_input = 0;
|
||||||
|
n = len + 1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
n = 0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
n = ring_from_file(inbuf, fd);
|
n = ring_from_file(inbuf, fd);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -490,6 +555,7 @@ play(int sock)
|
||||||
int send_eof; /* need to send EOF_COOKIE */
|
int send_eof; /* need to send EOF_COOKIE */
|
||||||
fd_set rdfd, wrfd;
|
fd_set rdfd, wrfd;
|
||||||
int n;
|
int n;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
@ -497,6 +563,14 @@ play(int sock)
|
||||||
sigaction(SIGINT, &sa, NULL);
|
sigaction(SIGINT, &sa, NULL);
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
#ifdef HAVE_READLINE_HISTORY
|
||||||
|
if (history_file)
|
||||||
|
read_history(history_file);
|
||||||
|
#endif /* HAVE_READLINE_HISTORY */
|
||||||
|
rl_bind_key('\t', rl_insert); /* Disable tab completion */
|
||||||
|
rl_callback_handler_install("", input_handler);
|
||||||
|
#endif /* HAVE_LIBREADLINE */
|
||||||
|
|
||||||
ring_init(&inbuf);
|
ring_init(&inbuf);
|
||||||
eof_fd0 = partial_line_sent = send_eof = send_intr = 0;
|
eof_fd0 = partial_line_sent = send_eof = send_intr = 0;
|
||||||
|
@ -525,7 +599,7 @@ play(int sock)
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
perror("select");
|
perror("select");
|
||||||
return -1;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,7 +618,6 @@ play(int sock)
|
||||||
input_fd = 0;
|
input_fd = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -571,7 +644,7 @@ play(int sock)
|
||||||
sigaction(SIGINT, &sa, NULL);
|
sigaction(SIGINT, &sa, NULL);
|
||||||
send_intr = 0;
|
send_intr = 0;
|
||||||
}
|
}
|
||||||
} else
|
} else if (ring_len(&inbuf) > 0)
|
||||||
partial_line_sent = ring_peek(&inbuf, -1) != '\n';
|
partial_line_sent = ring_peek(&inbuf, -1) != '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,7 +653,7 @@ play(int sock)
|
||||||
n = send_input(sock, &inbuf);
|
n = send_input(sock, &inbuf);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
perror("write socket");
|
perror("write socket");
|
||||||
return -1;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,10 +662,22 @@ play(int sock)
|
||||||
n = recv_output(sock);
|
n = recv_output(sock);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
perror("read socket");
|
perror("read socket");
|
||||||
return -1;
|
break;
|
||||||
}
|
}
|
||||||
if (n == 0)
|
if (n == 0) {
|
||||||
return 0;
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
#ifdef HAVE_READLINE_HISTORY
|
||||||
|
if (history_file)
|
||||||
|
write_history(history_file);
|
||||||
|
#endif /* HAVE_READLINE_HISTORY */
|
||||||
|
#endif /* HAVE_LIBREADLINE */
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
rl_callback_handler_remove();
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,14 @@
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "secure.h"
|
#include "secure.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
# if defined(HAVE_READLINE_READLINE_H)
|
||||||
|
# include <readline/readline.h>
|
||||||
|
# elif defined(HAVE_READLINE_H)
|
||||||
|
# include <readline.h>
|
||||||
|
# endif /* defined(HAVE_READLINE_H) */
|
||||||
|
#endif /* HAVE_LIBREADLINE */
|
||||||
|
|
||||||
int eight_bit_clean;
|
int eight_bit_clean;
|
||||||
FILE *auxfp;
|
FILE *auxfp;
|
||||||
int restricted;
|
int restricted;
|
||||||
|
@ -131,10 +139,18 @@ static void
|
||||||
prompt(int code, char *prompt, char *teles)
|
prompt(int code, char *prompt, char *teles)
|
||||||
{
|
{
|
||||||
char *nl;
|
char *nl;
|
||||||
|
char pr[1024];
|
||||||
|
|
||||||
nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
|
nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
|
||||||
printf("%s%s%s", nl, teles, prompt);
|
snprintf(pr, sizeof(pr), "%s%s", teles, prompt);
|
||||||
|
#ifdef HAVE_LIBREADLINE
|
||||||
|
rl_set_prompt(pr);
|
||||||
|
printf("%s", nl);
|
||||||
|
rl_forced_update_display();
|
||||||
|
#else /* !HAVE_LIBREADLINE */
|
||||||
|
printf("%s%s", nl, pr);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
#endif /* !HAVE_LIBREADLINE */
|
||||||
if (auxfp) {
|
if (auxfp) {
|
||||||
fprintf(auxfp, "%s%s%s", nl, teles, prompt);
|
fprintf(auxfp, "%s%s%s", nl, teles, prompt);
|
||||||
fflush(auxfp);
|
fflush(auxfp);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue