]> 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-2010, 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-2009
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 int eight_bit_clean;
50 FILE *auxfp;
51
52 static FILE *redir_fp;
53 static int redir_is_pipe;
54 static int executing;
55 static size_t input_to_forget;
56
57 static void prompt(int, char *, char *);
58 static void doredir(char *p);
59 static void dopipe(char *p);
60 static int doexecute(char *p);
61
62 void
63 servercmd(int code, char *arg, int len)
64 {
65     static int nmin, nbtu, fd;
66     static char the_prompt[1024];
67     static char teles[64];
68
69     switch (code) {
70     case C_PROMPT:
71         if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
72             fprintf(stderr, "prompt: bad server prompt %s\n", arg);
73         }
74         snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
75                  nmin, nbtu);
76         if (redir_fp) {
77             if (redir_is_pipe)
78                 (void)pclose(redir_fp);
79             else
80                 (void)fclose(redir_fp);
81             redir_fp = NULL;
82         }
83         if (input_to_forget) {
84             forget_input(input_to_forget);
85             input_to_forget = 0;
86         }
87         prompt(code, the_prompt, teles);
88         executing = 0;
89         break;
90     case C_FLUSH:
91         snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
92         prompt(code, the_prompt, teles);
93         break;
94     case C_EXECUTE:
95         fd = doexecute(arg);
96         if (fd < 0)
97             send_eof++;
98         else {
99             input_fd = fd;
100             executing = 1;
101         }
102         break;
103     case C_EXIT:
104         printf("Exit: %s", arg);
105         if (auxfp)
106             fprintf(auxfp, "Exit: %s", arg);
107         break;
108     case C_FLASH:
109         printf("\n%s", arg);
110         if (auxfp)
111             fprintf(auxfp, "\n%s", arg);
112         break;
113     case C_INFORM:
114         if (arg[0] != '\n') {
115             snprintf(teles, sizeof(teles), "(%.*s) ", len -1, arg);
116             if (!redir_fp) {
117                 putchar('\07');
118                 prompt(code, the_prompt, teles);
119             }
120         } else
121             teles[0] = 0;
122         break;
123     case C_PIPE:
124         dopipe(arg);
125         break;
126     case C_REDIR:
127         doredir(arg);
128         break;
129     default:
130         assert(0);
131         break;
132     }
133 }
134
135 static void
136 prompt(int code, char *prompt, char *teles)
137 {
138     char *nl;
139
140     nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
141     printf("%s%s%s", nl, teles, prompt);
142     fflush(stdout);
143     if (auxfp) {
144         fprintf(auxfp, "%s%s%s", nl, teles, prompt);
145         fflush(auxfp);
146     }
147 }
148
149 static char *
150 fname(char *s)
151 {
152     char *beg, *end;
153
154     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
155     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
156     *end = 0;
157     return beg;
158 }
159
160 static int
161 redir_authorized(char *arg, char *attempt, int expected)
162 {
163     size_t seen = seen_input(arg);
164
165     if (executing) {
166         fprintf(stderr, "Can't %s in a batch file\n", attempt);
167         return 0;
168     }
169
170     if (!expected) {
171         fprintf(stderr, "WARNING!  Server attempted to %s unexpectedly\n",
172                 attempt);
173         return 0;
174     }
175
176     if (!seen || (input_to_forget && input_to_forget != seen)) {
177         fprintf(stderr, "WARNING!  Server attempted to %s %s\n",
178                 attempt, arg);
179         return 0;
180     }
181     input_to_forget = seen;
182     return 1;
183 }
184
185 static void
186 doredir(char *p)
187 {
188     int mode;
189     int fd;
190
191     if (!redir_authorized(p, "redirect to file", !redir_fp))
192         return;
193     if (*p++ != '>') {
194         fprintf(stderr, "WARNING!  Weird redirection %s", p);
195         return;
196     }
197
198     mode = O_WRONLY | O_CREAT;
199     if (*p == '>') {
200         mode |= O_APPEND;
201         p++;
202     } else if (*p == '!') {
203         mode |= O_TRUNC;
204         p++;
205     } else
206         mode |= O_EXCL;
207
208     p = fname(p);
209     if (*p == 0) {
210         fprintf(stderr, "Redirection lacks a file name\n");
211         return;
212     }
213
214     redir_is_pipe = 0;
215     fd = open(p, mode, 0666);
216     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
217     if (!redir_fp) {
218         fprintf(stderr, "Can't redirect to %s: %s\n",
219                 p, strerror(errno));
220     }
221 }
222
223 static void
224 dopipe(char *p)
225 {
226     if (!redir_authorized(p, "pipe to shell command", !redir_fp))
227         return;
228     if (*p++ != '|') {
229         fprintf(stderr, "WARNING!  Weird pipe %s", p);
230         return;
231     }
232
233     for (; *p && isspace(*p); p++) ;
234     if (*p == 0) {
235         fprintf(stderr, "Redirection lacks a command\n");
236         return;
237     }
238
239     redir_is_pipe = 1;
240     if ((redir_fp = popen(p, "w")) == NULL) {
241         fprintf(stderr, "Can't redirect to pipe %s: %s\n",
242                 p, strerror(errno));
243     }
244 }
245
246 static int
247 doexecute(char *p)
248 {
249     int fd;
250
251     if (!redir_authorized(p, "execute batch file", 1))
252         return -1;
253
254     p = fname(p);
255     if (*p == 0) {
256         fprintf(stderr, "Need a file to execute\n");
257         return -1;
258     }
259
260     if ((fd = open(p, O_RDONLY)) < 0) {
261         fprintf(stderr, "Can't open execute file %s: %s\n",
262                 p, strerror(errno));
263         return -1;
264     }
265
266     return fd;
267 }
268
269 void
270 outch(char c)
271 {
272     if (auxfp)
273         putc(c, auxfp);
274     if (redir_fp)
275         putc(c, redir_fp);
276     else if (eight_bit_clean) {
277         if (c == 14)
278             putso();
279         else if (c == 15)
280             putse();
281         else
282             putchar(c);
283     } else if (c & 0x80) {
284         putso();
285         putchar(c & 0x7f);
286         putse();
287     } else
288         putchar(c);
289 }