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