VPATH = @srcdir@
prog = empire$E
-obj = expect.$O host.$O ioqueue.$O ipglob.$O login.$O main.$O queue.$O \
-servcmd.$O serverio.$O tags.$O termio.$O termlib.$O version.$O
+obj = expect.$O host.$O ipglob.$O linebuf.$O login.$O main.$O play.$O \
+ringbuf.$O secure.$O servcmd.$O termlib.$O version.$O
all: $(prog)
# FIXME generate from .d
expect.$O: misc.h
host.$O: misc.h
-ioqueue.$O: misc.h queue.h ioqueue.h
+linebuf.$O: linebuf.h
login.$O: misc.h proto.h
-main.$O: misc.h proto.h queue.h ioqueue.h tags.h version.h
-queue.$O: misc.h queue.h
-servcmd.$O: misc.h proto.h queue.h ioqueue.h tags.h
-serverio.$O: misc.h queue.h ioqueue.h
-tags.$O: misc.h tags.h
-termio.$O: misc.h tags.h
+main.$O: misc.h version.h
+play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h
+ringbuf.$O: ringbuf.h
+secure.$O: ringbuf.h secure.h
+servcmd.$O: misc.h proto.h secure.h
termlib.$O: misc.h
version.$O: version.h
$(obj): config.h
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * ioqueue.c: Manage an i/o queue
- *
- * Known contributors to this file:
- * Steve McClure, 1998
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "ioqueue.h"
-#include "misc.h"
-#include "queue.h"
-
-static int ioqtobuf(struct ioqueue *ioq, char *buf, int cc);
-static void enqueuecc(struct ioqueue *ioq, char *buf, int cc);
-static int dequeuecc(struct ioqueue *ioq, int cc);
-
-
-void
-ioq_init(struct ioqueue *ioq, int bsize)
-{
- initque(&ioq->queue);
- ioq->cc = 0;
- ioq->bsize = bsize;
-}
-
-/*
- * Copy the specified number of characters into the buffer
- * provided, without actually dequeueing the data. Return
- * number of bytes actually found.
- */
-int
-ioq_peek(struct ioqueue *ioq, char *buf, int cc)
-{
- return ioqtobuf(ioq, buf, cc);
-}
-
-int
-ioq_dequeue(struct ioqueue *ioq, int cc)
-{
- if (dequeuecc(ioq, cc) != cc)
- return 0;
- return cc;
-}
-
-int
-ioq_read(struct ioqueue *ioq, char *buf, int cc)
-{
- int n;
-
- n = ioqtobuf(ioq, buf, cc);
- if (n > 0)
- dequeuecc(ioq, n);
- return n;
-}
-
-void
-ioq_write(struct ioqueue *ioq, char *buf, int cc)
-{
- enqueuecc(ioq, buf, cc);
-}
-
-int
-ioq_qsize(struct ioqueue *ioq)
-{
- return ioq->cc;
-}
-
-void
-ioq_drain(struct ioqueue *ioq)
-{
- struct io *io;
- struct qelem *qp;
-
- while ((qp = ioq->queue.q_forw) != &ioq->queue) {
- io = (struct io *)qp;
- free(io->data);
- (void)remque(&io->queue);
- (void)free(io);
- }
- ioq->cc = 0;
-}
-
-char *
-ioq_gets(struct ioqueue *ioq, char *buf, int cc, int *eol)
-{
- char *p;
- char *end;
- int nbytes;
-
- *eol = 0;
-
- cc--;
-
- nbytes = ioqtobuf(ioq, buf, cc);
- end = &buf[nbytes];
- for (p = buf; p < end && *p; p++) {
- if (*p == '\n') {
- *++p = '\0';
- *eol = 1;
- dequeuecc(ioq, p - buf);
- return buf;
- }
- }
- if (cc && (p - buf) == cc) {
- dequeuecc(ioq, cc);
- buf[cc] = '\0';
- return buf;
- }
- return NULL;
-}
-
-/*
- * all the rest are local to this module
- */
-
-
-/*
- * copy cc bytes from ioq to buf.
- * this routine doesn't free memory; this is
- * left for a higher level.
- */
-static int
-ioqtobuf(struct ioqueue *ioq, char *buf, int cc)
-{
- struct io *io;
- struct qelem *qp;
- char *offset;
- int nbytes;
- int nleft;
-
- nleft = cc;
- offset = buf;
- for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
- io = (struct io *)qp;
- if ((nbytes = io->nbytes - io->offset) < 0) {
- fprintf(stderr, "ioqtobuf: offset %d nbytes %d\n",
- io->offset, io->nbytes);
- continue;
- }
- if (nbytes > 0) {
- if (nleft < nbytes)
- nbytes = nleft;
- memcpy(offset, io->data + io->offset, nbytes);
- offset += nbytes;
- nleft -= nbytes;
- }
- }
- return offset - buf;
-}
-
-/*
- * append a buffer to the end of the ioq.
- */
-static void
-enqueuecc(struct ioqueue *ioq, char *buf, int cc)
-{
- struct io *io;
-
- io = malloc(sizeof(*io));
- io->nbytes = cc;
- io->offset = 0;
- io->data = buf;
- insque(&io->queue, ioq->queue.q_back);
- ioq->cc += cc;
-}
-
-/*
- * remove cc bytes from ioqueue ioq
- * free memory, dequeue io elements
- * which are no longer used.
- */
-static int
-dequeuecc(struct ioqueue *ioq, int cc)
-{
- struct io *io;
- struct qelem *qp;
- int nbytes;
- int there;
-
- nbytes = 0;
- while ((qp = ioq->queue.q_forw) != &ioq->queue) {
- io = (struct io *)qp;
- there = io->nbytes - io->offset;
- if (there < 0) {
- fprintf(stderr, "dequeuecc: nbytes %d, offset %d\n",
- io->nbytes, io->offset);
- continue;
- }
- if (cc > there) {
- cc -= there;
- nbytes += there;
- (void)remque(&io->queue);
- free(io->data);
- } else {
- io->offset += cc;
- nbytes += cc;
- break;
- }
- }
- ioq->cc -= nbytes;
- return nbytes;
-}
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * ioqueue.h: stores and frees data associated with a file descriptor.
- * uses writev to write, and read to read.
- *
- * Known contributors to this file:
- *
- */
-
-#ifndef IOQUEUE_H
-#define IOQUEUE_H
-
-#include "queue.h"
-
-struct ioqueue {
- struct qelem queue; /* queue fwd/back */
- int bsize; /* basic block size */
- int cc; /* character count */
-};
-
-struct io {
- struct qelem queue; /* list of ioqueue elements */
- int nbytes; /* number of data bytes present */
- int offset; /* offset into current entry */
- char *data; /* pointer to start */
-};
-
-void ioq_init(struct ioqueue *ioq, int bsize);
-int ioq_peek(struct ioqueue *ioq, char *buf, int cc);
-int ioq_dequeue(struct ioqueue *ioq, int cc);
-int ioq_read(struct ioqueue *ioq, char *buf, int cc);
-void ioq_write(struct ioqueue *ioq, char *buf, int cc);
-int ioq_qsize(struct ioqueue *ioq);
-void ioq_drain(struct ioqueue *ioq);
-char *ioq_gets(struct ioqueue *ioq, char *buf, int cc, int *eol);
-
-#endif
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * linebuf.c: Simple line buffer
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include "linebuf.h"
+
+/*
+ * Initialize empty line buffer.
+ * Not necessary if *LBUF is already zeroed.
+ */
+void
+lbuf_init(struct lbuf *lbuf)
+{
+ lbuf->len = lbuf->full = 0;
+}
+
+/*
+ * Return length of currently buffered line.
+ * This includes the newline if present.
+ */
+int
+lbuf_len(struct lbuf *lbuf)
+{
+ return lbuf->len;
+}
+
+/*
+ * Is LBUF full (i.e. we got the newline)?
+ */
+int
+lbuf_full(struct lbuf *lbuf)
+{
+ return lbuf->full;
+}
+
+/*
+ * Return a pointer to the currently buffered line.
+ * If you mess with the line in a way that changes the line length,
+ * better call lbuf_init() next.
+ */
+char *
+lbuf_line(struct lbuf *lbuf)
+{
+ assert(lbuf->len < sizeof(lbuf->line));
+ lbuf->line[lbuf->len] = 0;
+ return lbuf->line;
+}
+
+/*
+ * Append CH to the line buffered in LBUF.
+ * LBUF must not be full.
+ * If CH is a newline, the buffer is now full. Return the line
+ * length, including the newline.
+ * Else return 0 if there was space, and -1 if not.
+ */
+int
+lbuf_putc(struct lbuf *lbuf, char ch)
+{
+ assert(!lbuf->full);
+
+ if (ch == '\n') {
+ assert(lbuf->len + 1 < sizeof(lbuf->line));
+ lbuf->line[lbuf->len++] = ch;
+ lbuf->line[lbuf->len] = 0;
+ lbuf->full = 1;
+ return lbuf->len;
+ }
+
+ if (lbuf->len + 2 >= sizeof(lbuf->line))
+ return -1; /* truncating long line */
+
+ lbuf->line[lbuf->len++] = ch;
+ return 0;
+}
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * linebuf.h: Simple line buffer
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#ifndef LINEBUF_H
+#define LINEBUF_H
+
+#define LBUF_LEN_MAX 4096
+
+struct lbuf {
+ /* All members are private! */
+ unsigned len; /* strlen(line) */
+ int full; /* got a complete line, with newline? */
+ char line[LBUF_LEN_MAX]; /* buffered line, zero-terminated */
+};
+
+extern void lbuf_init(struct lbuf *);
+extern int lbuf_len(struct lbuf *);
+extern int lbuf_full(struct lbuf *);
+extern char *lbuf_line(struct lbuf *);
+extern int lbuf_putc(struct lbuf *, char);
+
+#endif
#include <config.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(_WIN32)
-#include <io.h>
-#else
#include <pwd.h>
-#include <sys/time.h>
-#include <sys/types.h>
+#include <stdlib.h>
#include <unistd.h>
-#endif
-
-#include "ioqueue.h"
#include "misc.h"
-#include "proto.h"
-#include "tags.h"
#include "version.h"
-#ifdef _WIN32
-HANDLE hStdIn;
-#endif
-
-#define RETRY 3
-
-int eight_bit_clean;
-int sock;
-
-static volatile sig_atomic_t interrupt;
-static void intr(int sig);
-static int handleintr(int);
-
static void
print_usage(char *program_name)
{
char *uname;
char *host;
char *port;
+ int sock;
#ifdef _WIN32
- WORD wVersionRequested;
- WSADATA WsaData;
- int err;
- fd_set readfds;
- struct timeval tm;
- DWORD stdinmode;
- SECURITY_ATTRIBUTES security;
- int bRedirected = 0;
char unamebuf[128];
-#else
- struct sigaction sa;
- fd_set mask;
- fd_set savemask;
- int retry = 0;
#endif
- struct ioqueue server;
- FILE *auxout_fp = NULL;
- int n;
#ifdef _WIN32
/*
* after each prompt is required.
*/
setvbuf(stdout, NULL, _IOLBF, 4096);
-#else
- FD_ZERO(&mask);
- FD_ZERO(&savemask);
#endif
while ((opt = getopt(argc, argv, "2:kuhv")) != EOF) {
}
getsose();
- if (auxfname && (auxout_fp = fopen(auxfname, "a")) == NULL) {
+ if (auxfname && (auxfp = fopen(auxfname, "a")) == NULL) {
fprintf(stderr, "Unable to open %s for append\n", auxfname);
exit(1);
}
#ifdef _WIN32
- wVersionRequested = MAKEWORD(2, 0);
- err = WSAStartup(wVersionRequested, &WsaData);
+ err = WSAStartup(MAKEWORD(2, 0), &WsaData);
if (err != 0) {
printf("WSAStartup Failed, error code %d\n", err);
exit(1);
if (!login(sock, uname, country, passwd, send_kill, utf8))
exit(1);
- ioq_init(&server, 2048);
- io_init();
-#ifndef _WIN32
- FD_ZERO(&mask);
- FD_SET(0, &savemask);
- FD_SET(sock, &savemask);
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = intr;
- sigaction(SIGINT, &sa, NULL);
- sa.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &sa, NULL);
- while (FD_ISSET(sock, &savemask)) {
- mask = savemask;
- n = select(sock + 1, &mask, NULL, NULL, NULL);
- if (interrupt) {
- if (!handleintr(sock))
- break;
- errno = 0;
- }
- if (n <= 0) {
- if (errno == EINTR) {
- perror("select");
- (void)close(sock);
- FD_CLR(sock, &savemask);
- }
- } else {
- if (FD_ISSET(0, &mask)) {
- if (!termio(0, sock, auxout_fp)) {
- if (retry++ >= RETRY) {
- FD_CLR(0, &savemask);
- }
- } else {
- retry = 0;
- }
- }
- if (FD_ISSET(sock, &mask)) {
- if (!serverio(sock, &server))
- FD_CLR(sock, &savemask);
- else
- servercmd(&server, auxout_fp);
- }
- }
- }
-#else /* _WIN32 */
- signal(SIGINT, intr);
-
- bRedirected = 0;
- tm.tv_sec = 0;
- tm.tv_usec = 1000;
-
- if (!isatty(fileno(stdin)))
- bRedirected = 1;
- else {
- security.nLength = sizeof(SECURITY_ATTRIBUTES);
- security.lpSecurityDescriptor = NULL;
- security.bInheritHandle = TRUE;
- hStdIn = CreateFile("CONIN$",
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &security, OPEN_EXISTING, (DWORD) NULL, NULL);
-
- if (hStdIn == INVALID_HANDLE_VALUE) {
- printf("Error getting hStdIn.\n");
- fflush(stdout);
- exit(-3);
- }
-
- err = GetConsoleMode(hStdIn, &stdinmode);
- if (!err) {
- printf("Error getting console mode.\n");
- fflush(stdout);
- exit(-4);
- } else {
- stdinmode |= ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
- err = SetConsoleMode(hStdIn, stdinmode);
- if (!err) {
- printf("Error setting console mode.\n");
- fflush(stdout);
- exit(-5);
- }
- }
- }
- while (1) {
- FD_ZERO(&readfds);
- FD_SET(sock, &readfds);
- n = select(sock + 1, &readfds, NULL, NULL, &tm);
- if (interrupt) {
- if (!handleintr(sock))
- break;
- errno = 0;
- }
- if (n < 0) {
- if (errno == EINTR) {
- errno = WSAGetLastError();
- perror("select");
- (void)closesocket(sock);
- break;
- }
- } else {
- if (bRedirected == 1) {
- if (!termio(0, sock, auxout_fp))
- bRedirected = -1;
- } else if (bRedirected == 0) {
- if (WaitForSingleObject(hStdIn, 10) != WAIT_TIMEOUT) {
- termio(-1, sock, auxout_fp);
- FlushConsoleInputBuffer(hStdIn);
- }
- }
- if (FD_ISSET(sock, &readfds)) {
- if (!serverio(sock, &server))
- break;
- else
- servercmd(&server, auxout_fp);
- }
- }
- }
- if (bRedirected == 0)
- CloseHandle(hStdIn);
-#endif /* _WIN32 */
- ioq_drain(&server);
-#ifdef _WIN32
- (void)closesocket(sock);
-#else
- (void)close(sock);
-#endif
- return 0; /* Shut the compiler up */
-}
-
-static void
-intr(int sig)
-{
- interrupt = 1;
-#ifdef _WIN32
- signal(SIGINT, intr);
-#endif
-}
+ if (play(sock) < 0)
+ exit(1);
-static int
-handleintr(int s)
-{
- if (interrupt) {
- /* tacky, but it works */
-#if !defined(_WIN32)
- if (write(s, "\naborted\n", 1 + 7 + 1) <= 0)
-#else
- if (send(s, "\naborted\n", 1 + 7 + 1, 0) <= 0)
-#endif
- return 0;
- interrupt = 0;
- }
- return 1;
+ return 0;
}
#include <windows.h>
#endif
-struct ioqueue;
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
extern char empirehost[];
extern char empireport[];
extern int eight_bit_clean;
-extern int sock;
+extern int input_fd;
+extern FILE *auxfp;
extern char *SO;
extern char *SE;
-#ifdef _WIN32
-extern HANDLE hStdIn;
-#endif
-
#ifdef _WIN32
#define getsose() ((void)0)
#define putso() ((void)0)
int expect(int s, int match, char *buf);
int tcp_connect(char *, char *);
int login(int s, char *uname, char *cname, char *cpass, int kill_proc, int);
+int play(int);
void sendcmd(int s, char *cmd, char *arg);
-void servercmd(struct ioqueue *ioq, FILE *auxfi);
-int serverio(int s, struct ioqueue *ioq);
-int termio(int fd, int sock, FILE *auxfi);
+void servercmd(int, char *, int);
+void outch(char);
#endif
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * play.c: Playing the game
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "linebuf.h"
+#include "misc.h"
+#include "proto.h"
+#include "ringbuf.h"
+#include "secure.h"
+
+#define EOF_COOKIE "ctld\n"
+#define INTR_COOKIE "\naborted\n"
+
+int input_fd;
+static volatile sig_atomic_t send_intr; /* need to send INTR_COOKIE */
+
+/*
+ * Receive and process server output from SOCK.
+ * Return number of characters received on success, -1 on error.
+ */
+static int
+recv_output(int sock)
+{
+ /*
+ * Read a chunk of server output and feed its characters into a
+ * simple state machine.
+ * Initial state is SCANNING_ID.
+ * In state SCANNING_ID, buffer the character. If it's a space,
+ * decode the id that has been buffered, and enter state BUFFERING
+ * or COPYING depending on its value.
+ * In state BUFFERING, buffer the character. If it's newline,
+ * pass id and buffered text to servercmd(), then enter state
+ * SCANNING_ID.
+ * In state COPYING, pass the character to outch(). If it's
+ * newline, enter state SCANNING_ID.
+ */
+ static enum {
+ SCANNING_ID, BUFFERING, COPYING
+ } state = SCANNING_ID;
+ static int id;
+ static struct lbuf lbuf;
+ char buf[4096];
+ ssize_t n;
+ int i, ch, len;
+ char *line, *end;
+
+ n = read(sock, buf, sizeof(buf));
+ if (n < 0)
+ return -1;
+
+ for (i = 0; i < n; i++) {
+ ch = buf[i];
+ switch (state) {
+ case SCANNING_ID:
+ if (ch == '\n') {
+ /* FIXME gripe unexpected! */
+ lbuf_init(&lbuf);
+ break;
+ }
+ if (ch != ' ') {
+ lbuf_putc(&lbuf, ch);
+ break;
+ }
+ line = lbuf_line(&lbuf);
+ id = strtol(line, &end, 16);
+ if (end == line || *end) {
+ /* FIXME gripe bad id */
+ id = -1;
+ }
+ lbuf_init(&lbuf);
+
+ switch (id) {
+ case C_PROMPT:
+ case C_FLUSH:
+ case C_EXECUTE:
+ case C_EXIT:
+ case C_FLASH:
+ case C_INFORM:
+ case C_PIPE:
+ case C_REDIR:
+ state = BUFFERING;
+ break;
+ default:
+ /* unknown or unexpected id, treat like C_DATA */
+ case C_DATA:
+ state = COPYING;
+ break;
+ }
+ break;
+
+ case BUFFERING:
+ len = lbuf_putc(&lbuf, ch);
+ if (len) {
+ line = lbuf_line(&lbuf);
+ servercmd(id, line, len);
+ lbuf_init(&lbuf);
+ state = SCANNING_ID;
+ }
+ break;
+
+ case COPYING:
+ outch(ch);
+ if (ch == '\n')
+ state = SCANNING_ID;
+ }
+ }
+
+ return n;
+}
+
+/*
+ * Receive command input from FD into INBUF.
+ * Return 1 on receipt of input, zero on EOF, -1 on error.
+ */
+static int
+recv_input(int fd, struct ring *inbuf)
+{
+ static struct lbuf cmdbuf;
+ int n, i, ch;
+ char *line;
+ int res = 1;
+
+ n = ring_from_file(inbuf, fd);
+ if (n < 0)
+ return -1;
+ if (n == 0) {
+ /* EOF on input */
+ if (lbuf_len(&cmdbuf)) {
+ /* incomplete line */
+ ring_putc(inbuf, '\n');
+ n++;
+ }
+ /*
+ * Can't put EOF cookie into INBUF here, it may not fit.
+ * Leave it to caller.
+ */
+ res = 0;
+ }
+
+ /* copy input to AUXFP etc. */
+ for (i = -n; i < 0; i++) {
+ ch = ring_peek(inbuf, i);
+ assert(ch != EOF);
+ if (lbuf_putc(&cmdbuf, ch)) {
+ line = lbuf_line(&cmdbuf);
+ if (auxfp)
+ fputs(line, auxfp);
+ save_input(line);
+ lbuf_init(&cmdbuf);
+ }
+ }
+
+ return res;
+}
+
+static void
+intr(int sig)
+{
+ send_intr = 1;
+#ifdef _WIN32
+ signal(SIGINT, intr);
+#endif
+}
+
+/*
+ * Play on SOCK.
+ * The session must be in the playing phase.
+ * Return 0 when the session ended, -1 on error.
+ */
+int
+play(int sock)
+{
+ /*
+ * Player input flows from INPUT_FD through recv_input() into ring
+ * buffer INBUF, which drains into SOCK. This must not block.
+ * Server output flows from SOCK into recv_output(). Reading SOCK
+ * must not block.
+ */
+ struct sigaction sa;
+ struct ring inbuf; /* input buffer, draining to SOCK */
+ int eof_fd0; /* read fd 0 hit EOF? */
+ int send_eof; /* need to send EOF_COOKIE */
+ fd_set rdfd, wrfd;
+ int n;
+
+ sa.sa_flags = 0;
+ sa.sa_handler = intr;
+ sigaction(SIGINT, &sa, NULL);
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sa, NULL);
+
+ ring_init(&inbuf);
+ eof_fd0 = send_eof = 0;
+
+ for (;;) {
+ FD_ZERO(&rdfd);
+ FD_ZERO(&wrfd);
+
+ /*
+ * Want to read player input only when we don't need to send
+ * cookies, and we haven't hit EOF on fd 0, and INBUF can
+ * accept some.
+ */
+ if (!send_intr && !send_eof && !eof_fd0 && ring_space(&inbuf))
+ FD_SET(input_fd, &rdfd);
+ /* Want to send player input only when we have something */
+ if (send_intr || send_eof || ring_len(&inbuf))
+ FD_SET(sock, &wrfd);
+ /* Always want to read server output */
+ FD_SET(sock, &rdfd);
+
+ n = select(MAX(input_fd, sock) + 1, &rdfd, &wrfd, NULL, NULL);
+ if (n < 0) {
+ if (errno != EINTR) {
+ perror("select");
+ return -1;
+ }
+ }
+
+ if (send_eof
+ && ring_putm(&inbuf, EOF_COOKIE, sizeof(EOF_COOKIE) - 1) >= 0)
+ send_eof = 0;
+ if (send_intr
+ && ring_putm(&inbuf, INTR_COOKIE, sizeof(INTR_COOKIE) - 1) >= 0)
+ send_intr = 0;
+
+ if (n < 0)
+ continue;
+
+ /* read player input */
+ if (FD_ISSET(input_fd, &rdfd)) {
+ n = recv_input(input_fd, &inbuf);
+ if (n < 0) {
+ perror("read stdin"); /* FIXME stdin misleading, could be execing */
+ return -1;
+ }
+ if (n == 0) {
+ /* EOF on input */
+ send_eof = 1;
+ if (input_fd) {
+ /* execute done, switch back to fd 0 */
+ input_fd = 0;
+ } else {
+ /* stop reading input, drain socket ring buffers */
+ eof_fd0 = 1;
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGINT, &sa, NULL);
+ }
+ }
+ }
+
+ /* send it to the server */
+ if (FD_ISSET(sock, &wrfd)) {
+ n = ring_to_file(&inbuf, sock);
+ if (n < 0) {
+ perror("write socket");
+ return -1;
+ }
+ }
+
+ /* read server output and print it */
+ if (FD_ISSET(sock, &rdfd)) {
+ n = recv_output(sock);
+ if (n < 0) {
+ perror("read socket");
+ return -1;
+ }
+ if (n == 0)
+ return 0;
+ if (input_fd < 0) {
+ /* execute failed */
+ input_fd = 0;
+ send_eof = 1;
+ }
+ }
+ }
+}
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * queue.c: implementation of various queuing routines
- *
- * Known contributors to this file:
- * Steve McClure, 1998
- */
-
-#include <config.h>
-
-#include "queue.h"
-
-void
-insque(struct qelem *p, struct qelem *q)
-{
- p->q_forw = q->q_forw;
- p->q_back = q;
- q->q_forw->q_back = p;
- q->q_forw = p;
-}
-
-void
-remque(struct qelem *p)
-{
- p->q_back->q_forw = p->q_forw;
- p->q_forw->q_back = p->q_back;
-}
-
-void
-initque(struct qelem *p)
-{
- p->q_forw = p;
- p->q_back = p;
-}
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * queue.h: generic vax-like doubly linked list queues.
- *
- * Known contributors to this file:
- *
- */
-
-#ifndef QUEUE_H
-#define QUEUE_H
-
-#define QEMPTY(p) ((p)->q_forw == (p))
-
-struct qelem {
- struct qelem *q_forw;
- struct qelem *q_back;
-};
-
-void insque(struct qelem *p, struct qelem *q);
-void remque(struct qelem *p);
-void initque(struct qelem *p);
-
-#endif
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * ringbuf.c: Simple ring buffer
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include "ringbuf.h"
+
+/*
+ * Initialize empty ring buffer.
+ * Not necessary if *R is already zeroed.
+ */
+void
+ring_init(struct ring *r)
+{
+ r->cons = r->prod = 0;
+}
+
+/*
+ * Return number of bytes held in ring buffer.
+ */
+int
+ring_len(struct ring *r)
+{
+ assert(r->prod - r->cons <= RING_SIZE);
+ return r->prod - r->cons;
+}
+
+/*
+ * Return how much space is left in ring buffer.
+ */
+int
+ring_space(struct ring *r)
+{
+ return RING_SIZE - (r->prod - r->cons);
+}
+
+/*
+ * Peek at ring buffer contents.
+ * N must be between -RING_SIZE-1 and RING_SIZE.
+ * If N>=0, peek at the (N+1)-th byte to be gotten.
+ * If N<0, peek at the -N-th byte that has been put in.
+ * Return the byte as unsigned char coverted to int, or EOF if there
+ * aren't that many bytes in the ring buffer.
+ */
+int
+ring_peek(struct ring *r, int n)
+{
+ unsigned idx;
+
+ assert(-RING_SIZE - 1 <= n && n <= RING_SIZE);
+
+ idx = n >= 0 ? r->cons + n : r->prod - -n;
+ if (idx < r->cons && idx >= r->prod)
+ return EOF;
+ return r->buf[idx % RING_SIZE];
+}
+
+/*
+ * Get and remove the oldest byte from the ring buffer.
+ * Return it as unsigned char coverted to int, or EOF if the buffer was
+ * empty.
+ */
+int
+ring_getc(struct ring *r)
+{
+ if (r->cons == r->prod)
+ return EOF;
+ return r->buf[r->cons++ % RING_SIZE];
+}
+
+/*
+ * Attempt to put byte C into the ring buffer.
+ * Return EOF when the buffer is full, else C.
+ */
+int
+ring_putc(struct ring *r, unsigned char c)
+{
+ if (r->prod - r->cons == RING_SIZE)
+ return EOF;
+ return r->buf[r->prod++ % RING_SIZE] = c;
+}
+
+/*
+ * Attempt to put SZ bytes from BUF into the ring buffer.
+ * Return space left in ring buffer when it fits, else don't change
+ * the ring buffer and return how much space is missing.
+ */
+int
+ring_putm(struct ring *r, void *buf, size_t sz)
+{
+ char *p = buf;
+ int left = ring_space(r) - sz;
+ int res;
+ size_t i;
+
+ if (left >= 0) {
+ res = 0;
+ for (i = 0; i < sz; i++)
+ res = ring_putc(r, p[i]);
+ assert(res != EOF);
+ }
+
+ return left;
+}
+
+/*
+ * Discard the N oldest bytes from the ring buffer.
+ * It must hold at least that many.
+ */
+void
+ring_discard(struct ring *r, int n)
+{
+ assert(n <= ring_len(r));
+ r->cons += n;
+}
+
+/*
+ * Search the ring buffer for zero-terminated string S.
+ * If found, return a non-negative value referring to the beginning of
+ * S in the buffer when passed to ring_peek(). Else return -1.
+ */
+int
+ring_search(struct ring *r, char *s)
+{
+ size_t len = strlen(s);
+ size_t i, j;
+
+ for (i = r->cons; i + len <= r->prod; i++) {
+ for (j = 0; j < len && s[j] == r->buf[(i + j) % RING_SIZE]; j++) ;
+ if (!s[j])
+ return i - r->cons;
+ }
+ return -1;
+}
+
+/*
+ * Fill ring buffer from file referred by file descriptor FD.
+ * If ring buffer is already full, do nothing and return 0.
+ * Else attempt to read as many bytes as space permits, with readv(),
+ * and return its value.
+ */
+int
+ring_from_file(struct ring *r, int fd)
+{
+ unsigned cons = r->cons % RING_SIZE;
+ unsigned prod = r->prod % RING_SIZE;
+ struct iovec iov[2];
+ int cnt;
+ ssize_t res;
+
+ if (r->prod == r->cons + RING_SIZE)
+ return 0;
+
+ iov[0].iov_base = r->buf + prod;
+ if (cons <= prod) {
+ /* r->buf[prod..] */
+ iov[0].iov_len = RING_SIZE - prod;
+ /* r->buf[..cons-1] */
+ iov[1].iov_base = r->buf;
+ iov[1].iov_len = cons;
+ cnt = 2;
+ } else {
+ /* r->buf[prod..cons-1] */
+ iov[0].iov_len = cons - prod;
+ cnt = 1;
+ }
+ res = readv(fd, iov, cnt);
+ if (res < 0)
+ return res;
+ r->prod += res;
+ return res;
+}
+
+/*
+ * Drain ring buffer to file referred by file descriptor FD.
+ * If ring buffer is already empty, do nothing and return 0.
+ * Else attempt to write complete contents with writev(), and return
+ * its value.
+ */
+int
+ring_to_file(struct ring *r, int fd)
+{
+ unsigned cons = r->cons % RING_SIZE;
+ unsigned prod = r->prod % RING_SIZE;
+ struct iovec iov[2];
+ int cnt;
+ ssize_t res;
+
+ if (r->cons == r->prod)
+ return 0;
+
+ iov[0].iov_base = r->buf + cons;
+ if (prod <= cons) {
+ /* r->buf[cons..] */
+ iov[0].iov_len = RING_SIZE - cons;
+ /* r->buf[..prod-1] */
+ iov[1].iov_base = r->buf;
+ iov[1].iov_len = prod;
+ cnt = 2;
+ } else {
+ /* r->buf[cons..prod-1] */
+ iov[0].iov_len = prod - cons;
+ cnt = 1;
+ }
+ res = writev(fd, iov, cnt);
+ if (res < 0)
+ return res;
+ r->cons += res;
+ return res;
+}
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * ringbuf.h: Simple ring buffer
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#ifndef RINGBUF_H
+#define RINGBUF_H
+
+#include <stddef.h>
+
+#define RING_SIZE 4096
+
+/* Ring buffer, consumer reads, producer writes */
+struct ring {
+ /* All members are private! */
+ /*
+ * Consumer reads from buf[cons % RING_SIZE], incrementing cons
+ * Produces writes to buf[prod % RING_SIZE], incrementing prod
+ * prod == cons: empty
+ * prod == cons + RING_SIZE: full
+ * invariant: prod - cons <= RING_SIZE
+ */
+ unsigned cons, prod;
+ unsigned char buf[RING_SIZE];
+};
+
+extern void ring_init(struct ring *);
+extern int ring_len(struct ring *);
+extern int ring_space(struct ring *);
+extern int ring_peek(struct ring *, int);
+extern int ring_getc(struct ring *);
+extern int ring_putc(struct ring *, unsigned char);
+extern int ring_putm(struct ring *, void *, size_t);
+extern void ring_discard(struct ring *, int);
+extern int ring_search(struct ring *, char *);
+extern int ring_from_file(struct ring *, int fd);
+extern int ring_to_file(struct ring *, int fd);
+
+#endif
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * secure.c: Check redir etc. to protect against tampering deity
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include "ringbuf.h"
+#include "secure.h"
+
+struct ring recent_input;
+
+void
+save_input(char *inp)
+{
+ size_t len = strlen(inp);
+ int left;
+
+ left = ring_putm(&recent_input, inp, len);
+ if (left < 0) {
+ ring_discard(&recent_input, ring_search(&recent_input, "\n"));
+ ring_putm(&recent_input, inp, len);
+ }
+}
+
+int
+seen_input(char *tail)
+{
+ int dist = ring_search(&recent_input, tail);
+
+ if (dist < 0)
+ return 0;
+
+ ring_discard(&recent_input, dist + strlen(tail));
+ return 1;
+}
--- /dev/null
+/*
+ * Empire - A multi-player, client/server Internet based war game.
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ---
+ *
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
+ *
+ * ---
+ *
+ * secure.h: Check redir etc. to protect against tampering deity
+ *
+ * Known contributors to this file:
+ * Markus Armbruster, 2007
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+extern void clear_recent_input(void);
+extern void save_input(char *);
+extern int seen_input(char *);
+
+#endif
#include <config.h>
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-#include "ioqueue.h"
#include "misc.h"
#include "proto.h"
-#include "tags.h"
+#include "secure.h"
+
+int eight_bit_clean;
+FILE *auxfp;
-static char num_teles[64];
-static char the_prompt[1024];
-static int mode;
-static int nbtu;
-static int nmin;
static FILE *redir_fp;
static FILE *pipe_fp;
-static void prompt(FILE *auxfi);
+static void prompt(int, char *, char *);
static void doredir(char *p);
static void dopipe(char *p);
-static void doexecute(char *p, FILE *auxfi);
-static void output(int code, char *buf, FILE *auxfi);
-static void screen(char *buf);
+static void doexecute(char *p);
void
-servercmd(struct ioqueue *ioq, FILE *auxfi)
+servercmd(int code, char *arg, int len)
{
- char buf[1024];
- char *p;
- static int code = -1;
- int eol;
+ static int nmin, nbtu;
+ static char the_prompt[1024];
+ static char teles[64];
- while (ioq_gets(ioq, buf, sizeof(buf), &eol)) {
- p = buf;
- if (code == -1) {
- if (isalpha(*buf))
- code = 10 + (*buf - 'a');
- else
- code = *buf - '0';
- while (*p && !isspace(*p))
- p++;
- *p++ = 0;
+ switch (code) {
+ case C_PROMPT:
+ if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
+ fprintf(stderr, "prompt: bad server prompt %s\n", arg);
}
- /*
- * FIXME
- * C_REDIR, C_PIPE, and C_EXECUTE will not
- * work with filename longer than one buffer
- */
- switch (code) {
- case C_PROMPT:
- if (sscanf(p, "%d %d", &nmin, &nbtu) != 2) {
- fprintf(stderr, "prompt: bad server prompt %s\n", p);
+ snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
+ nmin, nbtu);
+ prompt(code, the_prompt, teles);
+ break;
+ case C_FLUSH:
+ snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
+ prompt(code, the_prompt, teles);
+ break;
+ case C_EXECUTE:
+ doexecute(arg);
+ break;
+ case C_EXIT:
+ printf("Exit: %s", arg);
+ if (auxfp)
+ fprintf(auxfp, "Exit: %s", arg);
+ break;
+ case C_FLASH:
+ printf("\n%s", arg);
+ if (auxfp)
+ fprintf(auxfp, "\n%s", arg);
+ break;
+ case C_INFORM:
+ if (*arg) {
+ snprintf(teles, sizeof(teles), "(%.*s )", len -1, arg);
+ if (!redir_fp && !pipe_fp) {
+ putchar('\07');
+ prompt(code, the_prompt, teles);
}
- mode = code;
- sprintf(the_prompt, "[%d:%d] Command : ", nmin, nbtu);
- prompt(auxfi);
- break;
- case C_REDIR:
- if (eol)
- p[strlen(p) - 1] = '\0';
- doredir(p);
- break;
- case C_PIPE:
- if (eol)
- p[strlen(p) - 1] = '\0';
- dopipe(p);
- break;
- case C_FLUSH:
- mode = code;
- if (eol)
- p[strlen(p) - 1] = '\0';
- sprintf(the_prompt, "%s", p);
- prompt(auxfi);
- break;
- case C_EXECUTE:
- if (eol)
- p[strlen(p) - 1] = '\0';
- doexecute(p, auxfi);
- break;
- case C_INFORM:
- if (eol)
- p[strlen(p) - 1] = '\0';
- if (*p) {
- p[strlen(p) - 1] = '\0';
- sprintf(num_teles, "(%s) ", p + 1);
- if (!redir_fp && !pipe_fp) {
- putchar('\07');
- prompt(NULL);
- }
- } else
- *num_teles = '\0';
- break;
- default:
- output(code, p, auxfi);
- break;
- }
- if (eol)
- code = -1;
+ } else
+ teles[0] = 0;
+ break;
+ case C_PIPE:
+ dopipe(arg);
+ break;
+ case C_REDIR:
+ doredir(arg);
+ break;
+ default:
+ assert(0);
+ break;
}
}
static void
-prompt(FILE *auxfi)
+prompt(int code, char *prompt, char *teles)
{
- if (mode == C_PROMPT) {
+ char *nl;
+
+ if (code == C_PROMPT) {
if (redir_fp) {
(void)fclose(redir_fp);
redir_fp = NULL;
pipe_fp = NULL;
}
}
- if (mode == C_PROMPT)
- printf("\n");
- printf("%s%s", num_teles, the_prompt);
- (void)fflush(stdout);
- if (auxfi) {
- fprintf(auxfi, "\n%s%s", num_teles, the_prompt);
- (void)fflush(auxfi);
+ nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
+ printf("%s%s%s", nl, teles, prompt);
+ fflush(stdout);
+ if (auxfp) {
+ fprintf(auxfp, "%s%s%s", nl, teles, prompt);
+ fflush(auxfp);
}
}
static void
doredir(char *p)
{
- char *tag;
int mode;
int fd;
redir_fp = NULL;
}
+ if (!seen_input(p)) {
+ fprintf(stderr, "WARNING! Server attempted to redirect %s\n",
+ p);
+ return;
+ }
+
if (*p++ != '>') {
fprintf(stderr, "WARNING! Weird redirection %s", p);
return;
} else
mode |= O_EXCL;
- tag = gettag(p);
p = fname(p);
- if (tag == NULL) {
- fprintf(stderr, "WARNING! Server redirected output to file %s\n",
- p);
- return;
- }
- free(tag);
-
if (*p == 0) {
fprintf(stderr, "Redirection lacks a file name\n");
return;
}
+
fd = open(p, mode, 0600);
redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
if (!redir_fp) {
static void
dopipe(char *p)
{
- char *tag;
-
- if (*p++ != '|') {
- fprintf(stderr, "WARNING! Weird pipe %s", p);
+ if (!seen_input(p)) {
+ fprintf(stderr, "WARNING! Server attempted to pipe %s", p);
return;
}
- tag = gettag(p);
- if (tag == NULL) {
- fprintf(stderr, "WARNING! Server attempted to run: %s\n", p);
+ if (*p++ != '|') {
+ fprintf(stderr, "WARNING! Weird pipe %s", p);
return;
}
- free(tag);
for (; *p && isspace(*p); p++) ;
if (*p == 0) {
fprintf(stderr, "Redirection lacks a command\n");
return;
}
+
if ((pipe_fp = popen(p, "w")) == NULL) {
fprintf(stderr, "Can't redirect to pipe %s: %s\n",
p, strerror(errno));
}
static void
-doexecute(char *p, FILE *auxfi)
+doexecute(char *p)
{
- int fd;
- char *tag;
-
- tag = gettag(p);
- if (tag == NULL) {
+ if (!seen_input(p)) {
fprintf(stderr,
- "WARNING! Server attempted unauthorized read of file %s\n",
+ "WARNING! Server attempted to read file %s",
p);
return;
}
- free(tag);
p = fname(p);
if (*p == 0) {
fprintf(stderr, "Need a file to execute\n");
return;
}
- if ((fd = open(p, O_RDONLY, 0)) < 0) {
+
+ if ((input_fd = open(p, O_RDONLY)) < 0) {
fprintf(stderr, "Can't open execute file %s: %s\n",
p, strerror(errno));
return;
}
- /* copies 4k at a time to the socket */
- while (termio(fd, sock, auxfi)) /*do copy */
- ;
- /*
- * Some platforms don't send the eof (cntl-D) at the end of
- * copying a file. If emp_client hangs at the end of an
- * execute, include the following line and notify wolfpack
- * of the platform you are using.
- * sendeof(sock);
- */
- close(fd);
}
-static void
-output(int code, char *buf, FILE *auxfi)
+void
+outch(char c)
{
- switch (code) {
- case C_NOECHO:
- /* not implemented; server doesn't send it */
- break;
- case C_ABORT:
- printf("Aborted\n");
- if (auxfi)
- fprintf(auxfi, "Aborted\n");
- break;
- case C_CMDERR:
- case C_BADCMD:
- printf("Error; ");
- if (auxfi)
- fprintf(auxfi, "Error; ");
- break;
- case C_EXIT:
- printf("Exit: ");
- if (auxfi)
- fprintf(auxfi, "Exit: ");
- break;
- case C_FLASH:
- printf("\n");
- break;
- default:
- break;
- }
- if (auxfi) {
- fprintf(auxfi, "%s", buf);
- }
-
+ if (auxfp)
+ putc(c, auxfp);
if (redir_fp)
- fprintf(redir_fp, "%s", buf);
+ putc(c, redir_fp);
else if (pipe_fp)
- fprintf(pipe_fp, "%s", buf);
- else {
- screen(buf);
- }
-}
-
-static void
-screen(char *buf)
-{
- char c;
-
- while ((c = *buf++)) {
- if (eight_bit_clean) {
- if (c == 14)
- putso();
- else if (c == 15)
- putse();
- else
- putchar(c);
- } else if (c & 0x80) {
+ putc(c, pipe_fp);
+ else if (eight_bit_clean) {
+ if (c == 14)
putso();
- putchar(c & 0x7f);
+ else if (c == 15)
putse();
- } else
+ else
putchar(c);
- }
+ } else if (c & 0x80) {
+ putso();
+ putchar(c & 0x7f);
+ putse();
+ } else
+ putchar(c);
}
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * serverio.c: Handle input from server
- *
- * Known contributors to this file:
- * Steve McClure, 1998
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#if !defined(_WIN32)
-#include <unistd.h>
-#endif
-#include "misc.h"
-#include "ioqueue.h"
-
-int
-serverio(int s, struct ioqueue *ioq)
-{
- char *buf;
- int n;
-
- if ((buf = malloc(ioq->bsize)) == NULL) {
- fprintf(stderr, "malloc server i/o failed\n");
- return 0;
- }
-#ifdef _WIN32
- n = recv(s, buf, ioq->bsize, 0);
-#else
- n = read(s, buf, ioq->bsize);
-#endif
- if (n < 0) {
-#ifdef _WIN32
- errno = WSAGetLastError();
-#endif
- perror("server i/o read");
- free(buf);
- return 0;
- }
- if (n == 0) {
- fprintf(stderr, "Server EOF\n");
-#ifdef WIN32
- (void)closesocket(s);
-#else
- (void)close(s);
-#endif
- return 0;
- }
- if (n != ioq->bsize)
- buf = realloc(buf, n);
- ioq_write(ioq, buf, n);
- return 1;
-}
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * tags.c: save redir, execute and pipe info to protect against tampering
- * by the deity.
- *
- * Known contributors to this file:
- * John Yockey, 1998
- */
-
-#include <config.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include "misc.h"
-#include "tags.h"
-
-struct tagstruct *taglist;
-
-void
-io_init(void)
-{
- taglist = NULL;
-}
-
-char *
-gettag(char *p)
-{
- struct tagstruct *tag1, *tag2;
-
- if (taglist == NULL)
- return NULL;
- tag1 = taglist;
- if (!strncmp(tag1->item, p, strlen(tag1->item))) {
- p = tag1->item;
- taglist = taglist->next;
- free(tag1);
- return p;
- }
- while (tag1->next != NULL) {
- tag2 = tag1->next;
- if (!strncmp(tag2->item, p, strlen(tag2->item))) {
- p = tag2->item;
- tag1->next = tag2->next;
- free(tag2);
- return p;
- }
- tag1 = tag1->next;
- }
- return NULL;
-}
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * tags.h: Tag structure definition
- *
- * Known contributors to this file:
- * John Yockey, 1998
- */
-
-#ifndef TAGS_H
-#define TAGS_H
-
-struct tagstruct {
- char *item;
- struct tagstruct *next;
-};
-
-extern struct tagstruct *taglist;
-
-void io_init(void);
-char *gettag(char *p);
-
-#endif
+++ /dev/null
-/*
- * Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ---
- *
- * See files README, COPYING and CREDITS in the root of the source
- * tree for related information and legal notices. It is expected
- * that future projects/authors will amend these files as needed.
- *
- * ---
- *
- * termio.c: Various io functions
- *
- * Known contributors to this file:
- * Steve McClure, 1998
- */
-
-#include <config.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-#include "misc.h"
-#include "tags.h"
-
-static int sendeof(int sock);
-
-int
-termio(int fd, int sock, FILE *auxfi)
-{
- static char exec[] = "execute";
- static char buf[4096];
- char out[4096];
- int i, n;
- char *ptr;
- char *p, *q, *r, *s, *t;
- int nbytes;
- int prespace, exec_com, inarg, quoted, tagging;
- struct tagstruct *tag;
-#ifdef _WIN32
- char c;
- INPUT_RECORD InpBuffer[2];
- int ret;
- DWORD records;
-#endif
-
- i = strlen(buf);
- p = buf + i;
-#ifndef _WIN32
- n = read(fd, p, sizeof(buf) - i);
-#else
-/* The keyboard is sometimes generating both keydown and keyup
- * events for the same key. Thus, we only want to grab keydown
- * events. */
- if (fd == -1) {
- ret = PeekConsoleInput(hStdIn, InpBuffer, 1, &records);
- if (!ret) {
- fprintf(stderr, "Error peeking the console input (%lu)\n",
- GetLastError());
- return 0;
- }
- if (records == 0)
- return 0;
- if (InpBuffer[0].EventType != KEY_EVENT) {
- ret = ReadConsoleInput(hStdIn, InpBuffer, 1, &records);
- if (!ret) {
- fprintf(stderr, "Error reading the console input (%lu)\n",
- GetLastError());
- return 0;
- }
- if (records == 0)
- return 0;
- return 1;
- }
- if (!InpBuffer[0].Event.KeyEvent.bKeyDown) {
- ret = ReadConsoleInput(hStdIn, InpBuffer, 1, &records);
- if (!ret) {
- fprintf(stderr, "Error reading the console input (%lu)\n",
- GetLastError());
- return 0;
- }
- if (records == 0)
- return 0;
- return 1;
- }
- c = InpBuffer[0].Event.KeyEvent.uChar.AsciiChar;
-
- if (c == 13)
- c = 10;
- records = 1;
- p[0] = c;
- p[1] = '\0';
- if (c != 10) {
- ret = ReadConsole(hStdIn, p, sizeof(buf) - i, &records, NULL);
- if (!ret) {
- fprintf(stderr, "Error reading the console (%lu)\n",
- GetLastError());
- return 0;
- }
- } else
- putchar(c);
-/* Strip off the CRLF to just LF */
- if (records > 1) {
- if (p[records - 2] == 13 && p[records - 1] == 10) {
- p[records - 2] = 10;
- p[records - 1] = 0;
- records--;
- }
- }
- FlushConsoleInputBuffer(hStdIn);
- if (records == 0)
- return 0;
- n = records;
- } else if (fd == 0) {
- if (feof(stdin)) {
- sendeof(sock);
- return 0;
- }
- fgets(p, sizeof(buf) - i, stdin);
- n = strlen(p);
- } else {
- n = read(fd, p, sizeof(buf) - i);
- }
-#endif
- if (n == 0) {
- sendeof(sock);
- return 0;
- }
- if (n < 0) {
- perror("read standard input");
- return 0;
- }
- n += i;
- ptr = buf;
- p = buf;
- q = out;
- r = out;
- tagging = 0;
- inarg = 0;
- prespace = 1;
- quoted = 0;
- exec_com = 0;
- while (p < buf + n && q < out + 4000) {
- if (*p == '\n') {
- if (tagging) {
- tag = malloc(sizeof(struct tagstruct));
- tag->item = malloc(1 + p - s);
- tag->next = taglist;
- taglist = tag;
- t = tag->item;
- while (s < p)
- *t++ = *s++;
- *t = 0;
- }
- *q++ = *p++;
- tagging = 0;
- inarg = 0;
- prespace = 1;
- quoted = 0;
- exec_com = 0;
- ptr = p;
- r = q;
- } else if (tagging) {
- *q++ = *p++;
- } else if (!quoted && isspace(*p)) {
- *q++ = *p++;
- prespace = 1;
- if (exec_com && s > exec + 2) {
- tagging = 1;
- s = p;
- }
- } else if (prespace && *p == '|') {
- tagging = 1;
- *q++ = *p++;
- s = p;
- } else if (prespace && *p == '>') {
- tagging = 1;
- *q++ = *p++;
- if (*p != '\n' && (*p == '!' || *p == '>'))
- *q++ = *p++;
- s = p;
- } else {
- prespace = 0;
- if (*p == '"') {
- quoted = !quoted;
- } else {
- if (!inarg && *p != '?') {
- s = exec;
- exec_com = 1;
- inarg = 1;
- }
- if (exec_com && *s && *s++ != *p)
- exec_com = 0;
- }
- *q++ = *p++;
- }
- }
- p = buf;
- while (ptr < buf + n)
- *p++ = *ptr++;
- *p = 0;
- ptr = out;
- n = r - out;
- if (auxfi) {
- fwrite(out, n, 1, auxfi);
- }
- while (n > 0) {
-#ifndef _WIN32
- nbytes = write(sock, ptr, n);
-#else
- nbytes = send(sock, ptr, n, 0);
-#endif
- if (nbytes <= 0) {
-#ifdef _WIN32
- errno = WSAGetLastError();
-#endif
- perror("write server socket");
- return 0;
- }
- ptr += nbytes;
- n -= nbytes;
- }
- return 1;
-}
-
-static int
-sendeof(int sock)
-{
-#ifndef _WIN32
- if (write(sock, "ctld\n", 5) < 5) {
-#else
- if (send(sock, "ctld\n", 5, 0) < 5) {
-#endif
- fprintf(stderr, "sendeof: EOF send failed\n");
-#ifdef _WIN32
- closesocket(sock);
-#else
- close(sock);
-#endif
- return 0;
- }
- return 1;
-}