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