]> git.pond.sub.org Git - empserver/blob - src/client/main.c
(main, termio): Add the ability to set the username.
[empserver] / src / client / main.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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  *  main.c: client main function
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Steve McClure, 1998
33  */
34
35 #ifdef _NTSDK
36 #undef _NTSDK
37 #endif
38
39 #include "misc.h"
40 #include "proto.h"
41 #include "queue.h"
42 #include "ioqueue.h"
43 #include "tags.h"
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/types.h>
49 #ifndef _WIN32
50 #include <pwd.h>
51 #endif
52 #include <signal.h>
53 #include <errno.h>
54 #include <time.h>
55 #ifndef _WIN32
56 #include <sys/socket.h>
57 #include <sys/time.h>
58 #include <netinet/in.h>
59 #include <unistd.h>
60 #else
61 #include <windows.h>
62 #include <winsock.h>
63 #include <conio.h>
64 #include <io.h>
65 #endif
66
67 #ifdef _WIN32
68 HANDLE hStdIn;
69 #endif
70
71 #define RETRY   3
72
73 int interrupt;
74 int sock;
75
76 static void intr(int sig);
77
78
79 int
80 main(int ac, s_char **av)
81 {
82 #ifdef _WIN32
83     WSADATA WsaData;
84     int err;
85     fd_set readfds;
86     struct timeval tm;
87     DWORD stdinmode;
88     SECURITY_ATTRIBUTES security;
89     int bRedirected = 0;
90     char unamebuf[128];
91 #else
92     fd_set mask;
93     fd_set savemask;
94     int retry = 0;
95 #endif
96     struct ioqueue server;
97     s_char *argv[128];
98     int i, j;
99     s_char *ptr;
100     s_char *auxout_fname;
101     FILE *auxout_fp;
102     struct sockaddr_in sin;
103     int n;
104     s_char *cname;
105     s_char *pname;
106     s_char *uname;
107     int send_kill = 0;
108
109 #ifdef _WIN32
110     err = WSAStartup(0x0101, &WsaData);
111     if (err == SOCKET_ERROR) {
112         printf("WSAStartup Failed\n");
113         return FALSE;
114     }
115 #else
116     FD_ZERO(&mask);
117     FD_ZERO(&savemask);
118 #endif
119     memset(argv, 0, sizeof(argv));
120     saveargv(ac, av, argv);
121     auxout_fname = 0;
122     auxout_fp = 0;
123     for (i = j = 1; i < ac; ++i) {
124         ptr = argv[i];
125         if (strcmp(ptr, "-2") == 0) {
126             if (i + 1 >= ac) {
127                 fprintf(stderr, "-2: Missing filename!\n");
128                 exit(1);
129             }
130             auxout_fname = argv[i + 1];
131             ++i;
132             continue;
133         } else if (strcmp(ptr, "-k") == 0) {
134             send_kill = 1;
135             continue;
136         }
137         argv[j] = argv[i];
138         ++j;
139     }
140     ac = j;
141     if (auxout_fname && (auxout_fp = fopen(auxout_fname, "a")) == NULL) {
142         fprintf(stderr, "Unable to open %s for append\n", auxout_fname);
143         exit(1);
144     }
145     getsose();
146     if (!hostport(getenv("EMPIREPORT"), &sin) &&
147         !hostport("empire", &sin) && !hostport(empireport, &sin)) {
148         fprintf(stderr, "No empire port\n");
149         exit(1);
150     }
151     if (!hostaddr(getenv("EMPIREHOST"), &sin) &&
152         !hostaddr(empirehost, &sin)) {
153         fprintf(stderr, "No empire host\n");
154         exit(1);
155     }
156     if ((sock = hostconnect(&sin)) < 0)
157         exit(1);
158     cname = getenv("COUNTRY");
159     if (ac > 1)
160         cname = argv[1];
161     pname = getenv("PLAYER");
162     if (ac > 2)
163         pname = argv[2];
164     uname = getenv("LOGNAME");
165     if (uname == NULL) {
166 #ifndef _WIN32
167         struct passwd *pwd;
168
169         pwd = getpwuid(getuid());
170         if (pwd == NULL) {
171             fprintf(stderr, "You don't exist.  Go away\n");
172             exit(1);
173         }
174         uname = pwd->pw_name;
175 #else
176         DWORD unamesize;
177
178         unamesize = sizeof(unamebuf);
179         if (GetUserName(unamebuf, &unamesize)) {
180             uname = unamebuf;
181             if ((unamesize <= 0 ) || (strlen(uname) <= 0))
182                 uname = "nobody";
183         } else
184             uname = "nobody";
185 #endif
186     }
187     if (!login(sock, uname, cname, pname, send_kill)) {
188         close(sock);
189         exit(1);
190     }
191     ioq_init(&server, 2048);
192     io_init();
193 #ifndef _WIN32
194     FD_ZERO(&mask);
195     FD_SET(0, &savemask);
196     FD_SET(sock, &savemask);
197 #endif
198     (void)signal(SIGINT, intr);
199 #ifndef _WIN32
200     (void)signal(SIGPIPE, SIG_IGN);
201     while (FD_ISSET(sock, &savemask)) {
202         mask = savemask;
203         n = select(sock + 1, &mask, (fd_set *)0, (fd_set *)0,
204                    (struct timeval *)0);
205         if (interrupt) {
206             if (!handleintr(sock))
207                 break;
208             errno = 0;
209         }
210         if (n <= 0) {
211             if (errno == EINTR) {
212                 perror("select");
213                 (void)close(sock);
214                 FD_CLR(sock, &savemask);
215             }
216         } else {
217             if (FD_ISSET(0, &mask)) {
218                 if (!termio(0, sock, auxout_fp)) {
219                     if (retry++ >= RETRY) {
220                         FD_CLR(0, &savemask);
221                     }
222                 } else {
223                     retry = 0;
224                 }
225             }
226             if (FD_ISSET(sock, &mask)) {
227                 if (!serverio(sock, &server))
228                     FD_CLR(sock, &savemask);
229                 else
230                     servercmd(&server, auxout_fp);
231             }
232         }
233     }
234 #else
235     bRedirected = 0;
236     tm.tv_sec = 0;
237     tm.tv_usec = 1000;
238
239     if (!_isatty(_fileno(stdin)))
240         bRedirected = 1;
241     else {
242         security.nLength = sizeof(SECURITY_ATTRIBUTES);
243         security.lpSecurityDescriptor = NULL;
244         security.bInheritHandle = TRUE;
245         hStdIn = CreateFile("CONIN$",
246                             GENERIC_READ | GENERIC_WRITE,
247                             FILE_SHARE_READ | FILE_SHARE_WRITE,
248                             &security, OPEN_EXISTING, (DWORD) NULL, NULL);
249         
250         if (hStdIn == INVALID_HANDLE_VALUE) {
251             printf("Error getting hStdIn.\n");
252             fflush(stdout);
253             exit(-3);
254         }
255         
256         err = GetConsoleMode(hStdIn, &stdinmode);
257         if (!err) {
258             printf("Error getting console mode.\n");
259             fflush(stdout);
260             exit(-4);
261         } else {
262             stdinmode |= ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
263             err = SetConsoleMode(hStdIn, stdinmode);
264             if (!err) {
265                 printf("Error setting console mode.\n");
266                 fflush(stdout);
267                 exit(-5);
268             }
269         }
270     }
271     while (1) {
272         FD_ZERO(&readfds);
273         FD_SET(sock, &readfds);
274         n = select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0,
275                    (struct timeval *)&tm);
276         if (interrupt) {
277             if (!handleintr(sock))
278                 break;
279             errno = 0;
280         }
281         if (n < 0) {
282             if (errno == EINTR) {
283                 errno = WSAGetLastError();
284                 perror("select");
285                 (void)close(sock);
286                 break;
287             }
288         } else {
289             if (bRedirected == 1) {
290                 if (!termio(0, sock, auxout_fp))
291                     bRedirected = -1;
292             } else if (bRedirected == 0) {
293                 if (WaitForSingleObject(hStdIn, 10) != WAIT_TIMEOUT) {
294                     termio(-1, sock, auxout_fp);
295                     FlushConsoleInputBuffer(hStdIn);
296                 }
297             }
298             if (FD_ISSET(sock, &readfds)) {
299                 if (!serverio(sock, &server))
300                     break;
301                 else
302                     servercmd(&server, auxout_fp);
303             }
304         }
305     }
306     if (bRedirected == 0)
307         CloseHandle(hStdIn);
308 #endif
309     ioq_drain(&server);
310     (void)close(sock);
311     return 0;                   /* Shut the compiler up */
312 }
313
314 static void
315 intr(int sig)
316 {
317     interrupt++;
318 #ifdef _WIN32
319     signal(SIGINT, intr);
320 #endif
321 #ifdef hpux
322     signal(SIGINT, intr);
323 #endif
324 }