]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
4bd97408ae0d2b302278fc4562e4c6be263f9ba8
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  servercmd.c: Change the state depending on the command from the server.
29  *
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Steve McClure, 1998
33  *     Ron Koenderink, 2005
34  *     Markus Armbruster, 2005-2007
35  */
36
37 #include <config.h>
38
39 #include <assert.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include "misc.h"
46 #include "proto.h"
47 #include "secure.h"
48
49 #ifdef _WIN32
50     #define open(filename, flags, ...) \
51         ((flags & O_CREAT) \
52          ? w32_openfd((filename), (flags), ## __VA_ARGS__) \
53          : w32_openhandle((filename), (flags)))
54 #endif
55
56 int eight_bit_clean;
57 FILE *auxfp;
58
59 static FILE *redir_fp;
60 static int redir_is_pipe;
61 static int executing;
62 static size_t input_to_forget;
63
64 static void prompt(int, char *, char *);
65 static void doredir(char *p);
66 static void dopipe(char *p);
67 static int doexecute(char *p);
68
69 void
70 servercmd(int code, char *arg, int len)
71 {
72     static int nmin, nbtu, fd;
73     static char the_prompt[1024];
74     static char teles[64];
75
76     switch (code) {
77     case C_PROMPT:
78         if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
79             fprintf(stderr, "prompt: bad server prompt %s\n", arg);
80         }
81         snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
82                  nmin, nbtu);
83         if (redir_fp) {
84             if (redir_is_pipe)
85                 (void)pclose(redir_fp);
86             else
87                 (void)fclose(redir_fp);
88             redir_fp = NULL;
89         }
90         if (input_to_forget) {
91             forget_input(input_to_forget);
92             input_to_forget = 0;
93         }
94         prompt(code, the_prompt, teles);
95         executing = 0;
96         break;
97     case C_FLUSH:
98         snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
99         prompt(code, the_prompt, teles);
100         break;
101     case C_EXECUTE:
102         fd = doexecute(arg);
103         if (fd < 0)
104             send_eof++;
105         else {
106             input_fd = fd;
107             executing = 1;
108         }
109         break;
110     case C_EXIT:
111         printf("Exit: %s", arg);
112         if (auxfp)
113             fprintf(auxfp, "Exit: %s", arg);
114         break;
115     case C_FLASH:
116         printf("\n%s", arg);
117         if (auxfp)
118             fprintf(auxfp, "\n%s", arg);
119         break;
120     case C_INFORM:
121         if (arg[0] != '\n') {
122             snprintf(teles, sizeof(teles), "(%.*s) ", len -1, arg);
123             if (!redir_fp) {
124                 putchar('\07');
125                 prompt(code, the_prompt, teles);
126             }
127         } else
128             teles[0] = 0;
129         break;
130     case C_PIPE:
131         dopipe(arg);
132         break;
133     case C_REDIR:
134         doredir(arg);
135         break;
136     default:
137         assert(0);
138         break;
139     }
140 }
141
142 static void
143 prompt(int code, char *prompt, char *teles)
144 {
145     char *nl;
146
147     nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
148     printf("%s%s%s", nl, teles, prompt);
149     fflush(stdout);
150     if (auxfp) {
151         fprintf(auxfp, "%s%s%s", nl, teles, prompt);
152         fflush(auxfp);
153     }
154 }
155
156 static char *
157 fname(char *s)
158 {
159     char *beg, *end;
160
161     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
162     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
163     *end = 0;
164     return beg;
165 }
166
167 static int
168 redir_authorized(char *arg, char *attempt, int expected)
169 {
170     size_t seen = seen_input(arg);
171
172     if (executing) {
173         fprintf(stderr, "Can't %s in a batch file\n", attempt);
174         return 0;
175     }
176
177     if (!expected) {
178         fprintf(stderr, "WARNING!  Server attempted to %s unexpectedly\n",
179                 attempt);
180         return 0;
181     }
182
183     if (!seen || (input_to_forget && input_to_forget != seen)) {
184         fprintf(stderr, "WARNING!  Server attempted to %s %s\n",
185                 attempt, arg);
186         return 0;
187     }
188     input_to_forget = seen;
189     return 1;
190 }
191
192 static void
193 doredir(char *p)
194 {
195     int mode;
196     int fd;
197
198     if (!redir_authorized(p, "redirect to file", !redir_fp))
199         return;
200     if (*p++ != '>') {
201         fprintf(stderr, "WARNING!  Weird redirection %s", p);
202         return;
203     }
204
205     mode = O_WRONLY | O_CREAT;
206     if (*p == '>') {
207         mode |= O_APPEND;
208         p++;
209     } else if (*p == '!') {
210         mode |= O_TRUNC;
211         p++;
212     } else
213         mode |= O_EXCL;
214
215     p = fname(p);
216     if (*p == 0) {
217         fprintf(stderr, "Redirection lacks a file name\n");
218         return;
219     }
220
221     redir_is_pipe = 0;
222     fd = open(p, mode, 0666);
223     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
224     if (!redir_fp) {
225         fprintf(stderr, "Can't redirect to %s: %s\n",
226                 p, strerror(errno));
227     }
228 }
229
230 static void
231 dopipe(char *p)
232 {
233     if (!redir_authorized(p, "pipe to shell command", !redir_fp))
234         return;
235     if (*p++ != '|') {
236         fprintf(stderr, "WARNING!  Weird pipe %s", p);
237         return;
238     }
239
240     for (; *p && isspace(*p); p++) ;
241     if (*p == 0) {
242         fprintf(stderr, "Redirection lacks a command\n");
243         return;
244     }
245
246     redir_is_pipe = 1;
247     if ((redir_fp = popen(p, "w")) == NULL) {
248         fprintf(stderr, "Can't redirect to pipe %s: %s\n",
249                 p, strerror(errno));
250     }
251 }
252
253 static int
254 doexecute(char *p)
255 {
256     int fd;
257
258     if (!redir_authorized(p, "execute batch file", 1))
259         return -1;
260
261     p = fname(p);
262     if (*p == 0) {
263         fprintf(stderr, "Need a file to execute\n");
264         return -1;
265     }
266
267     if ((fd = open(p, O_RDONLY)) < 0) {
268         fprintf(stderr, "Can't open execute file %s: %s\n",
269                 p, strerror(errno));
270         return -1;
271     }
272
273     return fd;
274 }
275
276 void
277 outch(char c)
278 {
279     if (auxfp)
280         putc(c, auxfp);
281     if (redir_fp)
282         putc(c, redir_fp);
283     else if (eight_bit_clean) {
284         if (c == 14)
285             putso();
286         else if (c == 15)
287             putse();
288         else
289             putchar(c);
290     } else if (c & 0x80) {
291         putso();
292         putchar(c & 0x7f);
293         putse();
294     } else
295         putchar(c);
296 }