[BACK]Return to ttyrec.c CVS log [TXT][DIR] Up to [contributed] / dgamelaunch-openbsd

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