]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
(doexecute): Use fname(). Simplify convoluted logic. Fix check for
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2007, 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  */
35
36 #include <config.h>
37
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #ifdef _WIN32
45 #include <io.h>
46 #else
47 #include <unistd.h>
48 #endif
49
50 #include "ioqueue.h"
51 #include "misc.h"
52 #include "proto.h"
53 #include "tags.h"
54
55 static char num_teles[64];
56 static char the_prompt[1024];
57 static int mode;
58 static int nbtu;
59 static int nmin;
60 static FILE *redir_fp;
61 static FILE *pipe_fp;
62
63 static void prompt(FILE *auxfi);
64 static void doredir(char *p);
65 static void dopipe(char *p);
66 static void doexecute(char *p, FILE *auxfi);
67 static void output(int code, char *buf, FILE *auxfi);
68 static void screen(char *buf);
69
70 void
71 servercmd(struct ioqueue *ioq, FILE *auxfi)
72 {
73     char buf[1024];
74     char *p;
75     static int code = -1;
76     int eol;
77
78     while (ioq_gets(ioq, buf, sizeof(buf), &eol)) {
79         p = buf;
80         if (code == -1) {
81             if (isalpha(*buf))
82                 code = 10 + (*buf - 'a');
83             else
84                 code = *buf - '0';
85             while (*p && !isspace(*p))
86                 p++;
87             *p++ = 0;
88         }
89         /*
90          * FIXME
91          * C_REDIR, C_PIPE, and C_EXECUTE will not
92          * work with filename longer than one buffer
93          */
94         switch (code) {
95         case C_PROMPT:
96             if (sscanf(p, "%d %d", &nmin, &nbtu) != 2) {
97                 fprintf(stderr, "prompt: bad server prompt %s\n", p);
98             }
99             mode = code;
100             sprintf(the_prompt, "[%d:%d] Command : ", nmin, nbtu);
101             prompt(auxfi);
102             break;
103         case C_REDIR:
104             if (eol)
105                 p[strlen(p) - 1] = '\0';
106             doredir(p);
107             break;
108         case C_PIPE:
109             if (eol)
110                 p[strlen(p) - 1] = '\0';
111             dopipe(p);
112             break;
113         case C_FLUSH:
114             mode = code;
115             if (eol)
116                 p[strlen(p) - 1] = '\0';
117             sprintf(the_prompt, "%s", p);
118             prompt(auxfi);
119             break;
120         case C_EXECUTE:
121             if (eol)
122                 p[strlen(p) - 1] = '\0';
123             doexecute(p, auxfi);
124             break;
125         case C_INFORM:
126             if (eol)
127                 p[strlen(p) - 1] = '\0';
128             if (*p) {
129                 p[strlen(p) - 1] = '\0';
130                 sprintf(num_teles, "(%s) ", p + 1);
131                 if (!redir_fp && !pipe_fp) {
132                     putchar('\07');
133                     prompt(NULL);
134                 }
135             } else
136                 *num_teles = '\0';
137             break;
138         default:
139             output(code, p, auxfi);
140             break;
141         }
142         if (eol)
143             code = -1;
144     }
145 }
146
147 static void
148 prompt(FILE *auxfi)
149 {
150     if (mode == C_PROMPT) {
151         if (redir_fp) {
152             (void)fclose(redir_fp);
153             redir_fp = NULL;
154         } else if (pipe_fp) {
155             (void)pclose(pipe_fp);
156             pipe_fp = NULL;
157         }
158     }
159     if (mode == C_PROMPT)
160         printf("\n");
161     printf("%s%s", num_teles, the_prompt);
162     (void)fflush(stdout);
163     if (auxfi) {
164         fprintf(auxfi, "\n%s%s", num_teles, the_prompt);
165         (void)fflush(auxfi);
166     }
167 }
168
169 static char *
170 fname(char *s)
171 {
172     char *beg, *end;
173
174     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
175     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
176     *end = 0;
177     return beg;
178 }
179
180 /*
181  * opens redir_fp if successful
182  */
183 static void
184 doredir(char *p)
185 {
186     char *tag;
187     int mode;
188     int fd;
189
190     if (redir_fp) {
191         (void)fclose(redir_fp);
192         redir_fp = NULL;
193     }
194
195     if (*p++ != '>') {
196         fprintf(stderr, "WARNING!  Weird redirection %s", p);
197         return;
198     }
199
200     mode = O_WRONLY | O_CREAT;
201     if (*p == '>') {
202         mode |= O_APPEND;
203         p++;
204     } else if (*p == '!') {
205         mode |= O_TRUNC;
206         p++;
207     } else
208         mode |= O_EXCL;
209
210     tag = gettag(p);
211     p = fname(p);
212     if (tag == NULL) {
213         fprintf(stderr, "WARNING!  Server redirected output to file %s\n",
214                 p);
215         return;
216     }
217     free(tag);
218
219     if (*p == 0) {
220         fprintf(stderr, "Redirection lacks a file name\n");
221         return;
222     }
223     fd = open(p, mode, 0600);
224     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
225     if (!redir_fp) {
226         fprintf(stderr, "Can't redirect to %s: %s\n",
227                 p, strerror(errno));
228     }
229 }
230
231 /*
232  * opens "pipe_fp" if successful
233  */
234 static void
235 dopipe(char *p)
236 {
237     char *tag;
238
239     if (*p++ != '|') {
240         fprintf(stderr, "WARNING!  Weird pipe %s", p);
241         return;
242     }
243
244     tag = gettag(p);
245     if (tag == NULL) {
246         fprintf(stderr, "WARNING!  Server attempted to run: %s\n", p);
247         return;
248     }
249     free(tag);
250
251     for (; *p && isspace(*p); p++) ;
252     if (*p == 0) {
253         fprintf(stderr, "Redirection lacks a command\n");
254         return;
255     }
256     if ((pipe_fp = popen(p, "w")) == NULL) {
257         fprintf(stderr, "Can't redirect to pipe %s: %s\n",
258                 p, strerror(errno));
259     }
260 }
261
262 static void
263 doexecute(char *p, FILE *auxfi)
264 {
265     int fd;
266     char *tag;
267
268     tag = gettag(p);
269     if (tag == NULL) {
270         fprintf(stderr,
271                 "WARNING!  Server attempted unauthorized read of file %s\n",
272                 p);
273         return;
274     }
275     free(tag);
276
277     p = fname(p);
278     if (*p == 0) {
279         fprintf(stderr, "Need a file to execute\n");
280         return;
281     }
282     if ((fd = open(p, O_RDONLY, 0)) < 0) {
283         fprintf(stderr, "Can't open execute file %s: %s\n",
284                 p, strerror(errno));
285         return;
286     }
287     /* copies 4k at a time to the socket */
288     while (termio(fd, sock, auxfi))     /*do copy */
289         ;
290     /*
291      * Some platforms don't send the eof (cntl-D) at the end of
292      * copying a file.  If emp_client hangs at the end of an
293      * execute, include the following line and notify wolfpack
294      * of the platform you are using.
295      * sendeof(sock);
296      */
297     close(fd);
298 }
299
300 static void
301 output(int code, char *buf, FILE *auxfi)
302 {
303     switch (code) {
304     case C_NOECHO:
305         /* not implemented; server doesn't send it */
306         break;
307     case C_ABORT:
308         printf("Aborted\n");
309         if (auxfi)
310             fprintf(auxfi, "Aborted\n");
311         break;
312     case C_CMDERR:
313     case C_BADCMD:
314         printf("Error; ");
315         if (auxfi)
316             fprintf(auxfi, "Error; ");
317         break;
318     case C_EXIT:
319         printf("Exit: ");
320         if (auxfi)
321             fprintf(auxfi, "Exit: ");
322         break;
323     case C_FLASH:
324         printf("\n");
325         break;
326     default:
327         break;
328     }
329     if (auxfi) {
330         fprintf(auxfi, "%s", buf);
331     }
332
333     if (redir_fp)
334         fprintf(redir_fp, "%s", buf);
335     else if (pipe_fp)
336         fprintf(pipe_fp, "%s", buf);
337     else {
338         screen(buf);
339     }
340 }
341
342 static void
343 screen(char *buf)
344 {
345     char c;
346
347     while ((c = *buf++)) {
348         if (eight_bit_clean) {
349             if (c == 14)
350                 putso();
351             else if (c == 15)
352                 putse();
353             else
354                 putchar(c);
355         } else if (c & 0x80) {
356             putso();
357             putchar(c & 0x7f);
358             putse();
359         } else
360             putchar(c);
361     }
362 }