Annotation of dgamelaunch-openbsd/ttyrec.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * Copyright (c) 1980 Regents of the University of California.
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. All advertising materials mentioning features or use of this software
! 14: * must display the following acknowledgement:
! 15: * This product includes software developed by the University of
! 16: * California, Berkeley and its contributors.
! 17: * 4. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: */
! 33:
! 34: /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
! 35: * - added Native Language Support
! 36: */
! 37:
! 38: /* 2000-12-27 Satoru Takabayashi <satoru@namazu.org>
! 39: * - modify `script' to create `ttyrec'.
! 40: */
! 41:
! 42: /*
! 43: * script
! 44: */
! 45:
! 46: #include "dgamelaunch.h"
! 47: #include "config.h"
! 48:
! 49: #include <sys/types.h>
! 50: #include <sys/stat.h>
! 51: #include <sys/ioctl.h>
! 52: #include <sys/time.h>
! 53: #include <sys/wait.h>
! 54: #include <fcntl.h>
! 55:
! 56: #include <termios.h>
! 57: #include <time.h>
! 58: #include <signal.h>
! 59: #include <stdio.h>
! 60: #include <unistd.h>
! 61: #include <string.h>
! 62: #ifndef NOSTREAMS
! 63: # include <stropts.h>
! 64: #endif
! 65: #include <stdlib.h>
! 66: #include <stdint.h>
! 67:
! 68: #include "ttyrec.h"
! 69: #include "io.h"
! 70:
! 71: #ifndef XCASE
! 72: # define XCASE 0
! 73: #endif
! 74: static void query_encoding(int game, char *username);
! 75:
! 76: int slave;
! 77: pid_t dgl_parent;
! 78: pid_t child, subchild;
! 79: pid_t input_child;
! 80: char* ipfile = NULL;
! 81:
! 82: volatile int wait_for_menu = 0;
! 83:
! 84: FILE *fscript;
! 85: int master;
! 86:
! 87: struct termios tt;
! 88: struct winsize win;
! 89:
! 90: char last_ttyrec[512] = { '\0' };
! 91:
! 92: int ancient_encoding = 0;
! 93:
! 94: void
! 95: ttyrec_id(int game, char *username, char *ttyrec_filename)
! 96: {
! 97: int i;
! 98: time_t tstamp;
! 99: Header h;
! 100: char *buf = (char *)malloc(1024);
! 101: char tmpbuf[256];
! 102: char *server_id = banner_var_value("$SERVERID");
! 103: if (!buf) return;
! 104:
! 105: tstamp = time(NULL);
! 106:
! 107: #define dCLRSCR "\033[2J"
! 108: #define dCRLF "\r\n"
! 109: snprintf(buf, 1024,
! 110: dCLRSCR "\033[1;1H" dCRLF
! 111: "Player: %s" dCRLF
! 112: "Game: %s" dCRLF
! 113: "Server: %s" dCRLF
! 114: "Filename: %s" dCRLF
! 115: "Time: (%lu) %s" dCRLF
! 116: dCLRSCR,
! 117: username,
! 118: myconfig[game]->game_name,
! 119: (server_id ? server_id : "Unknown"),
! 120: ttyrec_filename,
! 121: tstamp, ctime(&tstamp)
! 122: );
! 123: #undef dCLRSCR
! 124: #undef dCRLF
! 125: h.len = strlen(buf);
! 126: gettimeofday (&h.tv, NULL);
! 127:
! 128: (void) write_header(fscript, &h);
! 129: (void) fwrite(buf, 1, h.len, fscript);
! 130:
! 131: free(buf);
! 132: }
! 133:
! 134: int
! 135: ttyrec_main (int game, char *username, char *ttyrec_path, char* ttyrec_filename)
! 136: {
! 137: char dirname[100];
! 138:
! 139: /* Note our PID to let children kill the main dgl process for idling */
! 140: dgl_parent = getpid();
! 141: child = subchild = input_child = 0;
! 142:
! 143: if (!ttyrec_path) {
! 144: child = fork();
! 145: if (child < 0) {
! 146: perror ("fork");
! 147: fail ();
! 148: }
! 149: if (child == 0) {
! 150: execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
! 151: } else {
! 152: int status;
! 153: (void) wait(&status);
! 154: }
! 155: return 0;
! 156: }
! 157:
! 158: if (ttyrec_path[strlen(ttyrec_path)-1] == '/')
! 159: snprintf (dirname, 100, "%s%s", ttyrec_path, ttyrec_filename);
! 160: else
! 161: snprintf (dirname, 100, "%s/%s", ttyrec_path, ttyrec_filename);
! 162: ancient_encoding = myconfig[game]->encoding;
! 163: if (ancient_encoding == -1)
! 164: query_encoding(game, username);
! 165:
! 166: snprintf(last_ttyrec, 512, "%s", dirname);
! 167:
! 168: atexit(&remove_ipfile);
! 169: if ((fscript = fopen (dirname, "w")) == NULL)
! 170: {
! 171: perror (dirname);
! 172: fail ();
! 173: }
! 174: setbuf (fscript, NULL);
! 175:
! 176: fixtty ();
! 177:
! 178: (void) signal (SIGCHLD, finish);
! 179: child = fork ();
! 180: if (child < 0)
! 181: {
! 182: perror ("fork");
! 183: fail ();
! 184: }
! 185: if (child == 0)
! 186: {
! 187: subchild = child = fork ();
! 188: if (child < 0)
! 189: {
! 190: perror ("fork");
! 191: fail ();
! 192: }
! 193: if (child)
! 194: {
! 195: close (slave);
! 196: ipfile = gen_inprogress_lock (game, child, ttyrec_filename);
! 197: ttyrec_id(game, username, ttyrec_filename);
! 198: dooutput (myconfig[game]->max_idle_time);
! 199: }
! 200: else
! 201: doshell (game, username);
! 202: }
! 203:
! 204: (void) fclose (fscript);
! 205:
! 206: wait_for_menu = 1;
! 207: input_child = fork();
! 208: if (input_child < 0)
! 209: {
! 210: perror ("fork2");
! 211: fail ();
! 212: }
! 213: if (!input_child)
! 214: doinput ();
! 215: else
! 216: {
! 217: while (wait_for_menu)
! 218: sleep(1);
! 219: }
! 220:
! 221: remove_ipfile();
! 222: child = 0;
! 223:
! 224: return 0;
! 225: }
! 226:
! 227: void
! 228: doinput ()
! 229: {
! 230: register int cc;
! 231: char ibuf[BUFSIZ];
! 232:
! 233: while ((cc = read (0, ibuf, BUFSIZ)) > 0)
! 234: (void) write (master, ibuf, cc);
! 235: done ();
! 236: }
! 237:
! 238: void
! 239: finish (int sig)
! 240: {
! 241: int status;
! 242: register int pid;
! 243: register int die = 0;
! 244:
! 245: (void)sig; /* unused */
! 246:
! 247: while ((pid = wait3 (&status, WNOHANG, 0)) > 0)
! 248: {
! 249: if (pid == child)
! 250: die = 1;
! 251: }
! 252:
! 253: if (die)
! 254: {
! 255: if (input_child)
! 256: {
! 257: // Need to kill the child that's writing input to pty.
! 258: kill(input_child, SIGTERM);
! 259: while ((pid = wait3(&status, WNOHANG, 0)) > 0);
! 260: }
! 261: else
! 262: done ();
! 263: }
! 264: wait_for_menu = 0;
! 265: }
! 266:
! 267: void
! 268: game_idle_kill(int signal)
! 269: {
! 270: kill(child, SIGHUP);
! 271: kill(dgl_parent, SIGHUP);
! 272: }
! 273:
! 274: static unsigned short charset_vt100[128] =
! 275: {
! 276: 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
! 277: 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
! 278: 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
! 279: 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
! 280: 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
! 281: 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
! 282: 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
! 283: 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
! 284: 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
! 285: 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
! 286: 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
! 287: 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
! 288: #if 0
! 289: 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
! 290: 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0xf800,
! 291: 0xf801, 0x2500, 0xf803, 0xf804, 0x251c, 0x2524, 0x2534, 0x252c,
! 292: 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
! 293: #endif
! 294: 0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
! 295: 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
! 296: 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
! 297: 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020,
! 298: };
! 299:
! 300: static unsigned short charset_cp437[256] =
! 301: {
! 302: // Real IBM charset has no control codes, but they are needed by
! 303: // terminals.
! 304: 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
! 305: 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
! 306: 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
! 307: 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
! 308: #if 0
! 309: 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
! 310: 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
! 311: 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
! 312: 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
! 313: #endif
! 314: 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
! 315: 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
! 316: 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
! 317: 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
! 318: 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
! 319: 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
! 320: 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
! 321: 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
! 322: 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
! 323: 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
! 324: 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
! 325: 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
! 326: 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
! 327: 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
! 328: 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
! 329: 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
! 330: 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
! 331: 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
! 332: 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
! 333: 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
! 334: 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
! 335: 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
! 336: 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
! 337: 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
! 338: 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
! 339: 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
! 340: 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
! 341: 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
! 342: };
! 343:
! 344: // there must be at least 4 bytes free, NOT CHECKED!
! 345: static int wctoutf8(char *d, uint32_t s)
! 346: {
! 347: if (s < 0x80)
! 348: {
! 349: d[0] = s;
! 350: return 1;
! 351: }
! 352: if (s < 0x800)
! 353: {
! 354: d[0] = ( s >> 6) | 0xc0;
! 355: d[1] = ( s & 0x3f) | 0x80;
! 356: return 2;
! 357: }
! 358: if (s < 0x10000)
! 359: {
! 360: d[0] = ( s >> 12) | 0xe0;
! 361: d[1] = ((s >> 6) & 0x3f) | 0x80;
! 362: d[2] = ( s & 0x3f) | 0x80;
! 363: return 3;
! 364: }
! 365: if (s < 0x110000)
! 366: {
! 367: d[0] = ( s >> 18) | 0xf0;
! 368: d[1] = ((s >> 12) & 0x3f) | 0x80;
! 369: d[2] = ((s >> 6) & 0x3f) | 0x80;
! 370: d[3] = ( s & 0x3f) | 0x80;
! 371: return 4;
! 372: }
! 373: // Invalid char marker (U+FFFD).
! 374: d[0] = 0xef;
! 375: d[1] = 0xbf;
! 376: d[2] = 0xbd;
! 377: return 3;
! 378: }
! 379:
! 380: void
! 381: dooutput (int max_idle_time)
! 382: {
! 383: int cc, i, len;
! 384: time_t tvec, time ();
! 385: char obuf[BUFSIZ], ubuf[BUFSIZ*4+2], *ctime (), *out;
! 386: int galt = 0; // vt100 G switch
! 387:
! 388: setbuf (stdout, NULL);
! 389: (void) close (0);
! 390: tvec = time ((time_t *) NULL);
! 391: /* Set up SIGALRM handler to kill idle games */
! 392: signal(SIGALRM, game_idle_kill);
! 393: for (;;)
! 394: {
! 395: Header h;
! 396:
! 397: cc = read (master, obuf, BUFSIZ);
! 398: if (cc <= 0)
! 399: break;
! 400:
! 401: if (max_idle_time)
! 402: alarm(max_idle_time);
! 403:
! 404: switch (ancient_encoding)
! 405: {
! 406: case 0: // UTF-8
! 407: default:
! 408: h.len = cc;
! 409: gettimeofday (&h.tv, NULL);
! 410: (void) write (1, obuf, cc);
! 411: (void) write_header (fscript, &h);
! 412: (void) fwrite (obuf, 1, cc, fscript);
! 413: break;
! 414: case 1: // IBM
! 415: out = ubuf;
! 416: // Old Crawl emits useless toggles of vt100 mode, even though it
! 417: // never uses them in this mode. And they break stuff...
! 418: for (i = 0; i < cc; i++)
! 419: {
! 420: if (galt == 2) // ignore "ESC ( 0", "ESC ( B" and anything such
! 421: {
! 422: galt = 0;
! 423: continue;
! 424: }
! 425: else if (galt == 1)
! 426: if (obuf[i] == '(')
! 427: {
! 428: galt = 2;
! 429: continue;
! 430: }
! 431: else
! 432: {
! 433: galt = 0; // false alarm, emit ESC and continue
! 434: *out ++ = 27;
! 435: }
! 436: else if (obuf[i] == 27)
! 437: {
! 438: galt = 1;
! 439: continue;
! 440: }
! 441: else if (obuf[i] == 14 || obuf[i] == 15)
! 442: continue;
! 443: out += wctoutf8(out, charset_cp437[(unsigned char)obuf[i]]);
! 444: }
! 445: h.len = len = out - ubuf;
! 446: gettimeofday(&h.tv, NULL);
! 447: write(1, ubuf, len);
! 448: write_header(fscript, &h);
! 449: fwrite(ubuf, 1, len, fscript);
! 450: break;
! 451: case 2: // DEC
! 452: out = ubuf;
! 453: for (i = 0; i < cc; i++)
! 454: {
! 455: if (obuf[i] == 14)
! 456: galt = 1;
! 457: else if (obuf[i] == 15)
! 458: galt = 0;
! 459: else if (obuf[i] & 0x80) // strictly 7-bit
! 460: out += wctoutf8(out, 0xFFFD); // or we could assume some other charset
! 461: else if (galt)
! 462: out += wctoutf8(out, charset_vt100[(int)obuf[i]]);
! 463: else
! 464: *out++ = obuf[i];
! 465: }
! 466: h.len = len = out - ubuf;
! 467: gettimeofday(&h.tv, NULL);
! 468: write(1, ubuf, len);
! 469: write_header(fscript, &h);
! 470: fwrite(ubuf, 1, len, fscript);
! 471: break;
! 472: }
! 473: }
! 474: done ();
! 475: }
! 476:
! 477: void
! 478: doshell (int game, char *username)
! 479: {
! 480: getslave ();
! 481: (void) close (master);
! 482: (void) fclose (fscript);
! 483: (void) dup2 (slave, 0);
! 484: (void) dup2 (slave, 1);
! 485: (void) dup2 (slave, 2);
! 486: (void) close (slave);
! 487:
! 488: /*
! 489: if (myconfig[game]->mkdir)
! 490: (void) mkdir(myconfig[game]->mkdir, 0755);
! 491:
! 492: if (myconfig[game]->chdir)
! 493: (void) chdir(myconfig[game]->chdir);
! 494: */
! 495:
! 496: execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
! 497:
! 498: fail ();
! 499: }
! 500:
! 501: void
! 502: fixtty ()
! 503: {
! 504: struct termios rtt;
! 505:
! 506: rtt = tt;
! 507: rtt.c_iflag = 0;
! 508: rtt.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
! 509: rtt.c_oflag = OPOST;
! 510: rtt.c_cc[VINTR] = _POSIX_VDISABLE;
! 511: rtt.c_cc[VQUIT] = _POSIX_VDISABLE;
! 512: rtt.c_cc[VERASE] = _POSIX_VDISABLE;
! 513: rtt.c_cc[VKILL] = _POSIX_VDISABLE;
! 514: rtt.c_cc[VEOF] = 1;
! 515: rtt.c_cc[VEOL] = 0;
! 516: rtt.c_cc[VMIN] = 1;
! 517: rtt.c_cc[VTIME] = 0;
! 518: (void) tcsetattr (0, TCSAFLUSH, &rtt);
! 519: }
! 520:
! 521: void
! 522: fail ()
! 523: {
! 524:
! 525: (void) kill (0, SIGTERM);
! 526: done ();
! 527: }
! 528:
! 529: void
! 530: done ()
! 531: {
! 532: time_t tvec, time ();
! 533: char *ctime ();
! 534:
! 535: if (subchild)
! 536: {
! 537: tvec = time ((time_t *) NULL);
! 538: (void) fclose (fscript);
! 539: (void) close (master);
! 540: }
! 541: else
! 542: {
! 543: (void) tcsetattr (0, TCSAFLUSH, &tt);
! 544: }
! 545:
! 546: remove_ipfile();
! 547: graceful_exit (0);
! 548: }
! 549:
! 550: void
! 551: getslave ()
! 552: {
! 553: (void) setsid ();
! 554: /* grantpt( master);
! 555: unlockpt(master);
! 556: if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
! 557: perror((const char *)ptsname(master));
! 558: fail();
! 559: perror("open(fd, O_RDWR)");
! 560: fail();
! 561: } */
! 562: #ifndef NOSTREAMS
! 563: if (isastream (slave))
! 564: {
! 565: if (ioctl (slave, I_PUSH, "ptem") < 0)
! 566: {
! 567: perror ("ioctl(fd, I_PUSH, ptem)");
! 568: fail ();
! 569: }
! 570: if (ioctl (slave, I_PUSH, "ldterm") < 0)
! 571: {
! 572: perror ("ioctl(fd, I_PUSH, ldterm)");
! 573: fail ();
! 574: }
! 575: #ifndef _HPUX_SOURCE
! 576: if (ioctl (slave, I_PUSH, "ttcompat") < 0)
! 577: {
! 578: perror ("ioctl(fd, I_PUSH, ttcompat)");
! 579: fail ();
! 580: }
! 581: #endif
! 582: }
! 583: #endif /* !NOSTREAMS */
! 584: (void) ioctl (0, TIOCGWINSZ, (char *) &win);
! 585: }
! 586:
! 587: void
! 588: remove_ipfile (void)
! 589: {
! 590: if (ipfile != NULL) {
! 591: unlink (ipfile);
! 592: free(ipfile);
! 593: ipfile = NULL;
! 594: }
! 595: signal(SIGALRM, SIG_IGN);
! 596: }
! 597:
! 598: int encoding_by_name(const char *enc)
! 599: {
! 600: if (!strcasecmp(enc, "UTF-8") || !strcasecmp(enc, "UNICODE"))
! 601: return 0;
! 602: if (!strcasecmp(enc, "IBM") || !strcasecmp(enc, "CP437"))
! 603: return 1;
! 604: if (!strcasecmp(enc, "DEC"))
! 605: return 2;
! 606: if (!strcasecmp(enc, "ASCII"))
! 607: return 1; // what to do with invalid chars?
! 608: return -1;
! 609: }
! 610:
! 611: static void call_print_charset(char *exe, char **args)
! 612: {
! 613: char **args2, **a;
! 614: int nargs = 0;
! 615: for (args2 = args; *args2; args2++)
! 616: nargs++;
! 617: args2 = calloc(nargs + 1, sizeof(char*));
! 618: for (a = args2; *args; args++)
! 619: *a++ = *args;
! 620:
! 621: *a++ = "--print-charset";
! 622: *a = 0;
! 623: execvp(exe, args2);
! 624: }
! 625:
! 626: static void query_encoding(int game, char *username)
! 627: {
! 628: int son;
! 629: int p[2];
! 630: int null;
! 631: struct timeval tv;
! 632: fd_set se;
! 633: char buf[128];
! 634:
! 635: if (pipe(p))
! 636: perror("pipe");
! 637: switch(son = fork())
! 638: {
! 639: case -1:
! 640: perror("fork");
! 641: fail();
! 642: case 0:
! 643: null = open("/dev/null", O_RDONLY);
! 644: if (null != -1)
! 645: dup2(null, 0), close(null);
! 646: else
! 647: {
! 648: fprintf(stderr, "Error: can't open /dev/null\n");
! 649: // non-fatal, but if the child opens some other file, it might
! 650: // get confused
! 651: close(0);
! 652: }
! 653: dup2(p[1], 1);
! 654: close(p[1]);
! 655: close(p[0]);
! 656: call_print_charset(myconfig[game]->game_path, myconfig[game]->bin_args);
! 657: exit(1);
! 658: }
! 659: close(p[1]);
! 660:
! 661: FD_ZERO(&se);
! 662: FD_SET(p[0],&se);
! 663: tv.tv_sec = 60; // FIXME: a huge delay, in case there's a db rebuild
! 664: tv.tv_usec = 0;
! 665: if (select(p[0]+1,&se,NULL,NULL,&tv) != 1)
! 666: {
! 667: fprintf(stderr, "Error: can't obtain charset info.\nPress any key...\n");
! 668: read(0, buf, 1);
! 669: close(p[0]); // SIGPIPE
! 670: kill(son, SIGTERM); // and SIGTERM for a good measure
! 671: waitpid(son, 0, 0);
! 672: ancient_encoding = 0;
! 673: return;
! 674: }
! 675:
! 676: // Sending _one_ short message over a pipe is atomic on all systems I know.
! 677: // Don't assume this on about any other file descriptor.
! 678: read(p[0], buf, sizeof(buf)-1);
! 679: buf[sizeof(buf)-1] = 0;
! 680: close(p[0]);
! 681: kill(son, SIGTERM);
! 682: waitpid(son, 0, 0);
! 683: if (strchr(buf, '\n'))
! 684: *strchr(buf, '\n') = 0;
! 685: ancient_encoding = encoding_by_name(buf);
! 686: if (ancient_encoding == -1)
! 687: {
! 688: fprintf(stderr, "Error: unknown encoding \"%s\"\nPress any key...\n", buf);
! 689: read(0, buf, 1);
! 690: }
! 691: }
CVSweb