Annotation of sbbs/sbbs3/xtrn.cpp, revision 1.1.1.2

1.1       root        1: /* xtrn.cpp */
                      2: 
                      3: /* Synchronet external program support routines */
                      4: 
1.1.1.2 ! root        5: /* $Id: xtrn.cpp,v 1.173 2004/12/12 09:25:08 deuce Exp $ */
1.1       root        6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       12:  *                                                                                                                                                     *
                     13:  * This program is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU General Public License                         *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU General Public License for more details: gpl.txt or                     *
                     18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include "sbbs.h"
                     39: #include "cmdshell.h"
                     40: #include "telnet.h"
                     41: 
1.1.1.2 ! root       42: #include <signal.h>                    // kill()
        !            43: 
1.1       root       44: #ifdef __unix__
                     45:        #include <sys/wait.h>   // WEXITSTATUS
1.1.1.2 ! root       46: 
        !            47:        #define TTYDEFCHARS             // needed for ttydefchars definition
        !            48: 
        !            49: #if defined(__FreeBSD__)
        !            50:        #include <libutil.h>    // forkpty()
        !            51: #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DARWIN__)
        !            52:        #include <util.h>
        !            53: #elif defined(__linux__)
        !            54:        #include <pty.h>
        !            55: #elif defined(__QNX__)
        !            56: #if 0
        !            57:        #include <unix.h>
        !            58: #else
        !            59:        #define NEEDS_FORKPTY
        !            60: #endif
        !            61: #endif
        !            62: 
        !            63:        #ifdef NEEDS_FORKPTY
        !            64:        #include <grp.h>
        !            65:        #endif
        !            66: 
        !            67:        #include <termios.h>
        !            68: 
        !            69: /*
        !            70:  * Control Character Defaults
        !            71:  */
        !            72: #ifndef CTRL
        !            73:        #define CTRL(x) (x&037)
        !            74: #endif
        !            75: #ifndef CEOF
        !            76:        #define CEOF            CTRL('d')
        !            77: #endif
        !            78: #ifndef CEOL
        !            79:        #define CEOL            0xff            /* XXX avoid _POSIX_VDISABLE */
        !            80: #endif
        !            81: #ifndef CERASE
        !            82:        #define CERASE          0177
        !            83: #endif
        !            84: #ifndef CERASE2
        !            85:        #define CERASE2         CTRL('h')
        !            86: #endif
        !            87: #ifndef CINTR
        !            88:        #define CINTR           CTRL('c')
        !            89: #endif
        !            90: #ifndef CSTATUS
        !            91:        #define CSTATUS         CTRL('t')
        !            92: #endif
        !            93: #ifndef CKILL
        !            94:        #define CKILL           CTRL('u')
        !            95: #endif
        !            96: #ifndef CMIN
        !            97:        #define CMIN            1
        !            98: #endif
        !            99: #ifndef CQUIT
        !           100:        #define CQUIT           034             /* FS, ^\ */
        !           101: #endif
        !           102: #ifndef CSUSP
        !           103:        #define CSUSP           CTRL('z')
        !           104: #endif
        !           105: #ifndef CTIME
        !           106:        #define CTIME           0
        !           107: #endif
        !           108: #ifndef CDSUSP
        !           109:        #define CDSUSP          CTRL('y')
        !           110: #endif
        !           111: #ifndef CSTART
        !           112:        #define CSTART          CTRL('q')
        !           113: #endif
        !           114: #ifndef CSTOP
        !           115:        #define CSTOP           CTRL('s')
        !           116: #endif
        !           117: #ifndef CLNEXT
        !           118:        #define CLNEXT          CTRL('v')
        !           119: #endif
        !           120: #ifndef CDISCARD
        !           121:        #define CDISCARD        CTRL('o')
        !           122: #endif
        !           123: #ifndef CWERASE
        !           124:        #define CWERASE         CTRL('w')
        !           125: #endif
        !           126: #ifndef CREPRINT
        !           127:        #define CREPRINT        CTRL('r')
        !           128: #endif
        !           129: #ifndef CEOT
        !           130:        #define CEOT            CEOF
        !           131: #endif
        !           132: /* compat */
        !           133: #ifndef CBRK
        !           134:        #define CBRK            CEOL
        !           135: #endif
        !           136: #ifndef CRPRNT
        !           137:        #define CRPRNT          CREPRINT
        !           138: #endif
        !           139: #ifndef CFLUSH
        !           140:        #define CFLUSH          CDISCARD
1.1       root      141: #endif
                    142: 
1.1.1.2 ! root      143: #ifndef TTYDEF_IFLAG
        !           144:        #define TTYDEF_IFLAG    (BRKINT | ICRNL | IMAXBEL | IXON | IXANY)
        !           145: #endif
        !           146: #ifndef TTYDEF_OFLAG
        !           147:        #define TTYDEF_OFLAG    (OPOST | ONLCR)
        !           148: #endif
        !           149: #ifndef TTYDEF_LFLAG
        !           150:        #define TTYDEF_LFLAG    (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL)
        !           151: #endif
        !           152: #ifndef TTYDEF_CFLAG
        !           153:        #define TTYDEF_CFLAG    (CREAD | CS8 | HUPCL)
        !           154: #endif
        !           155: #if defined(__QNX__) || defined(__solaris__) || defined(__NetBSD__)
        !           156:        static cc_t     ttydefchars[NCCS] = {
        !           157:         CEOF,   CEOL,   CEOL,   CERASE, CWERASE, CKILL, CREPRINT,
        !           158:         CERASE2, CINTR, CQUIT,  CSUSP,  CDSUSP, CSTART, CSTOP,  CLNEXT,
        !           159:         CDISCARD, CMIN, CTIME,  CSTATUS
        !           160: #ifndef __solaris__
        !           161:        , _POSIX_VDISABLE
        !           162: #endif
        !           163:        };
        !           164: #endif
        !           165: 
        !           166: #endif /* __unix__ */
        !           167: 
        !           168: #define XTRN_IO_BUF_LEN 10000  /* 50% of IO_THREAD_BUF_SIZE */
        !           169: 
1.1       root      170: /*****************************************************************************/
                    171: /* Interrupt routine to expand WWIV Ctrl-C# codes into ANSI escape sequences */
                    172: /*****************************************************************************/
                    173: BYTE* wwiv_expand(BYTE* buf, ulong buflen, BYTE* outbuf, ulong& newlen
                    174:        ,ulong user_misc, bool& ctrl_c)
                    175: {
                    176:     char       ansi_seq[32];
                    177:        ulong   i,j,k;
                    178: 
                    179:     for(i=j=0;i<buflen;i++) {
1.1.1.2 ! root      180:         if(buf[i]==CTRL_C) {   /* WWIV color escape char */
1.1       root      181:             ctrl_c=true;
                    182:             continue;
                    183:         }
                    184:         if(!ctrl_c) {
                    185:             outbuf[j++]=buf[i];
                    186:             continue;
                    187:         }
                    188:         ctrl_c=false;
                    189:         if(user_misc&ANSI) {
                    190:             switch(buf[i]) {
                    191:                 default:
                    192:                     strcpy(ansi_seq,"\x1b[0m");          /* low grey */
                    193:                     break;
                    194:                 case '1':
                    195:                     strcpy(ansi_seq,"\x1b[0;1;36m");     /* high cyan */
                    196:                     break;
                    197:                 case '2':
                    198:                     strcpy(ansi_seq,"\x1b[0;1;33m");     /* high yellow */
                    199:                     break;
                    200:                 case '3':
                    201:                     strcpy(ansi_seq,"\x1b[0;35m");       /* low magenta */
                    202:                     break;
                    203:                 case '4':
                    204:                     strcpy(ansi_seq,"\x1b[0;1;44m");     /* white on blue */
                    205:                     break;
                    206:                 case '5':
                    207:                     strcpy(ansi_seq,"\x1b[0;32m");       /* low green */
                    208:                     break;
                    209:                 case '6':
                    210:                     strcpy(ansi_seq,"\x1b[0;1;5;31m");   /* high blinking red */
                    211:                     break;
                    212:                 case '7':
                    213:                     strcpy(ansi_seq,"\x1b[0;1;34m");     /* high blue */
                    214:                     break;
                    215:                 case '8':
                    216:                     strcpy(ansi_seq,"\x1b[0;34m");       /* low blue */
                    217:                     break;
                    218:                 case '9':
                    219:                     strcpy(ansi_seq,"\x1b[0;36m");       /* low cyan */
                    220:                     break;
                    221:             }
                    222:             for(k=0;ansi_seq[k];k++)
                    223:                 outbuf[j++]=ansi_seq[k];
                    224:         }
                    225:     }
                    226:     newlen=j;
                    227:     return(outbuf);
                    228: }
                    229: 
                    230: /*****************************************************************************/
                    231: // Escapes Telnet IAC (255) by doubling the IAC char
                    232: /*****************************************************************************/
1.1.1.2 ! root      233: BYTE* telnet_expand(BYTE* inbuf, ulong inlen, BYTE* outbuf, ulong& newlen)
1.1       root      234: {
                    235:        BYTE*   first_iac;
                    236:        ulong   i,outlen;
                    237: 
                    238:     first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
                    239: 
1.1.1.2 ! root      240:        if(first_iac==NULL) {   /* Nothing to expand */
1.1       root      241:                newlen=inlen;
                    242:                return(inbuf);
                    243:        }
                    244: 
1.1.1.2 ! root      245:        outlen=first_iac-inbuf;
        !           246:        memcpy(outbuf, inbuf, outlen);
1.1       root      247: 
                    248:     for(i=outlen;i<inlen;i++) {
                    249:                if(inbuf[i]==TELNET_IAC)
1.1.1.2 ! root      250:                        outbuf[outlen++]=TELNET_IAC;
1.1       root      251:                outbuf[outlen++]=inbuf[i];
                    252:        }
                    253:     newlen=outlen;
                    254:     return(outbuf);
                    255: }
                    256: 
1.1.1.2 ! root      257: #define XTRN_LOADABLE_MODULE                                                           \
        !           258:        if(cmdline[0]=='*') {   /* Baja module or JavaScript */ \
        !           259:                SAFECOPY(str,cmdline+1);                                                        \
        !           260:                p=strchr(str,' ');                                                                      \
        !           261:                if(p) {                                                                                         \
        !           262:                        strcpy(main_csi.str,p+1);                                               \
        !           263:                        *p=0;                                                                                   \
        !           264:                } else                                                                                          \
        !           265:                        main_csi.str[0]=0;                                                              \
        !           266:                if(!strchr(str,'.'))                                                            \
        !           267:                        strcat(str,".bin");                                                             \
        !           268:                return(exec_bin(str,&main_csi));                                        \
        !           269:        }                                                                                                               
        !           270: #ifdef JAVASCRIPT
        !           271:        #define XTRN_LOADABLE_JS_MODULE                                                 \
        !           272:        if(cmdline[0]=='?')     /* JavaScript */                                \
        !           273:                return(js_execfile(cmdline+1))                                          
        !           274: #else
        !           275:        #define XTRN_LOADABLE_JS_MODULE
        !           276: #endif
1.1       root      277: 
                    278: #ifdef _WIN32
                    279: 
                    280: #include "execvxd.h"   /* Win9X FOSSIL VxD API */
                    281: 
                    282: extern SOCKET node_socket[];
                    283: 
                    284: // -------------------------------------------------------------------------
                    285: // GetAddressOfOpenVxDHandle
                    286: //
                    287: // This function returns the address of OpenVxDHandle. OpenVxDHandle is a 
                    288: // KERNEL32 function that returns a ring 0 event handle that corresponds to a
                    289: // given ring 3 event handle. The ring 0 handle can be used by VxDs to
                    290: // synchronize with the Win32 app.
                    291: //
                    292: typedef HANDLE (WINAPI *OPENVXDHANDLE)(HANDLE);
                    293: 
                    294: OPENVXDHANDLE GetAddressOfOpenVxDHandle(void)
                    295: {
1.1.1.2 ! root      296:        return((OPENVXDHANDLE)GetProcAddress(hK32, "OpenVxDHandle"));
        !           297: }
1.1       root      298: 
1.1.1.2 ! root      299: /*****************************************************************************/
        !           300: // Expands Single CR to CRLF
        !           301: /*****************************************************************************/
        !           302: BYTE* cr_expand(BYTE* inbuf, ulong inlen, BYTE* outbuf, ulong& newlen)
        !           303: {
        !           304:        ulong   i,j;
1.1       root      305: 
1.1.1.2 ! root      306:        for(i=j=0;i<inlen;i++) {
        !           307:                outbuf[j++]=inbuf[i];
        !           308:                if(inbuf[i]=='\r')
        !           309:                        outbuf[j++]='\n';
        !           310:        }
        !           311:        newlen=j;
        !           312:     return(outbuf);
1.1       root      313: }
                    314: 
1.1.1.2 ! root      315: /* Clean-up resources while preserving current LastError value */
        !           316: #define XTRN_CLEANUP                                                                                           \
        !           317:        last_error=GetLastError();                                                                              \
        !           318:     if(vxd!=INVALID_HANDLE_VALUE)              CloseHandle(vxd);                       \
        !           319:        if(rdslot!=INVALID_HANDLE_VALUE)        CloseHandle(rdslot);            \
        !           320:        if(wrslot!=INVALID_HANDLE_VALUE)        CloseHandle(wrslot);            \
        !           321:        if(start_event!=NULL)                           CloseHandle(start_event);       \
        !           322:        if(hungup_event!=NULL)                          CloseHandle(hungup_event);      \
        !           323:        ReleaseMutex(exec_mutex);                                                                               \
        !           324:        SetLastError(last_error)
        !           325: 
1.1       root      326: /****************************************************************************/
                    327: /* Runs an external program                                                                                            */
                    328: /****************************************************************************/
1.1.1.2 ! root      329: int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
1.1       root      330: {
1.1.1.2 ! root      331:        char    str[MAX_PATH+1],*p;
        !           332:        const char* p_startup_dir;
        !           333:        char    path[MAX_PATH+1];
        !           334:        char    fname[MAX_PATH+1];
        !           335:     char       fullcmdline[MAX_PATH+1];
        !           336:        char    realcmdline[MAX_PATH+1];
        !           337:        char    comspec_str[MAX_PATH+1];
        !           338:        char    title[MAX_PATH+1];
1.1       root      339:        BYTE    buf[XTRN_IO_BUF_LEN],*bp;
                    340:     BYTE       telnet_buf[XTRN_IO_BUF_LEN*2];
1.1.1.2 ! root      341:     BYTE       output_buf[XTRN_IO_BUF_LEN*2];
1.1       root      342:     BYTE       wwiv_buf[XTRN_IO_BUF_LEN*2];
                    343:     bool       wwiv_flag=false;
                    344:     bool       native=false;                   // DOS program by default
1.1.1.2 ! root      345:        bool    nt=false;                               // WinNT/2K? 
1.1       root      346:     bool       was_online=true;
1.1.1.2 ! root      347:        bool    rio_abortable_save=rio_abortable;
        !           348:        bool    use_pipes=false;        // NT-compatible console redirection
        !           349:        BOOL    processTerminated=false;
        !           350:        uint    i;
1.1       root      351:     time_t     hungup=0;
                    352:        HANDLE  vxd=INVALID_HANDLE_VALUE;
                    353:        HANDLE  rdslot=INVALID_HANDLE_VALUE;
                    354:        HANDLE  wrslot=INVALID_HANDLE_VALUE;
1.1.1.2 ! root      355:        HANDLE  start_event=NULL;
1.1       root      356:        HANDLE  hungup_event=NULL;
1.1.1.2 ! root      357:        HANDLE  rdoutpipe;
        !           358:        HANDLE  wrinpipe;
1.1       root      359:     PROCESS_INFORMATION process_info;
                    360:        DWORD   hVM;
                    361:        DWORD   rd;
                    362:     DWORD      wr;
                    363:     DWORD      len;
                    364:     DWORD      avail;
1.1.1.2 ! root      365:        DWORD   dummy;
        !           366:        DWORD   msglen;
1.1       root      367:        DWORD   retval;
                    368:        DWORD   last_error;
                    369:        DWORD   loop_since_io=0;
1.1.1.2 ! root      370:        struct  tm tm;
1.1       root      371:        sbbsexec_start_t start;
                    372:        OPENVXDHANDLE OpenVxDHandle;
                    373: 
1.1.1.2 ! root      374:        if(online==ON_LOCAL)
        !           375:                eprintf(LOG_INFO,"Executing external: %s",cmdline);
        !           376: 
        !           377:        XTRN_LOADABLE_MODULE;
        !           378:        XTRN_LOADABLE_JS_MODULE;
        !           379: 
        !           380:        attr(cfg.color[clr_external]);          /* setup default attributes */
        !           381: 
        !           382:     SAFECOPY(str,cmdline);                             /* Set str to program name only */
        !           383:        truncstr(str," ");
        !           384:     SAFECOPY(fname,getfname(str));
1.1       root      385: 
                    386:     for(i=0;i<cfg.total_natvpgms;i++)
1.1.1.2 ! root      387:         if(!stricmp(fname,cfg.natvpgm[i]->name))
1.1       root      388:             break;
                    389:     if(i<cfg.total_natvpgms || mode&EX_NATIVE)
                    390:         native=true;
                    391: 
1.1.1.2 ! root      392:        if(mode&EX_SH || strcspn(cmdline,"<>|")!=strlen(cmdline)) 
1.1       root      393:                sprintf(comspec_str,"%s /C ", comspec);
                    394:        else
                    395:                comspec_str[0]=0;
                    396: 
                    397:     if(startup_dir && cmdline[1]!=':' && cmdline[0]!='/'
                    398:        && cmdline[0]!='\\' && cmdline[0]!='.')
                    399:                sprintf(fullcmdline, "%s%s%s", comspec_str, startup_dir, cmdline);
                    400:     else
                    401:        sprintf(fullcmdline, "%s%s", comspec_str, cmdline);
                    402: 
1.1.1.2 ! root      403:        SAFECOPY(realcmdline, fullcmdline);     // for errormsg if failed to execute
1.1       root      404: 
                    405:        now=time(NULL);
1.1.1.2 ! root      406:        if(localtime_r(&now,&tm)==NULL)
        !           407:                memset(&tm,0,sizeof(tm));
        !           408: 
        !           409:        OpenVxDHandle=GetAddressOfOpenVxDHandle();
        !           410: 
        !           411:        if(OpenVxDHandle==NULL) 
        !           412:                nt=true;        // Windows NT/2000
        !           413: 
        !           414:        if(!nt && !native && !(cfg.xtrn_misc&XTRN_NO_MUTEX)
        !           415:                && (retval=WaitForSingleObject(exec_mutex,5000))!=WAIT_OBJECT_0) {
        !           416:                errormsg(WHERE, ERR_TIMEOUT, "exec_mutex", retval);
        !           417:                return(GetLastError());
        !           418:        }
        !           419: 
        !           420:        if(native && mode&EX_OUTR && !(mode&EX_OFFLINE))
        !           421:                use_pipes=true;
1.1       root      422: 
                    423:        if(native) { // Native (32-bit) external
                    424: 
                    425:                // Current environment passed to child process
                    426:                sprintf(dszlog,"DSZLOG=%sPROTOCOL.LOG",cfg.node_dir);
                    427:                sprintf(sbbsnode,"SBBSNODE=%s",cfg.node_dir);
1.1.1.2 ! root      428:                sprintf(sbbsctrl,"SBBSCTRL=%s",cfg.ctrl_dir);
        !           429:                sprintf(sbbsdata,"SBBSDATA=%s",cfg.data_dir);
        !           430:                sprintf(sbbsexec,"SBBSEXEC=%s",cfg.exec_dir);
1.1       root      431:                sprintf(sbbsnnum,"SBBSNNUM=%d",cfg.node_num);
1.1.1.2 ! root      432:                putenv(dszlog);                 /* Makes the DSZ LOG active */
        !           433:                putenv(sbbsnode);
        !           434:                putenv(sbbsctrl);
        !           435:                putenv(sbbsdata);
        !           436:                putenv(sbbsexec);
        !           437:                putenv(sbbsnnum);
        !           438:                /* date/time env vars */
        !           439:                sprintf(env_day                 ,"DAY=%02u"                     ,tm.tm_mday);
        !           440:                sprintf(env_weekday             ,"WEEKDAY=%s"           ,wday[tm.tm_wday]);
        !           441:                sprintf(env_monthname   ,"MONTHNAME=%s"         ,mon[tm.tm_mon]);
        !           442:                sprintf(env_month               ,"MONTH=%02u"           ,tm.tm_mon+1);
        !           443:                sprintf(env_year                ,"YEAR=%u"                      ,1900+tm.tm_year);
        !           444:                putenv(env_day);
        !           445:                putenv(env_weekday);
        !           446:                putenv(env_monthname);
        !           447:                putenv(env_month);
        !           448:                if(putenv(env_year))
        !           449:                errormsg(WHERE,ERR_WRITE,"environment",0);
1.1       root      450: 
                    451:     } else { // DOS external
                    452: 
1.1.1.2 ! root      453:                sprintf(path,"%sDOSXTRN.RET", cfg.node_dir);
        !           454:                remove(path);
1.1       root      455: 
                    456:        // Create temporary environment file
1.1.1.2 ! root      457:        sprintf(path,"%sDOSXTRN.ENV", cfg.node_dir);
        !           458:         FILE* fp=fopen(path,"w");
1.1       root      459:         if(fp==NULL) {
1.1.1.2 ! root      460:                        XTRN_CLEANUP;
        !           461:                errormsg(WHERE, ERR_CREATE, path, 0);
        !           462:             return(errno);
1.1       root      463:         }
                    464:         fprintf(fp, "%s\n", fullcmdline);
                    465:                fprintf(fp, "DSZLOG=%sPROTOCOL.LOG\n", cfg.node_dir);
                    466:         fprintf(fp, "SBBSNODE=%s\n", cfg.node_dir);
1.1.1.2 ! root      467:         fprintf(fp, "SBBSCTRL=%s\n", cfg.ctrl_dir);
        !           468:                fprintf(fp, "SBBSDATA=%s\n", cfg.data_dir);
        !           469:                fprintf(fp, "SBBSEXEC=%s\n", cfg.exec_dir);
1.1       root      470:         fprintf(fp, "SBBSNNUM=%d\n", cfg.node_num);
1.1.1.2 ! root      471:                /* date/time env vars */
        !           472:                fprintf(fp, "DAY=%02u\n", tm.tm_mday);
        !           473:                fprintf(fp, "WEEKDAY=%s\n",wday[tm.tm_wday]);
        !           474:                fprintf(fp, "MONTHNAME=%s\n",mon[tm.tm_mon]);
        !           475:                fprintf(fp, "MONTH=%02u\n",tm.tm_mon+1);
        !           476:                fprintf(fp, "YEAR=%u\n",1900+tm.tm_year);
1.1       root      477:         fclose(fp);
                    478: 
1.1.1.2 ! root      479:                SAFECOPY(str,path);     // incase GetShortPathName fails
        !           480:                GetShortPathName(path,str,sizeof(str));
1.1       root      481:         sprintf(fullcmdline, "%sDOSXTRN.EXE %s", cfg.exec_dir, str);
                    482: 
1.1.1.2 ! root      483:                if(!(mode&EX_OFFLINE) && nt) {  // Windows NT/2000
1.1       root      484:                        i=SBBSEXEC_MODE_FOSSIL;
                    485:                        if(mode&EX_INR)
                    486:                        i|=SBBSEXEC_MODE_DOS_IN;
                    487:                        if(mode&EX_OUTR)
                    488:                        i|=SBBSEXEC_MODE_DOS_OUT;
1.1.1.2 ! root      489:                        sprintf(str," NT %u %u %u"
        !           490:                                ,cfg.node_num,i,startup->xtrn_polls_before_yield);
1.1       root      491:                        strcat(fullcmdline,str);
                    492: 
                    493:                        sprintf(str,"sbbsexec_hungup%d",cfg.node_num);
                    494:                        if((hungup_event=CreateEvent(
                    495:                                 NULL   // pointer to security attributes
                    496:                                ,TRUE   // flag for manual-reset event
                    497:                                ,FALSE  // flag for initial state
                    498:                                ,str    // pointer to event-object name
                    499:                                ))==NULL) {
1.1.1.2 ! root      500:                                XTRN_CLEANUP;
        !           501:                                errormsg(WHERE, ERR_CREATE, str, 0);
1.1       root      502:                                return(GetLastError());
                    503:                        }
                    504: 
                    505:                        sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d"
                    506:                                ,cfg.node_num);
                    507:                        rdslot=CreateMailslot(str
1.1.1.2 ! root      508:                                ,sizeof(buf)/2                  // Maximum message size (0=unlimited)
1.1       root      509:                                ,0                                              // Read time-out
                    510:                                ,NULL);                 // Security
                    511:                        if(rdslot==INVALID_HANDLE_VALUE) {
1.1.1.2 ! root      512:                                XTRN_CLEANUP;
1.1       root      513:                                errormsg(WHERE, ERR_CREATE, str, 0);
                    514:                                return(GetLastError());
                    515:                        }
                    516:                }
                    517:                else if(!(mode&EX_OFFLINE)) {
                    518: 
                    519:                        // Load vxd to intercept interrupts
                    520: 
                    521:                        sprintf(str,"\\\\.\\%s%s",cfg.exec_dir, SBBSEXEC_VXD);
                    522:                        if((vxd=CreateFile(str,0,0,0
                    523:                                ,CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE,0))
                    524:                                 ==INVALID_HANDLE_VALUE) {
1.1.1.2 ! root      525:                                XTRN_CLEANUP;
1.1       root      526:                                errormsg(WHERE, ERR_OPEN, str, 0);
                    527:                                return(GetLastError());
                    528:                        }
                    529: 
                    530:                        if((start_event=CreateEvent(
                    531:                                 NULL   // pointer to security attributes
                    532:                                ,TRUE   // flag for manual-reset event
                    533:                                ,FALSE  // flag for initial state
                    534:                                ,NULL   // pointer to event-object name
                    535:                                ))==NULL) {
1.1.1.2 ! root      536:                                XTRN_CLEANUP;
1.1       root      537:                                errormsg(WHERE, ERR_CREATE, "exec start event", 0);
                    538:                                return(GetLastError());
                    539:                        }
                    540: 
                    541:                        if(OpenVxDHandle!=NULL)
                    542:                                start.event=OpenVxDHandle(start_event);
                    543:                        else
                    544:                                start.event=start_event;
                    545: 
                    546:                        start.mode=SBBSEXEC_MODE_FOSSIL;
                    547:                        if(mode&EX_INR)
                    548:                        start.mode|=SBBSEXEC_MODE_DOS_IN;
                    549:                        if(mode&EX_OUTR)
                    550:                        start.mode|=SBBSEXEC_MODE_DOS_OUT;
                    551: 
1.1.1.2 ! root      552:                        sprintf(str," 95 %u %u %u"
        !           553:                                ,cfg.node_num,start.mode,startup->xtrn_polls_before_yield);
        !           554:                        strcat(fullcmdline,str);
        !           555: 
1.1       root      556:                        if(!DeviceIoControl(
                    557:                                vxd,                                    // handle to device of interest
                    558:                                SBBSEXEC_IOCTL_START,   // control code of operation to perform
                    559:                                &start,                                 // pointer to buffer to supply input data
                    560:                                sizeof(start),                  // size of input buffer
                    561:                                NULL,                                   // pointer to buffer to receive output data
                    562:                                0,                                              // size of output buffer
                    563:                                &rd,                                    // pointer to variable to receive output byte count
                    564:                                NULL                                    // Overlapped I/O
                    565:                                )) {
1.1.1.2 ! root      566:                                XTRN_CLEANUP;
1.1       root      567:                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_START);
                    568:                                return(GetLastError());
                    569:                        }
                    570:                }
                    571:     }
                    572: 
                    573:        if(startup_dir!=NULL && startup_dir[0])
                    574:                p_startup_dir=startup_dir;
                    575:        else
                    576:                p_startup_dir=NULL;
                    577:     STARTUPINFO startup_info={0};
                    578:     startup_info.cb=sizeof(startup_info);
                    579:        if(mode&EX_OFFLINE)
                    580:                startup_info.lpTitle=NULL;
                    581:        else {
                    582:                sprintf(title,"%s running %s on node %d"
                    583:                        ,useron.number ? useron.alias : "Event"
                    584:                        ,realcmdline
                    585:                        ,cfg.node_num);
                    586:                startup_info.lpTitle=title;
                    587:        }
1.1.1.2 ! root      588:     if(startup->options&BBS_OPT_XTRN_MINIMIZED) {
1.1       root      589:        startup_info.wShowWindow=SW_SHOWMINNOACTIVE;
                    590:         startup_info.dwFlags|=STARTF_USESHOWWINDOW;
                    591:     }
1.1.1.2 ! root      592:        if(use_pipes) {
        !           593:                // Set up the security attributes struct.
        !           594:                SECURITY_ATTRIBUTES sa;
        !           595:                memset(&sa,0,sizeof(sa));
        !           596:                sa.nLength= sizeof(SECURITY_ATTRIBUTES);
        !           597:                sa.lpSecurityDescriptor = NULL;
        !           598:                sa.bInheritHandle = TRUE;
        !           599: 
        !           600:                // Create the child output pipe (override default 4K buffer size)
        !           601:                if(!CreatePipe(&rdoutpipe,&startup_info.hStdOutput,&sa,sizeof(buf))) {
        !           602:                        errormsg(WHERE,ERR_CREATE,"stdout pipe",0);
        !           603:                        return(GetLastError());
        !           604:                }
        !           605:                startup_info.hStdError=startup_info.hStdOutput;
1.1       root      606: 
1.1.1.2 ! root      607:                // Create the child input pipe.
        !           608:                if(!CreatePipe(&startup_info.hStdInput,&wrinpipe,&sa,sizeof(buf))) {
        !           609:                        errormsg(WHERE,ERR_CREATE,"stdin pipe",0);
        !           610:                        return(GetLastError());
        !           611:                }
1.1       root      612: 
1.1.1.2 ! root      613:                DuplicateHandle(
        !           614:                        GetCurrentProcess(), rdoutpipe,
        !           615:                        GetCurrentProcess(), &rdslot, 0, FALSE, DUPLICATE_SAME_ACCESS);
        !           616: 
        !           617:                DuplicateHandle(
        !           618:                        GetCurrentProcess(), wrinpipe,
        !           619:                        GetCurrentProcess(), &wrslot, 0, FALSE, DUPLICATE_SAME_ACCESS);
        !           620: 
        !           621:                CloseHandle(rdoutpipe);
        !           622:                CloseHandle(wrinpipe);
        !           623: 
        !           624:                startup_info.dwFlags|=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
        !           625:        startup_info.wShowWindow=SW_HIDE;
        !           626:        }
        !           627:        if(native && !(mode&EX_OFFLINE)) {
        !           628: 
        !           629:                if(!(mode&EX_INR) && input_thread_running) {
        !           630:                        pthread_mutex_lock(&input_thread_mutex);
        !           631:                        input_thread_mutex_locked=true;
        !           632:                }
        !           633: 
        !           634:                if(!(mode&EX_OUTR)) {    /* Native Socket I/O program */
        !           635:                        /* Enable the Nagle algorithm */
        !           636:                        BOOL nodelay=FALSE;
        !           637:                        setsockopt(client_socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
        !           638:                }
1.1       root      639:        }
                    640: 
                    641:     if(!CreateProcess(
                    642:                NULL,                   // pointer to name of executable module
                    643:                fullcmdline,    // pointer to command line string
                    644:                NULL,                   // process security attributes
                    645:                NULL,                   // thread security attributes
1.1.1.2 ! root      646:                native && !(mode&EX_OFFLINE),                           // handle inheritance flag
        !           647:                CREATE_NEW_CONSOLE/*|CREATE_SEPARATE_WOW_VDM*/, // creation flags
1.1       root      648:         NULL,                          // pointer to new environment block
                    649:                p_startup_dir,  // pointer to current directory name
                    650:                &startup_info,  // pointer to STARTUPINFO
                    651:                &process_info   // pointer to PROCESS_INFORMATION
                    652:                )) {
1.1.1.2 ! root      653:                XTRN_CLEANUP;
        !           654:                if(input_thread_mutex_locked && input_thread_running) {
        !           655:                        pthread_mutex_unlock(&input_thread_mutex);
        !           656:                        input_thread_mutex_locked=false;
        !           657:                }
        !           658:                SetLastError(last_error);       /* Restore LastError */
1.1       root      659:         errormsg(WHERE, ERR_EXEC, realcmdline, mode);
                    660:         return(GetLastError());
                    661:     }
                    662: 
1.1.1.2 ! root      663: #if 0
        !           664:        char dbgstr[256];
        !           665:        sprintf(dbgstr,"Node %d created: hProcess %X hThread %X processID %X threadID %X\n"
        !           666:                ,cfg.node_num
        !           667:                ,process_info.hProcess 
        !           668:                ,process_info.hThread 
        !           669:                ,process_info.dwProcessId 
        !           670:                ,process_info.dwThreadId); 
        !           671:        OutputDebugString(dbgstr);
        !           672: #endif
        !           673: 
        !           674:        CloseHandle(process_info.hThread);
        !           675: 
1.1       root      676:        if(!native) {
                    677: 
                    678:                if(!(mode&EX_OFFLINE) && !nt) {
                    679:                // Wait for notification from VXD that new VM has started
                    680:                        if((retval=WaitForSingleObject(start_event, 5000))!=WAIT_OBJECT_0) {
1.1.1.2 ! root      681:                                XTRN_CLEANUP;
        !           682:                 TerminateProcess(process_info.hProcess, __LINE__);
        !           683:                                CloseHandle(process_info.hProcess);
1.1       root      684:                                errormsg(WHERE, ERR_TIMEOUT, "start_event", retval);
                    685:                                return(GetLastError());
                    686:                        }
                    687: 
                    688:                        CloseHandle(start_event);
1.1.1.2 ! root      689:                        start_event=NULL;       /* Mark as closed */
1.1       root      690: 
                    691:                        if(!DeviceIoControl(
                    692:                                vxd,                                    // handle to device of interest
                    693:                                SBBSEXEC_IOCTL_COMPLETE,        // control code of operation to perform
                    694:                                NULL,                                   // pointer to buffer to supply input data
                    695:                                0,                                              // size of input buffer
                    696:                                &hVM,                                   // pointer to buffer to receive output data
                    697:                                sizeof(hVM),                    // size of output buffer
                    698:                                &rd,                                    // pointer to variable to receive output byte count
                    699:                                NULL                                    // Overlapped I/O
                    700:                                )) {
1.1.1.2 ! root      701:                                XTRN_CLEANUP;
        !           702:                 TerminateProcess(process_info.hProcess, __LINE__);
        !           703:                                CloseHandle(process_info.hProcess);
1.1       root      704:                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_COMPLETE);
                    705:                                return(GetLastError());
                    706:                        }
                    707:                }
                    708:        }
1.1.1.2 ! root      709:     ReleaseMutex(exec_mutex);
        !           710: 
        !           711:        /* Disable Ctrl-C checking */
        !           712:        if(!(mode&EX_OFFLINE))
        !           713:                rio_abortable=false;
1.1       root      714: 
1.1.1.2 ! root      715:     // Executing app in foreground?, monitor
1.1       root      716:     retval=STILL_ACTIVE;
1.1.1.2 ! root      717:     while(!(mode&EX_BG)) {
        !           718:                if(mode&EX_CHKTIME)
        !           719:                        gettimeleft();
1.1       root      720:         if(!online && !(mode&EX_OFFLINE)) { // Tell VXD/VDD and external that user hung-up
                    721:                if(was_online) {
1.1.1.2 ! root      722:                                sprintf(str,"%s hung-up in external program",useron.alias);
        !           723:                                logline("X!",str);
1.1       root      724:                hungup=time(NULL);
                    725:                                if(!native) {
                    726:                                        if(nt)
                    727:                                                SetEvent(hungup_event);
                    728:                                        else if(!DeviceIoControl(
                    729:                                                vxd,            // handle to device of interest
                    730:                                                SBBSEXEC_IOCTL_DISCONNECT,      // operation to perform
                    731:                                                &hVM,           // pointer to buffer to supply input data
                    732:                                                sizeof(hVM),// size of input buffer
                    733:                                                NULL,           // pointer to buffer to receive output data
                    734:                                                0,                      // size of output buffer
                    735:                                                &rd,            // pointer to variable to receive output byte count
                    736:                                                NULL            // Overlapped I/O
                    737:                                                )) {
                    738:                                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_DISCONNECT);
                    739:                                                break;
                    740:                                        }
                    741:                                }
                    742:                    was_online=false;
                    743:             }
1.1.1.2 ! root      744:             if(hungup && time(NULL)-hungup>5 && !processTerminated) {
        !           745:                                lprintf(LOG_INFO,"Node %d Terminating process from line %d",cfg.node_num,__LINE__);
        !           746:                                processTerminated=TerminateProcess(process_info.hProcess, 2112);
        !           747:                        }
1.1       root      748:         }
1.1.1.2 ! root      749:                if((native && !use_pipes) || mode&EX_OFFLINE) { 
        !           750:                        /* Monitor for process termination only */
        !           751:                        if(WaitForSingleObject(process_info.hProcess,1000)==WAIT_OBJECT_0)
        !           752:                                break;
1.1       root      753:                } else {
                    754: 
1.1.1.2 ! root      755:                        if(nt || use_pipes) {   // Windows NT/2000
1.1       root      756: 
                    757:                                /* Write to VDD */
                    758: 
                    759:                                wr=RingBufPeek(&inbuf,buf,sizeof(buf));
                    760:                                if(wr) {
1.1.1.2 ! root      761:                                        if(!use_pipes && wrslot==INVALID_HANDLE_VALUE) {
1.1       root      762:                                                sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d"
                    763:                                                        ,cfg.node_num);
                    764:                                                wrslot=CreateFile(str
                    765:                                                        ,GENERIC_WRITE
                    766:                                                        ,FILE_SHARE_READ
                    767:                                                        ,NULL
                    768:                                                        ,OPEN_EXISTING
                    769:                                                        ,FILE_ATTRIBUTE_NORMAL
                    770:                                                        ,(HANDLE) NULL);
                    771: #if 0
                    772:                                                if(wrslot==INVALID_HANDLE_VALUE) {
                    773:                                                        errormsg(WHERE,ERR_OPEN,str,0);
                    774:                                                        break;
                    775:                                                }
                    776: #endif
                    777:                                        }
1.1.1.2 ! root      778:                                        
        !           779:                                        /* CR expansion */
        !           780:                                        if(use_pipes) 
        !           781:                                                bp=cr_expand(buf,wr,output_buf,wr);
        !           782:                                        else
        !           783:                                                bp=buf;
        !           784: 
1.1       root      785:                                        if(wrslot!=INVALID_HANDLE_VALUE
1.1.1.2 ! root      786:                                                && WriteFile(wrslot,bp,wr,&len,NULL)==TRUE) {
1.1       root      787:                                                RingBufRead(&inbuf, NULL, len);
                    788:                                                wr=len;
1.1.1.2 ! root      789:                                                if(use_pipes && !(mode&EX_NOECHO)) {
        !           790:                                                        /* echo */
        !           791:                                                        RingBufWrite(&outbuf, bp, wr);
        !           792:                                                }
1.1       root      793:                                        } else          // VDD not loaded yet
                    794:                                                wr=0;
                    795:                                }
                    796: 
                    797:                                /* Read from VDD */
                    798: 
1.1.1.2 ! root      799:                                rd=0;
1.1       root      800:                                len=sizeof(buf);
1.1.1.2 ! root      801:                                avail=RingBufFree(&outbuf)/2;   // leave room for wwiv/telnet expansion
        !           802: #if 0
        !           803:                                if(avail==0)
        !           804:                                        lprintf("Node %d !output buffer full (%u bytes)"
        !           805:                                                ,cfg.node_num,RingBufFull(&outbuf));
        !           806: #endif
1.1       root      807:                                if(len>avail)
                    808:                        len=avail;
1.1.1.2 ! root      809: 
        !           810:                                while(rd<len) {
        !           811:                                        DWORD waiting=0;
        !           812: 
        !           813:                                        if(use_pipes)
        !           814:                                                PeekNamedPipe(
        !           815:                                                        rdslot,             // handle to pipe to copy from
        !           816:                                                        NULL,               // pointer to data buffer
        !           817:                                                        0,                                      // size, in bytes, of data buffer
        !           818:                                                        NULL,                           // pointer to number of bytes read
        !           819:                                                        &waiting,                       // pointer to total number of bytes available
        !           820:                                                        NULL                            // pointer to unread bytes in this message
        !           821:                                                        );
        !           822:                                        else
        !           823:                                                GetMailslotInfo(
        !           824:                                                        rdslot,                         // mailslot handle 
        !           825:                                                        NULL,                           // address of maximum message size 
        !           826:                                                        NULL,                           // address of size of next message 
        !           827:                                                        &waiting,                       // address of number of messages 
        !           828:                                                        NULL                            // address of read time-out 
        !           829:                                                        );
        !           830:                                        if(!waiting)
        !           831:                                                break;
        !           832:                                        if(ReadFile(rdslot,buf+rd,len-rd,&msglen,NULL)==FALSE || msglen<1)
        !           833:                                                break;
        !           834:                                        rd+=msglen;
        !           835:                                }
        !           836: 
        !           837:                                if(rd) {
1.1       root      838:                                        if(mode&EX_WWIV) {
                    839:                                bp=wwiv_expand(buf, rd, wwiv_buf, rd, useron.misc, wwiv_flag);
                    840:                                                if(rd>sizeof(wwiv_buf))
                    841:                                                        errorlog("WWIV_BUF OVERRUN");
1.1.1.2 ! root      842:                                        } else if(telnet_mode&TELNET_MODE_OFF) {
        !           843:                                                bp=buf;
1.1       root      844:                                        } else {
1.1.1.2 ! root      845:                                bp=telnet_expand(buf, rd, telnet_buf, rd);
1.1       root      846:                                                if(rd>sizeof(telnet_buf))
                    847:                                                        errorlog("TELNET_BUF OVERRUN");
                    848:                                        }
1.1.1.2 ! root      849:                                        if(rd>RingBufFree(&outbuf)) {
        !           850:                                                errorlog("output buffer overflow");
        !           851:                                                rd=RingBufFree(&outbuf);
        !           852:                                        }
1.1       root      853:                                        RingBufWrite(&outbuf, bp, rd);
                    854:                                }
                    855:                        } else {        // Windows 9x
                    856: 
                    857:                                /* Write to VXD */
                    858: 
                    859:                                wr=RingBufPeek(&inbuf, buf+sizeof(hVM),sizeof(buf)-sizeof(hVM));
                    860:                                if(wr) {
                    861:                                        *(DWORD*)buf=hVM;
                    862:                                        wr+=sizeof(hVM);
                    863:                                        if(!DeviceIoControl(
                    864:                                                vxd,                                    // handle to device of interest
                    865:                                                SBBSEXEC_IOCTL_WRITE,   // control code of operation to perform
                    866:                                                buf,                                    // pointer to buffer to supply input data
                    867:                                                wr,                                             // size of input buffer
                    868:                                                &rd,                                    // pointer to buffer to receive output data
                    869:                                                sizeof(rd),                             // size of output buffer
                    870:                                                &dummy,                                 // pointer to variable to receive output byte count
                    871:                                                NULL                                    // Overlapped I/O
                    872:                                                )) {
                    873:                                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_READ);
                    874:                                                break;
                    875:                                        }
                    876:                                        RingBufRead(&inbuf, NULL, rd);
                    877:                                        wr=rd;
                    878:                                }
                    879:                        /* Read from VXD */
                    880:                                rd=0;
                    881:                                len=sizeof(buf);
1.1.1.2 ! root      882:                                avail=RingBufFree(&outbuf)/2;   // leave room for wwiv/telnet expansion
        !           883: #if 0
        !           884:                                if(avail==0) 
        !           885:                                        lprintf("Node %d !output buffer full (%u bytes)"
        !           886:                                                ,cfg.node_num,RingBufFull(&outbuf));
        !           887: #endif
        !           888: 
1.1       root      889:                                if(len>avail)
                    890:                        len=avail;
1.1.1.2 ! root      891:                                if(len) {
1.1       root      892:                                        if(!DeviceIoControl(
                    893:                                                vxd,                                    // handle to device of interest
                    894:                                                SBBSEXEC_IOCTL_READ,    // control code of operation to perform
                    895:                                                &hVM,                                   // pointer to buffer to supply input data
                    896:                                                sizeof(hVM),                    // size of input buffer
                    897:                                                buf,                                    // pointer to buffer to receive output data
                    898:                                                len,                                    // size of output buffer
                    899:                                                &rd,                                    // pointer to variable to receive output byte count
                    900:                                                NULL                                    // Overlapped I/O
                    901:                                                )) {
                    902:                                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_READ);
                    903:                                                break;
                    904:                                        }
1.1.1.2 ! root      905:                                        if(mode&EX_WWIV) {
1.1       root      906:                                bp=wwiv_expand(buf, rd, wwiv_buf, rd, useron.misc, wwiv_flag);
1.1.1.2 ! root      907:                                                if(rd>sizeof(wwiv_buf))
        !           908:                                                        errorlog("WWIV_BUF OVERRUN");
        !           909:                                        } else if(telnet_mode&TELNET_MODE_OFF) {
        !           910:                                                bp=buf;
        !           911:                                        } else {
        !           912:                                bp=telnet_expand(buf, rd, telnet_buf, rd);
        !           913:                                                if(rd>sizeof(telnet_buf))
        !           914:                                                        errorlog("TELNET_BUF OVERRUN");
        !           915:                                        }
        !           916:                                        if(rd>RingBufFree(&outbuf)) {
        !           917:                                                errorlog("output buffer overflow");
        !           918:                                                rd=RingBufFree(&outbuf);
        !           919:                                        }
1.1       root      920:                                        RingBufWrite(&outbuf, bp, rd);
                    921:                                }
                    922:                        }
1.1.1.2 ! root      923: #if defined(_DEBUG) && 0
        !           924:                        if(rd>1) {
        !           925:                                sprintf(str,"Node %d read %5d bytes from xtrn", cfg.node_num, rd);
        !           926:                                OutputDebugString(str);
        !           927:                        }
        !           928: #endif
        !           929:             if((!rd && !wr) || hungup) {
        !           930: 
        !           931:                                loop_since_io++;        /* number of loop iterations with no I/O */
        !           932: 
        !           933:                                /* only check process termination after 300 milliseconds of no I/O */
        !           934:                                /* to allow for last minute reception of output from DOS programs */
        !           935:                                if(loop_since_io>=3
        !           936:                                        && WaitForSingleObject(process_info.hProcess,0)==WAIT_OBJECT_0)
        !           937:                                        break;  /* Process Terminated */
        !           938: 
        !           939:                                /* only check node for interrupt flag every 3 seconds of no I/O */
        !           940:                                if((loop_since_io%30)==0) {     
        !           941:                                        // Check if the node has been interrupted
        !           942:                                        getnodedat(cfg.node_num,&thisnode,0);
        !           943:                                        if(thisnode.misc&NODE_INTR)
1.1       root      944:                                                break;
1.1.1.2 ! root      945:                                }
        !           946: 
        !           947:                                /* only send telnet GA every 30 seconds of no I/O */
        !           948:                                if((loop_since_io%300)==0) {
        !           949: #if defined(_DEBUG)
        !           950:                                        sprintf(str,"Node %d xtrn idle\n",cfg.node_num);
        !           951:                                        OutputDebugString(str);
1.1       root      952: #endif
1.1.1.2 ! root      953:                                        // Let's make sure the socket is up
        !           954:                                        // Sending will trigger a socket d/c detection
        !           955:                                        if(!(startup->options&BBS_OPT_NO_TELNET_GA))
        !           956:                                                send_telnet_cmd(TELNET_GA,0);
1.1       root      957:                                }
1.1.1.2 ! root      958:                                sem_trywait_block(&inbuf.sem,100);
1.1       root      959:             } else
                    960:                                loop_since_io=0;
                    961:         }
                    962:        }
                    963: 
                    964:        if(!native && !(mode&EX_OFFLINE) && !nt) {
                    965:                if(!DeviceIoControl(
                    966:                        vxd,                                    // handle to device of interest
                    967:                        SBBSEXEC_IOCTL_STOP,    // control code of operation to perform
                    968:                        &hVM,                                   // pointer to buffer to supply input data
                    969:                        sizeof(hVM),                    // size of input buffer
                    970:                        NULL,                                   // pointer to buffer to receive output data
                    971:                        0,                                              // size of output buffer
                    972:                        &rd,                                    // pointer to variable to receive output byte count
                    973:                        NULL                                    // Overlapped I/O
                    974:                        )) {
                    975:                        errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_STOP);
                    976:                }
                    977:        }
                    978: 
1.1.1.2 ! root      979:     if(!(mode&EX_BG)) {                        /* !background execution */
1.1       root      980: 
1.1.1.2 ! root      981:         if(GetExitCodeProcess(process_info.hProcess, &retval)==FALSE)
        !           982:             errormsg(WHERE, ERR_CHK, "ExitCodeProcess",(DWORD)process_info.hProcess);
1.1       root      983: 
1.1.1.2 ! root      984:                if(retval==STILL_ACTIVE) {
        !           985:                        lprintf(LOG_INFO,"Node %d Terminating process from line %d",cfg.node_num,__LINE__);
        !           986:                        TerminateProcess(process_info.hProcess, GetLastError());
        !           987:                }       
1.1       root      988: 
1.1.1.2 ! root      989:                // Get return value
        !           990:                if(!native) {
        !           991:                sprintf(str,"%sDOSXTRN.RET", cfg.node_dir);
        !           992:                        FILE* fp=fopen(str,"r");
        !           993:                        if(fp!=NULL) {
        !           994:                                fscanf(fp,"%d",&retval);
        !           995:                                fclose(fp);
        !           996:                        }
        !           997:                }
        !           998:        }
1.1       root      999: 
1.1.1.2 ! root     1000:        XTRN_CLEANUP;
        !          1001:        CloseHandle(process_info.hProcess);
1.1       root     1002: 
1.1.1.2 ! root     1003:        if(!(mode&EX_OFFLINE)) {        /* !off-line execution */
        !          1004: 
        !          1005:                if(native) {
        !          1006:                        
        !          1007:                        /* Re-enable blocking (incase disabled by xtrn program) */
        !          1008:                        ulong l=0;
        !          1009:                        ioctlsocket(client_socket, FIONBIO, &l);
        !          1010: 
        !          1011:                        /* Re-set socket options */
        !          1012:                        if(set_socket_options(&cfg, client_socket, str))
        !          1013:                                lprintf(LOG_ERR,"%04d !ERROR %s",client_socket, str);
        !          1014: 
        !          1015:                        if(input_thread_mutex_locked && input_thread_running) {
        !          1016:                                pthread_mutex_unlock(&input_thread_mutex);
        !          1017:                                input_thread_mutex_locked=false;
        !          1018:                        }
1.1       root     1019:                }
                   1020: 
1.1.1.2 ! root     1021:                curatr=~0;                      // Can't guarantee current attributes
        !          1022:                attr(LIGHTGRAY);        // Force to "normal"
        !          1023: 
        !          1024:                rio_abortable=rio_abortable_save;       // Restore abortable state
        !          1025: 
        !          1026:                /* Got back to Text/NVT mode */
        !          1027:                request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
        !          1028:        }
1.1       root     1029: 
                   1030: //     lprintf("%s returned %d",realcmdline, retval);
                   1031: 
1.1.1.2 ! root     1032:        errorlevel = retval; // Baja or JS retrievable error value
        !          1033: 
1.1       root     1034:        return(retval);
                   1035: }
                   1036: 
                   1037: #else  /* !WIN32 */
                   1038: 
1.1.1.2 ! root     1039: /*****************************************************************************/
        !          1040: // Expands Unix LF to CRLF
        !          1041: /*****************************************************************************/
        !          1042: BYTE* lf_expand(BYTE* inbuf, ulong inlen, BYTE* outbuf, ulong& newlen)
1.1       root     1043: {
1.1.1.2 ! root     1044:        ulong   i,j;
        !          1045: 
        !          1046:        for(i=j=0;i<inlen;i++) {
        !          1047:                if(inbuf[i]=='\n' && (!i || inbuf[i-1]!='\r'))
        !          1048:                        outbuf[j++]='\r';
        !          1049:                outbuf[j++]=inbuf[i];
        !          1050:        }
        !          1051:        newlen=j;
        !          1052:     return(outbuf);
        !          1053: }
        !          1054: 
        !          1055: #define MAX_ARGS 1000
        !          1056: 
        !          1057: #ifdef NEEDS_SETENV
        !          1058: static int setenv(const char *name, const char *value, int overwrite)
        !          1059: {
        !          1060:        char *envstr;
        !          1061:        char *oldenv;
        !          1062:        if(overwrite || getenv(name)==NULL) {
        !          1063:                envstr=(char *)malloc(strlen(name)+strlen(value)+2);
        !          1064:                if(envstr==NULL) {
        !          1065:                        errno=ENOMEM;
        !          1066:                        return(-1);
        !          1067:                }
        !          1068:                putenv(envstr);
        !          1069:        }
        !          1070:        return(0);
        !          1071: }
        !          1072: #endif
        !          1073: 
        !          1074: #ifdef NEEDS_CFMAKERAW
        !          1075: void
        !          1076: cfmakeraw(struct termios *t)
        !          1077: {
        !          1078:        t->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
        !          1079:        t->c_oflag &= ~OPOST;
        !          1080:        t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
        !          1081:        t->c_cflag &= ~(CSIZE|PARENB);
        !          1082:        t->c_cflag |= CS8;
        !          1083: }
        !          1084: #endif
        !          1085: 
        !          1086: #ifdef NEEDS_FORKPTY
        !          1087: static int login_tty(int fd)
        !          1088: {
        !          1089:        (void) setsid();
        !          1090:        if (!isatty(fd))
        !          1091:                return (-1);
        !          1092:        (void) dup2(fd, 0);
        !          1093:        (void) dup2(fd, 1);
        !          1094:        (void) dup2(fd, 2);
        !          1095:        if (fd > 2)
        !          1096:                (void) close(fd);
        !          1097:        return (0);
        !          1098: }
        !          1099: 
        !          1100: #ifdef NEEDS_DAEMON
        !          1101: /****************************************************************************/
        !          1102: /* Daemonizes the process                                                   */
        !          1103: /****************************************************************************/
        !          1104: int
        !          1105: daemon(int nochdir, int noclose)
        !          1106: {
        !          1107:     int fd;
        !          1108: 
        !          1109:     switch (fork()) {
        !          1110:     case -1:
        !          1111:         return (-1);
        !          1112:     case 0:
        !          1113:         break;
        !          1114:     default:
        !          1115:         _exit(0);
        !          1116:     }
        !          1117: 
        !          1118:     if (setsid() == -1)
        !          1119:         return (-1);
        !          1120: 
        !          1121:     if (!nochdir)
        !          1122:         (void)chdir("/");
        !          1123: 
        !          1124:     if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
        !          1125:         (void)dup2(fd, STDIN_FILENO);
        !          1126:         (void)dup2(fd, STDOUT_FILENO);
        !          1127:         (void)dup2(fd, STDERR_FILENO);
        !          1128:         if (fd > 2)
        !          1129:             (void)close(fd);
        !          1130:     }
        !          1131:     return (0);
        !          1132: }
        !          1133: #endif
        !          1134: 
        !          1135: static int openpty(int *amaster, int *aslave, char *name, struct termios *termp, winsize *winp)
        !          1136: {
        !          1137:        char line[] = "/dev/ptyXX";
        !          1138:        const char *cp1, *cp2;
        !          1139:        int master, slave, ttygid;
        !          1140:        struct group *gr;
        !          1141: 
        !          1142:        if ((gr = getgrnam("tty")) != NULL)
        !          1143:                ttygid = gr->gr_gid;
        !          1144:        else
        !          1145:                ttygid = -1;
        !          1146: 
        !          1147:        for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
        !          1148:                line[8] = *cp1;
        !          1149:                for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
        !          1150:                        line[5] = 'p';
        !          1151:                        line[9] = *cp2;
        !          1152:                        if ((master = open(line, O_RDWR, 0)) == -1) {
        !          1153:                                if (errno == ENOENT)
        !          1154:                                        break; /* try the next pty group */
        !          1155:                        } else {
        !          1156:                                line[5] = 't';
        !          1157:                                (void) chown(line, getuid(), ttygid);
        !          1158:                                (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
        !          1159:                                /* Hrm... SunOS doesn't seem to have revoke
        !          1160:                                (void) revoke(line); */
        !          1161:                                if ((slave = open(line, O_RDWR, 0)) != -1) {
        !          1162:                                        *amaster = master;
        !          1163:                                        *aslave = slave;
        !          1164:                                        if (name)
        !          1165:                                                strcpy(name, line);
        !          1166:                                        if (termp)
        !          1167:                                                (void) tcsetattr(slave,
        !          1168:                                                        TCSAFLUSH, termp);
        !          1169:                                        if (winp)
        !          1170:                                                (void) ioctl(slave, TIOCSWINSZ,
        !          1171:                                                        (char *)winp);
        !          1172:                                        return (0);
        !          1173:                                }
        !          1174:                                (void) close(master);
        !          1175:                        }
        !          1176:                }
        !          1177:        }
        !          1178:        errno = ENOENT; /* out of ptys */
        !          1179:        return (-1);
        !          1180: }
        !          1181: 
        !          1182: static int forkpty(int *amaster, char *name, termios *termp, winsize *winp)
        !          1183: {
        !          1184:        int master, slave, pid;
        !          1185: 
        !          1186:        if (openpty(&master, &slave, name, termp, winp) == -1)
        !          1187:                return (-1);
        !          1188:        switch (pid = FORK()) {
        !          1189:        case -1:
        !          1190:                return (-1);
        !          1191:        case 0:
        !          1192:                /*
        !          1193:                 * child
        !          1194:                 */
        !          1195:                (void) close(master);
        !          1196:                login_tty(slave);
        !          1197:                return (0);
        !          1198:        }
        !          1199:        /*
        !          1200:         * parent
        !          1201:         */
        !          1202:        *amaster = master;
        !          1203:        (void) close(slave);
        !          1204:        return (pid);
        !          1205: }
        !          1206: #endif /* NEED_FORKPTY */
        !          1207: 
        !          1208: int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
        !          1209: {
        !          1210:        char    str[MAX_PATH+1];
        !          1211:        char    fname[MAX_PATH+1];
        !          1212:        char    fullpath[MAX_PATH+1];
        !          1213:        char    fullcmdline[MAX_PATH+1];
        !          1214:        char*   argv[MAX_ARGS];
1.1       root     1215:        char*   p;
1.1.1.2 ! root     1216:        BYTE*   bp;
        !          1217:        BYTE    buf[XTRN_IO_BUF_LEN];
        !          1218:     BYTE       output_buf[XTRN_IO_BUF_LEN*2];
        !          1219:        ulong   avail;
        !          1220:     ulong      output_len;
        !          1221:        bool    native=false;                   // DOS program by default
        !          1222:        bool    rio_abortable_save=rio_abortable;
1.1       root     1223:        int             i;
1.1.1.2 ! root     1224:        bool    data_waiting;
        !          1225:        int             rd;
        !          1226:        int             wr;
1.1       root     1227:        int             argc;
                   1228:        pid_t   pid;
1.1.1.2 ! root     1229:        int             in_pipe[2];
        !          1230:        int             out_pipe[2];
        !          1231:        int             err_pipe[2];
        !          1232:        fd_set ibits;
        !          1233:        int     high_fd;
        !          1234:        struct timeval timeout;
        !          1235: 
        !          1236:        if(online==ON_LOCAL)
        !          1237:                eprintf(LOG_INFO,"Executing external: %s",cmdline);
        !          1238: 
        !          1239: 
        !          1240:        XTRN_LOADABLE_MODULE;
        !          1241:        XTRN_LOADABLE_JS_MODULE;
        !          1242: 
        !          1243:        attr(cfg.color[clr_external]);  /* setup default attributes */
        !          1244: 
        !          1245:     SAFECOPY(str,cmdline);                     /* Set fname to program name only */
        !          1246:        truncstr(str," ");
        !          1247:     SAFECOPY(fname,getfname(str));
1.1       root     1248: 
                   1249:     for(i=0;i<cfg.total_natvpgms;i++)
1.1.1.2 ! root     1250:         if(!stricmp(fname,cfg.natvpgm[i]->name))
1.1       root     1251:             break;
                   1252:     if(i<cfg.total_natvpgms || mode&EX_NATIVE)
                   1253:         native=true;
                   1254: 
1.1.1.2 ! root     1255:        sprintf(fullpath,"%s%s",startup_dir,fname);
        !          1256:        if(startup_dir!=NULL && cmdline[0]!='/' && cmdline[0]!='.' && fexist(fullpath))
        !          1257:                sprintf(fullcmdline,"%s%s",startup_dir,cmdline);
        !          1258:        else
        !          1259:                SAFECOPY(fullcmdline,cmdline);
1.1       root     1260: 
                   1261:        if(native) { // Native (32-bit) external
                   1262: 
                   1263:                // Current environment passed to child process
1.1.1.2 ! root     1264:                sprintf(dszlog,"%sPROTOCOL.LOG",cfg.node_dir);
        !          1265:                setenv("DSZLOG",dszlog,1);              /* Makes the DSZ LOG active */
        !          1266:                setenv("SBBSNODE",cfg.node_dir,1);
        !          1267:                setenv("SBBSCTRL",cfg.ctrl_dir,1);
        !          1268:                setenv("SBBSDATA",cfg.data_dir,1);
        !          1269:                setenv("SBBSEXEC",cfg.exec_dir,1);
        !          1270:                sprintf(sbbsnnum,"%u",cfg.node_num);
        !          1271:                if(setenv("SBBSNNUM",sbbsnnum,1))
1.1       root     1272:                errormsg(WHERE,ERR_WRITE,"environment",0);
                   1273: 
                   1274:        } else {
1.1.1.2 ! root     1275: #if defined(__FreeBSD__)
        !          1276:                /* ToDo: This seems to work for every door except Iron Ox
        !          1277:                   ToDo: Iron Ox is unique in that it runs perfectly from
        !          1278:                   ToDo: tcsh but not at all from anywhere else, complaining
        !          1279:                   ToDo: about corrupt files.  I've ruled out the possibilty
        !          1280:                   ToDo: of it being a terminal mode issue... no other ideas
        !          1281:                   ToDo: come to mind. */
        !          1282: 
        !          1283:                FILE * doscmdrc;
        !          1284: 
        !          1285:                sprintf(str,"%s.doscmdrc",cfg.node_dir);
        !          1286:                if((doscmdrc=fopen(str,"w+"))==NULL)  {
        !          1287:                        errormsg(WHERE,ERR_CREATE,str,0);
        !          1288:                        return(-1);
        !          1289:                }
        !          1290:                if(startup_dir!=NULL && startup_dir[0])
        !          1291:                        fprintf(doscmdrc,"assign C: %s\n",startup_dir);
        !          1292:                else
        !          1293:                        fprintf(doscmdrc,"assign C: .\n");
        !          1294: 
        !          1295:                fprintf(doscmdrc,"assign D: %s\n",cfg.node_dir);
        !          1296:                SAFECOPY(str,cfg.exec_dir);
        !          1297:                if((p=strrchr(str,'/'))!=NULL)
        !          1298:                        *p=0;
        !          1299:                if((p=strrchr(str,'/'))!=NULL)
        !          1300:                        *p=0;
        !          1301:                fprintf(doscmdrc,"assign E: %s\n",str);
        !          1302:                
        !          1303:                /* setup doscmd env here */
        !          1304:                /* ToDo Note, this assumes that the BBS uses standard dir names */
        !          1305:                fprintf(doscmdrc,"DSZLOG=E:\\node%d\\PROTOCOL.LOG\n",cfg.node_num);
        !          1306:                fprintf(doscmdrc,"SBBSNODE=D:\\\n");
        !          1307:                fprintf(doscmdrc,"SBBSCTRL=E:\\ctrl\\\n");
        !          1308:                fprintf(doscmdrc,"SBBSDATA=E:\\data\\\n");
        !          1309:                fprintf(doscmdrc,"SBBSEXEC=E:\\exec\\\n");
        !          1310:                fprintf(doscmdrc,"SBBSNNUM=%d\n",cfg.node_num);
        !          1311: 
        !          1312:                fclose(doscmdrc);
        !          1313:                SAFECOPY(str,fullcmdline);
        !          1314:                sprintf(fullcmdline,"%s -F %s",startup->dosemu_path,str);
        !          1315: 
        !          1316: #elif defined(__linux__) && defined(USE_DOSEMU)
        !          1317: 
        !          1318:                /* dosemu integration  --  Ryan Underwood, <nemesis @ icequake.net> */
        !          1319: 
        !          1320:                FILE *dosemubat;
        !          1321:                int setup_override;
        !          1322:                char tok[MAX_PATH+1];
        !          1323:  
        !          1324:                char dosemuconf[MAX_PATH+1];
        !          1325:                char dosemubinloc[MAX_PATH+1];
        !          1326:                char virtualconf[75];
        !          1327:                char dosterm[15];
        !          1328:                char log_external[MAX_PATH+1];
        !          1329: 
        !          1330:                /*  on the Unix side. xtrndir is the parent of the door's startup dir. */
        !          1331:                char xtrndir[MAX_PATH+1];
        !          1332: 
        !          1333:                /*  on the DOS side.  */
        !          1334:                char xtrndir_dos[MAX_PATH+1];
        !          1335:                char ctrldir_dos[MAX_PATH+1];
        !          1336:                char datadir_dos[MAX_PATH+1];
        !          1337:                char execdir_dos[MAX_PATH+1];
        !          1338: 
        !          1339:                /* Default locations that can be overridden by 
        !          1340:                 * the sysop in emusetup.bat */
        !          1341: 
        !          1342:                const char nodedrive[] = "D:";
        !          1343:                const char xtrndrive[] = "E:";
        !          1344:                const char ctrldrive[] = "F:";
        !          1345:                const char datadrive[] = "G:";
        !          1346:                const char execdrive[] = "H:";
        !          1347: 
        !          1348:                SAFECOPY(str,startup_dir);
        !          1349:                if(*(p=lastchar(str))=='/')             /* kill trailing slash */
        !          1350:                        *p=0;
        !          1351:                if((p=strrchr(str,'/'))!=NULL)  /* kill the last element of the path */
        !          1352:                        *p=0;
        !          1353: 
        !          1354:                SAFECOPY(xtrndir,str);
        !          1355: 
        !          1356:                /* construct DOS equivalents for the unix directories */
        !          1357: 
        !          1358:                SAFECOPY(ctrldir_dos,cfg.ctrl_dir);
        !          1359:                REPLACE_CHARS(ctrldir_dos,'/','\\',p);
        !          1360: 
        !          1361:                p=lastchar(ctrldir_dos);
        !          1362:                if (*p=='\\') *p=0;
        !          1363: 
        !          1364:                SAFECOPY(datadir_dos,cfg.data_dir);
        !          1365:                REPLACE_CHARS(datadir_dos,'/','\\',p);
        !          1366: 
        !          1367:                p=lastchar(datadir_dos);
        !          1368:                if (*p=='\\') *p=0;
        !          1369: 
        !          1370:                SAFECOPY(execdir_dos,cfg.exec_dir);
        !          1371:                REPLACE_CHARS(execdir_dos,'/','\\',p);
        !          1372: 
        !          1373:                p=lastchar(execdir_dos);
        !          1374:                if (*p=='\\') *p=0;
        !          1375: 
        !          1376:                SAFECOPY(xtrndir_dos,xtrndir);
        !          1377:                REPLACE_CHARS(xtrndir_dos,'/','\\',p);
        !          1378: 
        !          1379:                /* check for existence of a dosemu.conf in the door directory.
        !          1380:                 * It is a good idea to be able to use separate configs for each
        !          1381:                 * door. */
        !          1382: 
        !          1383:                sprintf(str,"%sdosemu.conf",startup_dir);
        !          1384:                if (!fexist(str)) {
        !          1385: 
        !          1386:                /* If we can't find it in the door dir, look for a global one
        !          1387:                 * in the ctrl dir. */
        !          1388: 
        !          1389:                        sprintf(str,"%sdosemu.conf",cfg.ctrl_dir);
        !          1390:                        if (!fexist(str)) {
        !          1391: 
        !          1392:                /* If we couldn't find either, try for the system one, then
        !          1393:                 * error out. */
        !          1394:                                SAFECOPY(str,"/etc/dosemu/dosemu.conf");
        !          1395:                                if (!fexist(str)) {
        !          1396:                                
        !          1397:                                        SAFECOPY(str,"/etc/dosemu.conf");
        !          1398:                                        if (!fexist(str)) {
        !          1399:                                                errormsg(WHERE,ERR_READ,str,0);
        !          1400:                                                return(-1);
        !          1401:                                        }
        !          1402:                                        else SAFECOPY(dosemuconf,str);  /* using system conf */
        !          1403:                                }
        !          1404:                                else SAFECOPY(dosemuconf,str);  /* using system conf */
        !          1405:                        }
        !          1406:                        else SAFECOPY(dosemuconf,str);   /* using global conf */
        !          1407:                }
        !          1408:                else SAFECOPY(dosemuconf,str);  /* using door-specific conf */
        !          1409: 
        !          1410:                /* same deal for emusetup.bat. */
        !          1411: 
        !          1412:                sprintf(str,"%semusetup.bat",startup_dir);
        !          1413:                fprintf(stderr, str);
        !          1414:                if (!fexist(str)) {
        !          1415: 
        !          1416:                /* If we can't find it in the door dir, look for a global one
        !          1417:                 * in the ctrl dir. */
        !          1418: 
        !          1419:                        sprintf(str,"%semusetup.bat",cfg.ctrl_dir);
        !          1420:                        if (!fexist(str)) {
        !          1421: 
        !          1422:                /* If we couldn't find either, set an error condition. */
        !          1423:                                setup_override = -1;
        !          1424:                        }
        !          1425:                        else setup_override = 0;  /* using global bat */
        !          1426:                }
        !          1427:                else setup_override = 1;  /* using door-specific bat */
        !          1428: 
        !          1429:                /* Create the external bat here to be placed in the node dir. */
        !          1430: 
        !          1431:                sprintf(str,"%sexternal.bat",cfg.node_dir);
        !          1432:                if(!(dosemubat=fopen(str,"w+"))) {
        !          1433:                        errormsg(WHERE,ERR_CREATE,str,0);
        !          1434:                        return(-1);
        !          1435:                }
        !          1436: 
        !          1437:                fprintf(dosemubat,"@echo off\r\n");
        !          1438:                fprintf(dosemubat,"set DSZLOG=%s\\PROTOCOL.LOG\r\n",nodedrive);
        !          1439:                fprintf(dosemubat,"set SBBSNODE=%s\r\n",nodedrive);
        !          1440:                fprintf(dosemubat,"set SBBSNNUM=%d\r\n",cfg.node_num);
        !          1441:                fprintf(dosemubat,"set SBBSCTRL=%s\r\n",ctrldrive);
        !          1442:                fprintf(dosemubat,"set SBBSDATA=%s\r\n",datadrive);
        !          1443:                fprintf(dosemubat,"set SBBSEXEC=%s\r\n",execdrive);
        !          1444: 
        !          1445:                /* clear existing redirections on dos side */
        !          1446:                fprintf(dosemubat,"lredir del %s\r\nlredir del %s\r\nlredir del %s\r\nlredir del %s\r\n",xtrndrive,ctrldrive,datadrive,execdrive);
        !          1447: 
        !          1448:                /* redirect necessary drive letters to unix paths */
        !          1449:                fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",xtrndrive,xtrndir_dos);
        !          1450:                fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",ctrldrive,ctrldir_dos);
        !          1451:                fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",datadrive,datadir_dos);
        !          1452:                fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",execdrive,execdir_dos);
        !          1453: 
        !          1454:                /* change to the drive where the parent of the startup_dir is mounted */
        !          1455:                fprintf(dosemubat,"%s\r\n",xtrndrive);
        !          1456: 
        !          1457:                if(startup_dir!=NULL && startup_dir[0]) {
        !          1458: 
        !          1459:                        SAFECOPY(str,startup_dir);
        !          1460: 
        !          1461:                /* if theres a trailing slash, dump it */
        !          1462: 
        !          1463:                        p=lastchar(str);
        !          1464:                        if (*p=='/') *p=0;
        !          1465: 
        !          1466:                        if ((p=strrchr(str, '/'))!=NULL)
        !          1467:                                SAFECOPY(str,p+1);  /* str = game's starting dir */
        !          1468: 
        !          1469:                        else str[0] = '\0';
        !          1470:                }
        !          1471: 
        !          1472:                else str[0] = '\0';
        !          1473: 
        !          1474:                fprintf(dosemubat,"cd %s\r\n",str);  /* startup_dir  */
        !          1475: 
        !          1476:                if (setup_override == 1)
        !          1477:                        fprintf(dosemubat,"call %s\\%s\\emusetup.bat %s\r\n",xtrndrive,str,cmdline);
        !          1478:                else if (setup_override == 0)
        !          1479:                        fprintf(dosemubat,"call %s\\emusetup.bat\r\n",ctrldrive);
        !          1480:                /* if (setup_override == -1) do_nothing */
        !          1481: 
        !          1482:                /*  Check if it's a bat file, to prepend "call" to the command  */
        !          1483: 
        !          1484:                SAFECOPY(tok,cmdline);
        !          1485:                truncstr(tok," ");
        !          1486: 
        !          1487:                p = strstr(tok, ".bat");  /*  check if it's a bat file  */
        !          1488:                if (p)
        !          1489:                        fprintf(dosemubat,"call ");  /* if so, "call" it */
        !          1490: 
        !          1491:                fprintf(dosemubat,"%s\r\n",cmdline);
        !          1492:                fprintf(dosemubat,"exitemu\r\n");
        !          1493: 
        !          1494:                /* Check the "Stdio Interception" flag from scfg for this door.  If it's
        !          1495:                 * enabled, we enable doorway mode.  Else, it's vmodem for us, unless
        !          1496:                 * it's a timed event.
        !          1497:                 */
        !          1498: 
        !          1499:                if (!(mode&(EX_INR|EX_OUTR)) && online!=ON_LOCAL)
        !          1500:                        SAFECOPY(virtualconf,"-I\"serial { virtual com 1 }\"");
        !          1501:                else
        !          1502:                        virtualconf[0] = '\0';
        !          1503: 
        !          1504:                /* Set the interception bits, since we are always going to want Synchronet
        !          1505:                 * to intercept dos programs under Unix.
        !          1506:                 */
        !          1507: 
        !          1508:                mode |= (EX_INR|EX_OUTR);
        !          1509: 
        !          1510:                /* See if we have the dosemu link in the door's dir.  If so, use the dosemu
        !          1511:                 * that it points to as our command to execute.  If not, use DOSemuPath.
        !          1512:                 */
        !          1513:  
        !          1514:                sprintf(str,"%sdosemu.bin",startup_dir);
        !          1515:                if (!fexist(str)) {
        !          1516:                        SAFECOPY(dosemubinloc,(cmdstr(startup->dosemu_path,nulstr,nulstr,tok)));
        !          1517:                }
        !          1518:                else {
        !          1519:                        SAFECOPY(dosemubinloc,str);
        !          1520:                }
        !          1521: 
        !          1522:                /* Attempt to keep dosemu from prompting for a disclaimer. */
        !          1523: 
        !          1524:                sprintf(str, "%s/.dosemu", cfg.ctrl_dir);
        !          1525:                if (!isdir(str)) {
        !          1526:                        mkdir(str, 0755);
        !          1527:                }
        !          1528: 
        !          1529:                strcat(str, "/disclaimer");
        !          1530:                ftouch(str);
        !          1531: 
        !          1532:                /* Set up the command for dosemu to execute with 'unix -e'. */
        !          1533: 
        !          1534:                sprintf(str,"%sexternal.bat",nodedrive);
        !          1535: 
        !          1536:                /* need TERM=linux for maintenance programs to work
        !          1537:                 * (dosemu won't start with no controlling terminal)
        !          1538:                 * Also, redirect stdout to a log if it's a timed event.
        !          1539:                 */
        !          1540:                 
        !          1541:                if (online==ON_LOCAL) {
        !          1542:                        SAFECOPY(dosterm,"TERM=linux");
        !          1543:                        sprintf(log_external,">> %sdosevent_%s.log",cfg.logs_dir,fname);
        !          1544:                }
        !          1545:                else {
        !          1546:                        dosterm[0]='\0';
        !          1547:                        log_external[0] = '\0';
        !          1548:                }
        !          1549: 
        !          1550:                /* Drum roll. */
        !          1551: 
        !          1552:                sprintf(fullcmdline,
        !          1553:                "/usr/bin/env %s HOME=%s QUIET=1 DOSDRIVE_D=%s %s -I\"video { none }\" -I\"keystroke \\r\" %s -f%s -E%s -o%sdosemu.log 2> %sdosemu_boot.log %s",
        !          1554:                        dosterm,cfg.ctrl_dir,cfg.node_dir,dosemubinloc,virtualconf,dosemuconf,str,cfg.node_dir,cfg.node_dir,log_external);
        !          1555: 
        !          1556:                fprintf(dosemubat,"REM For debugging: %s\r\n",fullcmdline);
        !          1557:                fclose(dosemubat);
        !          1558: 
        !          1559: #else
        !          1560:                bprintf("\r\nExternal DOS programs are not yet supported in \r\n%s\r\n"
        !          1561:                        ,VERSION_NOTICE);
        !          1562:                return(-1);
        !          1563: #endif
1.1       root     1564:        }
                   1565: 
1.1.1.2 ! root     1566:        if(!(mode&EX_INR) && input_thread_running) {
        !          1567:                lprintf(LOG_DEBUG,"Locking input thread mutex"); 
        !          1568:                if(pthread_mutex_lock(&input_thread_mutex)!=0)
        !          1569:                        errormsg(WHERE,ERR_LOCK,"input_thread_mutex",0);
        !          1570:                input_thread_mutex_locked=true;
        !          1571:        }
1.1       root     1572: 
1.1.1.2 ! root     1573:        if(pipe(err_pipe)!=0) {
        !          1574:                errormsg(WHERE,ERR_CREATE,"err_pipe",0);
1.1       root     1575:                return(-1);
                   1576:        }
                   1577: 
1.1.1.2 ! root     1578:        if((mode&EX_INR) && (mode&EX_OUTR))  {
        !          1579:                struct winsize winsize;
        !          1580:                struct termios term;
        !          1581:                memset(&term,0,sizeof(term));
        !          1582:                cfsetispeed(&term,B19200);
        !          1583:                cfsetospeed(&term,B19200);
        !          1584:                if(mode&EX_BIN)
        !          1585:                        cfmakeraw(&term);
        !          1586:                else {
        !          1587:                        term.c_iflag = TTYDEF_IFLAG;
        !          1588:                        term.c_oflag = TTYDEF_OFLAG;
        !          1589:                        term.c_lflag = TTYDEF_LFLAG;
        !          1590:                        term.c_cflag = TTYDEF_CFLAG;
        !          1591:                        memcpy(term.c_cc,ttydefchars,sizeof(term.c_cc));
        !          1592:                }
        !          1593:                winsize.ws_row=rows;
        !          1594:                winsize.ws_col=cols;
        !          1595:                if((pid=forkpty(&in_pipe[1],NULL,&term,&winsize))==-1) {
        !          1596:                        if(input_thread_mutex_locked && input_thread_running) {
        !          1597:                                if(pthread_mutex_unlock(&input_thread_mutex)!=0)
        !          1598:                                        errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0);
        !          1599:                                input_thread_mutex_locked=false;
        !          1600:                        }
        !          1601:                        errormsg(WHERE,ERR_EXEC,fullcmdline,0);
        !          1602:                        return(-1);
        !          1603:                }
        !          1604:                out_pipe[0]=in_pipe[1];
        !          1605:        }
        !          1606:        else  {
        !          1607:                if(mode&EX_INR)
        !          1608:                        if(pipe(in_pipe)!=0) {
        !          1609:                                errormsg(WHERE,ERR_CREATE,"in_pipe",0);
        !          1610:                                return(-1);
        !          1611:                        }
        !          1612:                if(mode&EX_OUTR)
        !          1613:                        if(pipe(out_pipe)!=0) {
        !          1614:                                errormsg(WHERE,ERR_CREATE,"out_pipe",0);
        !          1615:                                return(-1);
        !          1616:                        }
        !          1617: 
        !          1618: 
        !          1619:                if((pid=FORK())==-1) {
        !          1620:                        if(input_thread_mutex_locked && input_thread_running) {
        !          1621:                                if(pthread_mutex_unlock(&input_thread_mutex)!=0)
        !          1622:                                        errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0);
        !          1623:                                input_thread_mutex_locked=false;
        !          1624:                        }
        !          1625:                        errormsg(WHERE,ERR_EXEC,fullcmdline,0);
        !          1626:                        return(-1);
        !          1627:                }
        !          1628:        }
1.1       root     1629:        if(pid==0) {    /* child process */
1.1.1.2 ! root     1630:                /* Give away all privs for good now */
        !          1631:                if(startup->setuid!=NULL)
        !          1632:                        startup->setuid(TRUE);
        !          1633: 
        !          1634:                sigset_t        sigs;
        !          1635:                sigfillset(&sigs);
        !          1636:                sigprocmask(SIG_UNBLOCK,&sigs,NULL);
        !          1637:                if(!(mode&EX_BIN))  {
        !          1638:                        static char     term_env[256];
        !          1639:                        if(useron.misc&ANSI)
        !          1640:                                sprintf(term_env,"TERM=%s",startup->xtrn_term_ansi);
        !          1641:                        else
        !          1642:                                sprintf(term_env,"TERM=%s",startup->xtrn_term_dumb);
        !          1643:                        putenv(term_env);
        !          1644:                }
        !          1645: #ifdef __FreeBSD__
        !          1646:                if(!native)
        !          1647:                        chdir(cfg.node_dir);
        !          1648:                else
        !          1649: #endif
1.1       root     1650:                if(startup_dir!=NULL && startup_dir[0])
                   1651:                        chdir(startup_dir);
                   1652: 
1.1.1.2 ! root     1653:                if(mode&EX_SH || strcspn(fullcmdline,"<>|;\"")!=strlen(fullcmdline)) {
        !          1654:                        argv[0]=comspec;
        !          1655:                        argv[1]="-c";
        !          1656:                        argv[2]=fullcmdline;
        !          1657:                        argv[3]=NULL;
        !          1658:                } else {
        !          1659:                        argv[0]=fullcmdline;    /* point to the beginning of the string */
        !          1660:                        argc=1;
        !          1661:                        for(i=0;fullcmdline[i] && argc<MAX_ARGS;i++)    /* Break up command line */
        !          1662:                                if(fullcmdline[i]==' ') {
        !          1663:                                        fullcmdline[i]=0;                       /* insert nulls */
        !          1664:                                        argv[argc++]=fullcmdline+i+1; /* point to the beginning of the next arg */
        !          1665:                                }
        !          1666:                        argv[argc]=NULL;
        !          1667:                }
1.1       root     1668: 
1.1.1.2 ! root     1669:                if(mode&EX_INR && !(mode&EX_OUTR))  {
        !          1670:                        close(in_pipe[1]);              /* close write-end of pipe */
        !          1671:                        dup2(in_pipe[0],0);             /* redirect stdin */
        !          1672:                        close(in_pipe[0]);              /* close excess file descriptor */
        !          1673:                }
        !          1674: 
        !          1675:                if(mode&EX_OUTR && !(mode&EX_INR)) {
        !          1676:                        close(out_pipe[0]);             /* close read-end of pipe */
        !          1677:                        dup2(out_pipe[1],1);    /* stdout */
        !          1678:                        /* dup2(out_pipe[1],2); stderr */
        !          1679:                        close(out_pipe[1]);             /* close excess file descriptor */
        !          1680:                }
1.1       root     1681: 
1.1.1.2 ! root     1682:                if(mode&EX_BG)  /* background execution, detach child */
        !          1683:                {
        !          1684:                        lprintf(LOG_INFO,"Detaching external process");
        !          1685:                        daemon(TRUE,FALSE);
        !          1686:            }
        !          1687: 
        !          1688:                close(err_pipe[0]);             /* close read-end of pipe */
        !          1689:                dup2(err_pipe[1],2);    /* stderr */
        !          1690:        
1.1       root     1691:                execvp(argv[0],argv);
1.1.1.2 ! root     1692:                sprintf(str,"!ERROR %d executing %s",errno,argv[0]);
        !          1693:                errorlog(str);
        !          1694:                _exit(-1);      /* should never get here */
        !          1695:        }
        !          1696: 
        !          1697:        if(online!=ON_LOCAL)
        !          1698:                lprintf(LOG_INFO,"Node %d executing external: %s",cfg.node_num,fullcmdline);
        !          1699: 
        !          1700:        /* Disable Ctrl-C checking */
        !          1701:        if(!(mode&EX_OFFLINE))
        !          1702:                rio_abortable=false;
        !          1703:        
        !          1704:        close(err_pipe[1]);     /* close write-end of pipe */
        !          1705: 
        !          1706:        if(mode&EX_OUTR) {
        !          1707:                if(!(mode&EX_INR))
        !          1708:                        close(out_pipe[1]);     /* close write-end of pipe */
        !          1709:                while(!terminated) {
        !          1710:                        if(waitpid(pid, &i, WNOHANG)!=0)        /* child exited */
        !          1711:                                break;
        !          1712: 
        !          1713:                        if(mode&EX_CHKTIME)
        !          1714:                                gettimeleft();
        !          1715:                        
        !          1716:                        if(!online && !(mode&EX_OFFLINE)) {
        !          1717:                                sprintf(str,"%s hung-up in external program",useron.alias);
        !          1718:                                logline("X!",str);
        !          1719:                                break;
        !          1720:                        }
        !          1721: 
        !          1722:                        /* Input */     
        !          1723:                        if(mode&EX_INR && RingBufFull(&inbuf)) {
        !          1724:                                if((wr=RingBufRead(&inbuf,buf,sizeof(buf)))!=0)
        !          1725:                                        write(in_pipe[1],buf,wr);
        !          1726:                        }
        !          1727:                                
        !          1728:                        /* Error Output */
        !          1729:                        FD_ZERO(&ibits);
        !          1730:                        FD_SET(err_pipe[0],&ibits);
        !          1731:                        high_fd=err_pipe[0];
        !          1732:                        FD_SET(out_pipe[0],&ibits);
        !          1733:                        if(out_pipe[0]>err_pipe[0])
        !          1734:                                high_fd=out_pipe[0];
        !          1735:                        timeout.tv_sec=0;
        !          1736:                        timeout.tv_usec=1000;
        !          1737:                        bp=buf;
        !          1738:                        i=0;
        !          1739:                        while ((select(high_fd+1,&ibits,NULL,NULL,&timeout)>0) && FD_ISSET(err_pipe[0],&ibits) && (i<(int)sizeof(buf)-1))  {
        !          1740:                                if((rd=read(err_pipe[0],bp,1))>0)  {
        !          1741:                                        i+=rd;
        !          1742:                                        bp++;
        !          1743:                                        if(*(bp-1)=='\n')
        !          1744:                                                break;
        !          1745:                                }
        !          1746:                                else
        !          1747:                                        break;
        !          1748:                                FD_ZERO(&ibits);
        !          1749:                                FD_SET(err_pipe[0],&ibits);
        !          1750:                                FD_SET(out_pipe[0],&ibits);
        !          1751:                                timeout.tv_sec=0;
        !          1752:                                timeout.tv_usec=1000;
        !          1753:                        }
        !          1754:                        if(i)
        !          1755:                                lprintf(LOG_NOTICE,"%.*s",i,buf);               /* lprintf mangles i? */
        !          1756: 
        !          1757:                        /* Eat stderr if mode is EX_BIN */
        !          1758:                        if(mode&EX_BIN)  {
        !          1759:                                bp=buf;
        !          1760:                                i=0;
        !          1761:                        }
        !          1762: 
        !          1763: #if 0
        !          1764:                        /* Output */
        !          1765:                        FD_ZERO(&ibits);
        !          1766:                        FD_SET(out_pipe[0],&ibits);
        !          1767:                        timeout.tv_sec=0;
        !          1768:                        timeout.tv_usec=1000;
        !          1769:                        data_waiting=(select(out_pipe[0]+1,&ibits,NULL,NULL,&timeout)!=0);
        !          1770: #else
        !          1771:                        data_waiting=FD_ISSET(out_pipe[0],&ibits);
        !          1772: #endif
        !          1773:                        if(i==0 && data_waiting==0)
        !          1774:                                continue;
        !          1775: 
        !          1776:                        avail=(RingBufFree(&outbuf)-i)/2;       // Leave room for wwiv/telnet expansion
        !          1777:                        if(avail==0) {
        !          1778: #if 0
        !          1779:                                lprintf("Node %d !output buffer full (%u bytes)"
        !          1780:                                                ,cfg.node_num,RingBufFull(&outbuf));
        !          1781: #endif
        !          1782:                                YIELD();
        !          1783:                                continue;
        !          1784:                        }
        !          1785: 
        !          1786:                        rd=avail;
        !          1787: 
        !          1788:                        if(rd>((int)sizeof(buf)-i))
        !          1789:                                rd=sizeof(buf)-i;
        !          1790: 
        !          1791:                        if(data_waiting)  {
        !          1792:                                rd=read(out_pipe[0],bp,rd);
        !          1793:                                if(rd<1 && i==0)
        !          1794:                                        continue;
        !          1795:                                if(rd<0)
        !          1796:                                        rd=0;
        !          1797:                        }
        !          1798:                        else
        !          1799:                                rd=0;
        !          1800: 
        !          1801:                        rd += i;
        !          1802: 
        !          1803:                        if(mode&EX_BIN) {
        !          1804:                                if(telnet_mode&TELNET_MODE_OFF)
        !          1805:                                        bp=buf;
        !          1806:                                else
        !          1807:                                bp=telnet_expand(buf, rd, output_buf, output_len);
        !          1808:                        } else                  /* LF to CRLF expansion */
        !          1809:                                bp=lf_expand(buf, rd, output_buf, output_len);
        !          1810: 
        !          1811:                        /* Did expansion overrun the output buffer? */
        !          1812:                        if(output_len>sizeof(output_buf)) {
        !          1813:                                errorlog("OUTPUT_BUF OVERRUN");
        !          1814:                                output_len=sizeof(output_buf);
        !          1815:                        }
        !          1816: 
        !          1817:                        /* Does expanded size fit in the ring buffer? */
        !          1818:                        if(output_len>RingBufFree(&outbuf)) {
        !          1819:                                errorlog("output buffer overflow");
        !          1820:                                output_len=RingBufFree(&outbuf);
        !          1821:                        }
        !          1822: 
        !          1823:                        RingBufWrite(&outbuf, bp, output_len);
        !          1824: 
        !          1825:                }
        !          1826: 
        !          1827:                if(waitpid(pid, &i, WNOHANG)==0)  {             // Child still running? 
        !          1828:                        kill(pid, SIGHUP);                                      // Tell child user has hung up
        !          1829:                        time_t start=time(NULL);                        // Wait up to 10 seconds
        !          1830:                        while(time(NULL)-start<10) {            // for child to terminate
        !          1831:                                if(waitpid(pid, &i, WNOHANG)!=0)
        !          1832:                                        break;
        !          1833:                                mswait(500);
        !          1834:                        }
        !          1835:                        if(waitpid(pid, &i, WNOHANG)==0)        // Child still running?
        !          1836:                                kill(pid, SIGKILL);                             // terminate child process
        !          1837:                }
        !          1838:                /* close unneeded descriptors */
        !          1839:                if(mode&EX_INR)
        !          1840:                        close(in_pipe[1]);
        !          1841:                close(out_pipe[0]);
        !          1842:        }
        !          1843:        else {
        !          1844:                /* Enable the Nagle algorithm */
        !          1845:                int nodelay=FALSE;
        !          1846:                setsockopt(client_socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
        !          1847:        }
        !          1848: 
        !          1849:        while(waitpid(pid, &i, WNOHANG)==0)  {
        !          1850:                FD_ZERO(&ibits);
        !          1851:                FD_SET(err_pipe[0],&ibits);
        !          1852:                timeout.tv_sec=1;
        !          1853:                timeout.tv_usec=0;
        !          1854:                bp=buf;
        !          1855:                i=0;
        !          1856:                while ((select(err_pipe[0]+1,&ibits,NULL,NULL,&timeout)>0) && (i<XTRN_IO_BUF_LEN-1))  {
        !          1857:                        if((rd=read(err_pipe[0],bp,1))>0)  {
        !          1858:                                i+=rd;
        !          1859:                                if(*bp=='\n') {
        !          1860:                                        lprintf(LOG_NOTICE,"%.*s",i-1,buf);
        !          1861:                                        i=0;
        !          1862:                                        bp=buf;
        !          1863:                                }
        !          1864:                                else
        !          1865:                                        bp++;
        !          1866:                        }
        !          1867:                        else
        !          1868:                                break;
        !          1869:                }
        !          1870:                if(i)
        !          1871:                        lprintf(LOG_NOTICE,"%.*s",i,buf);
        !          1872:        }
        !          1873: 
        !          1874:        if(!(mode&EX_OFFLINE)) {        /* !off-line execution */
        !          1875: 
        !          1876:                /* Re-enable blocking (incase disabled by xtrn program) */
        !          1877:                ulong l=0;
        !          1878:                ioctlsocket(client_socket, FIONBIO, &l);
        !          1879: 
        !          1880:                /* Re-set socket options */
        !          1881:                if(set_socket_options(&cfg, client_socket, str))
        !          1882:                        lprintf(LOG_ERR,"%04d !ERROR %s",client_socket, str);
        !          1883: 
        !          1884:                curatr=~0;                      // Can't guarantee current attributes
        !          1885:                attr(LIGHTGRAY);        // Force to "normal"
        !          1886: 
        !          1887:                rio_abortable=rio_abortable_save;       // Restore abortable state
        !          1888: 
        !          1889:                /* Got back to Text/NVT mode */
        !          1890:                request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
1.1       root     1891:        }
                   1892: 
1.1.1.2 ! root     1893:        close(err_pipe[0]);
1.1       root     1894: 
1.1.1.2 ! root     1895:        if(input_thread_mutex_locked && input_thread_running) {
        !          1896:                if(pthread_mutex_unlock(&input_thread_mutex)!=0)
        !          1897:                        errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0);
        !          1898:                input_thread_mutex_locked=false;
        !          1899:        }
1.1       root     1900: 
1.1.1.2 ! root     1901:        return(errorlevel = WEXITSTATUS(i));
1.1       root     1902: }
                   1903: 
                   1904: #endif /* !WIN32 */
                   1905: 
                   1906: uint fakeriobp=0xffff;
                   1907: 
                   1908: /*****************************************************************************/
                   1909: /* Returns command line generated from instr with %c replacments             */
                   1910: /*****************************************************************************/
1.1.1.2 ! root     1911: char* sbbs_t::cmdstr(char *instr, char *fpath, char *fspec, char *outstr)
1.1       root     1912: {
                   1913:        char    str[256],*cmd;
                   1914:     int                i,j,len;
                   1915: 
                   1916:     if(outstr==NULL)
                   1917:         cmd=cmdstr_output;
                   1918:     else
                   1919:         cmd=outstr;
                   1920:     len=strlen(instr);
1.1.1.2 ! root     1921:     for(i=j=0;i<len && j<(int)sizeof(cmdstr_output);i++) {
1.1       root     1922:         if(instr[i]=='%') {
                   1923:             i++;
                   1924:             cmd[j]=0;
1.1.1.2 ! root     1925:                        char ch=instr[i];
        !          1926:                        if(isalpha(ch))
        !          1927:                                ch=toupper(ch);
        !          1928:             switch(ch) {
1.1       root     1929:                 case 'A':   /* User alias */
                   1930:                     strcat(cmd,useron.alias);
                   1931:                     break;
                   1932:                 case 'B':   /* Baud (DTE) Rate */
                   1933:                     strcat(cmd,ultoa(dte_rate,str,10));
                   1934:                     break;
                   1935:                 case 'C':   /* Connect Description */
                   1936:                     strcat(cmd,connection);
                   1937:                     break;
                   1938:                 case 'D':   /* Connect (DCE) Rate */
                   1939:                     strcat(cmd,ultoa((ulong)cur_rate,str,10));
                   1940:                     break;
                   1941:                 case 'E':   /* Estimated Rate */
                   1942:                     strcat(cmd,ultoa((ulong)cur_cps*10,str,10));
                   1943:                     break;
                   1944:                 case 'F':   /* File path */
                   1945:                     strcat(cmd,fpath);
                   1946:                     break;
                   1947:                 case 'G':   /* Temp directory */
                   1948:                     strcat(cmd,cfg.temp_dir);
                   1949:                     break;
                   1950:                 case 'H':   /* Port Handle or Hardware Flow Control */
1.1.1.2 ! root     1951: #if defined(__unix__)
        !          1952:                                        strcat(cmd,ultoa(client_socket,str,10));
        !          1953: #else
1.1       root     1954:                     strcat(cmd,ultoa(client_socket_dup,str,10));
1.1.1.2 ! root     1955: #endif
1.1       root     1956:                     break;
1.1.1.2 ! root     1957:                 case 'I':   /* IP address */
        !          1958:                     strcat(cmd,cid);
1.1       root     1959:                     break;
                   1960:                 case 'J':
                   1961:                     strcat(cmd,cfg.data_dir);
                   1962:                     break;
                   1963:                 case 'K':
                   1964:                     strcat(cmd,cfg.ctrl_dir);
                   1965:                     break;
                   1966:                 case 'L':   /* Lines per message */
                   1967:                     strcat(cmd,ultoa(cfg.level_linespermsg[useron.level],str,10));
                   1968:                     break;
                   1969:                 case 'M':   /* Minutes (credits) for user */
                   1970:                     strcat(cmd,ultoa(useron.min,str,10));
                   1971:                     break;
                   1972:                 case 'N':   /* Node Directory (same as SBBSNODE environment var) */
                   1973:                     strcat(cmd,cfg.node_dir);
                   1974:                     break;
                   1975:                 case 'O':   /* SysOp */
                   1976:                     strcat(cmd,cfg.sys_op);
                   1977:                     break;
1.1.1.2 ! root     1978:                 case 'P':   /* Client protocol */
        !          1979:                     strcat(cmd,client.protocol);
1.1       root     1980:                     break;
                   1981:                 case 'Q':   /* QWK ID */
                   1982:                     strcat(cmd,cfg.sys_id);
                   1983:                     break;
                   1984:                 case 'R':   /* Rows */
                   1985:                     strcat(cmd,ultoa(rows,str,10));
                   1986:                     break;
                   1987:                 case 'S':   /* File Spec */
                   1988:                     strcat(cmd,fspec);
                   1989:                     break;
                   1990:                 case 'T':   /* Time left in seconds */
                   1991:                     gettimeleft();
                   1992:                     strcat(cmd,ultoa(timeleft,str,10));
                   1993:                     break;
                   1994:                 case 'U':   /* UART I/O Address (in hex) */
                   1995:                     strcat(cmd,ultoa(cfg.com_base,str,16));
                   1996:                     break;
                   1997:                 case 'V':   /* Synchronet Version */
                   1998:                     sprintf(str,"%s%c",VERSION,REVISION);
                   1999:                     break;
                   2000:                 case 'W':   /* Time-slice API type (mswtype) */
                   2001: #if 0 //ndef __FLAT__
                   2002:                     strcat(cmd,ultoa(mswtyp,str,10));
                   2003: #endif
                   2004:                     break;
                   2005:                 case 'X':
                   2006:                     strcat(cmd,cfg.shell[useron.shell]->code);
                   2007:                     break;
                   2008:                 case '&':   /* Address of msr */
1.1.1.2 ! root     2009:                     sprintf(str,"%lu",(DWORD)&fakeriobp);
1.1       root     2010:                     strcat(cmd,str);
                   2011:                     break;
                   2012:                 case 'Y':
1.1.1.2 ! root     2013:                     strcat(cmd,comspec);
1.1       root     2014:                     break;
                   2015:                 case 'Z':
                   2016:                     strcat(cmd,cfg.text_dir);
                   2017:                     break;
1.1.1.2 ! root     2018:                                case '~':       /* DOS-compatible (8.3) filename */
        !          2019: #ifdef _WIN32
        !          2020:                                        char sfpath[MAX_PATH+1];
        !          2021:                                        SAFECOPY(sfpath,fpath);
        !          2022:                                        GetShortPathName(fpath,sfpath,sizeof(sfpath));
        !          2023:                                        strcat(cmd,sfpath);
        !          2024: #else
        !          2025:                     strcat(cmd,fpath);
        !          2026: #endif                 
        !          2027:                                        break;
1.1       root     2028:                 case '!':   /* EXEC Directory */
                   2029:                     strcat(cmd,cfg.exec_dir);
                   2030:                     break;
                   2031:                 case '#':   /* Node number (same as SBBSNNUM environment var) */
                   2032:                     sprintf(str,"%d",cfg.node_num);
                   2033:                     strcat(cmd,str);
                   2034:                     break;
                   2035:                 case '*':
                   2036:                     sprintf(str,"%03d",cfg.node_num);
                   2037:                     strcat(cmd,str);
                   2038:                     break;
                   2039:                 case '$':   /* Credits */
                   2040:                     strcat(cmd,ultoa(useron.cdt+useron.freecdt,str,10));
                   2041:                     break;
                   2042:                 case '%':   /* %% for percent sign */
                   2043:                     strcat(cmd,"%");
                   2044:                     break;
1.1.1.2 ! root     2045:                                case '.':       /* .exe for DOS/OS2/Win32, blank for Unix */
        !          2046: #ifndef __unix__
        !          2047:                                        strcat(cmd,".exe");
        !          2048: #endif
        !          2049:                                        break;
1.1       root     2050:                                case '?':       /* Platform */
                   2051: #ifdef __OS2__
                   2052:                                        strcpy(str,"OS2");
                   2053: #else
                   2054:                                        strcpy(str,PLATFORM_DESC);
                   2055: #endif
                   2056:                                        strlwr(str);
                   2057:                                        strcat(cmd,str);
                   2058:                                        break;
                   2059:                 default:    /* unknown specification */
                   2060:                     if(isdigit(instr[i])) {
                   2061:                         sprintf(str,"%0*d",instr[i]&0xf,useron.number);
                   2062:                         strcat(cmd,str); }
                   2063:                     break; }
                   2064:             j=strlen(cmd); }
                   2065:         else
                   2066:             cmd[j++]=instr[i]; }
                   2067:     cmd[j]=0;
                   2068: 
                   2069:     return(cmd);
                   2070: }
                   2071: 
1.1.1.2 ! root     2072: /****************************************************************************/
        !          2073: /* Returns command line generated from instr with %c replacments            */
        !          2074: /* This is the C-exported version                                                                                      */
        !          2075: /****************************************************************************/
        !          2076: extern "C" 
        !          2077: char* DLLCALL cmdstr(scfg_t* cfg, user_t* user, const char* instr, const char* fpath
        !          2078:                                                ,const char* fspec, char* cmd)
        !          2079: {
        !          2080:        char    str[256];
        !          2081:     int                i,j,len;
        !          2082: 
        !          2083:     len=strlen(instr);
        !          2084:     for(i=j=0;i<len && j<MAX_PATH;i++) {
        !          2085:         if(instr[i]=='%') {
        !          2086:             i++;
        !          2087:             cmd[j]=0;
        !          2088:                        char ch=instr[i];
        !          2089:                        if(isalpha(ch))
        !          2090:                                ch=toupper(ch);
        !          2091:             switch(ch) {
        !          2092:                 case 'A':   /* User alias */
        !          2093:                                        if(user!=NULL)
        !          2094:                                                strcat(cmd,user->alias);
        !          2095:                     break;
        !          2096:                 case 'B':   /* Baud (DTE) Rate */
        !          2097:                     break;
        !          2098:                 case 'C':   /* Connect Description */
        !          2099:                     break;
        !          2100:                 case 'D':   /* Connect (DCE) Rate */
        !          2101:                     break;
        !          2102:                 case 'E':   /* Estimated Rate */
        !          2103:                     break;
        !          2104:                 case 'F':   /* File path */
        !          2105:                     strcat(cmd,fpath);
        !          2106:                     break;
        !          2107:                 case 'G':   /* Temp directory */
        !          2108:                     strcat(cmd,cfg->temp_dir);
        !          2109:                     break;
        !          2110:                 case 'H':   /* Port Handle or Hardware Flow Control */
        !          2111:                     break;
        !          2112:                 case 'I':   /* IP address */
        !          2113:                     break;
        !          2114:                 case 'J':
        !          2115:                     strcat(cmd,cfg->data_dir);
        !          2116:                     break;
        !          2117:                 case 'K':
        !          2118:                     strcat(cmd,cfg->ctrl_dir);
        !          2119:                     break;
        !          2120:                 case 'L':   /* Lines per message */
        !          2121:                                        if(user!=NULL)
        !          2122:                                                strcat(cmd,ultoa(cfg->level_linespermsg[user->level],str,10));
        !          2123:                     break;
        !          2124:                 case 'M':   /* Minutes (credits) for user */
        !          2125:                                        if(user!=NULL)
        !          2126:                                                strcat(cmd,ultoa(user->min,str,10));
        !          2127:                     break;
        !          2128:                 case 'N':   /* Node Directory (same as SBBSNODE environment var) */
        !          2129:                     strcat(cmd,cfg->node_dir);
        !          2130:                     break;
        !          2131:                 case 'O':   /* SysOp */
        !          2132:                     strcat(cmd,cfg->sys_op);
        !          2133:                     break;
        !          2134:                 case 'P':   /* Client protocol */
        !          2135:                     break;
        !          2136:                 case 'Q':   /* QWK ID */
        !          2137:                     strcat(cmd,cfg->sys_id);
        !          2138:                     break;
        !          2139:                 case 'R':   /* Rows */
        !          2140:                                        if(user!=NULL)
        !          2141:                                                strcat(cmd,ultoa(user->rows,str,10));
        !          2142:                     break;
        !          2143:                 case 'S':   /* File Spec */
        !          2144:                     strcat(cmd,fspec);
        !          2145:                     break;
        !          2146:                 case 'T':   /* Time left in seconds */
        !          2147:                     break;
        !          2148:                 case 'U':   /* UART I/O Address (in hex) */
        !          2149:                     strcat(cmd,ultoa(cfg->com_base,str,16));
        !          2150:                     break;
        !          2151:                 case 'V':   /* Synchronet Version */
        !          2152:                     sprintf(str,"%s%c",VERSION,REVISION);
        !          2153:                     break;
        !          2154:                 case 'W':   /* Time-slice API type (mswtype) */
        !          2155: #if 0 //ndef __FLAT__
        !          2156:                     strcat(cmd,ultoa(mswtyp,str,10));
        !          2157: #endif
        !          2158:                     break;
        !          2159:                 case 'X':
        !          2160:                                        if(user!=NULL)
        !          2161:                                                strcat(cmd,cfg->shell[user->shell]->code);
        !          2162:                     break;
        !          2163:                 case '&':   /* Address of msr */
        !          2164:                     sprintf(str,"%lu",(DWORD)&fakeriobp);
        !          2165:                     strcat(cmd,str);
        !          2166:                     break;
        !          2167:                 case 'Y':
        !          2168:                     break;
        !          2169:                 case 'Z':
        !          2170:                     strcat(cmd,cfg->text_dir);
        !          2171:                     break;
        !          2172:                                case '~':       /* DOS-compatible (8.3) filename */
        !          2173: #ifdef _WIN32
        !          2174:                                        char sfpath[MAX_PATH+1];
        !          2175:                                        SAFECOPY(sfpath,fpath);
        !          2176:                                        GetShortPathName(fpath,sfpath,sizeof(sfpath));
        !          2177:                                        strcat(cmd,sfpath);
        !          2178: #else
        !          2179:                     strcat(cmd,fpath);
        !          2180: #endif                 
        !          2181:                                        break;
        !          2182:                 case '!':   /* EXEC Directory */
        !          2183:                     strcat(cmd,cfg->exec_dir);
        !          2184:                     break;
        !          2185:                 case '#':   /* Node number (same as SBBSNNUM environment var) */
        !          2186:                     sprintf(str,"%d",cfg->node_num);
        !          2187:                     strcat(cmd,str);
        !          2188:                     break;
        !          2189:                 case '*':
        !          2190:                     sprintf(str,"%03d",cfg->node_num);
        !          2191:                     strcat(cmd,str);
        !          2192:                     break;
        !          2193:                 case '$':   /* Credits */
        !          2194:                                        if(user!=NULL)
        !          2195:                                                strcat(cmd,ultoa(user->cdt+user->freecdt,str,10));
        !          2196:                     break;
        !          2197:                 case '%':   /* %% for percent sign */
        !          2198:                     strcat(cmd,"%");
        !          2199:                     break;
        !          2200:                                case '.':       /* .exe for DOS/OS2/Win32, blank for Unix */
        !          2201: #ifndef __unix__
        !          2202:                                        strcat(cmd,".exe");
        !          2203: #endif
        !          2204:                                        break;
        !          2205:                                case '?':       /* Platform */
        !          2206: #ifdef __OS2__
        !          2207:                                        strcpy(str,"OS2");
        !          2208: #else
        !          2209:                                        strcpy(str,PLATFORM_DESC);
        !          2210: #endif
        !          2211:                                        strlwr(str);
        !          2212:                                        strcat(cmd,str);
        !          2213:                                        break;
        !          2214:                 default:    /* unknown specification */
        !          2215:                     if(isdigit(instr[i]) && user!=NULL) {
        !          2216:                         sprintf(str,"%0*d",instr[i]&0xf,user->number);
        !          2217:                         strcat(cmd,str); 
        !          2218:                                        }
        !          2219:                     break; 
        !          2220:                        }
        !          2221:             j=strlen(cmd); 
        !          2222:                }
        !          2223:         else
        !          2224:             cmd[j++]=instr[i]; 
        !          2225:        }
        !          2226:     cmd[j]=0;
        !          2227: 
        !          2228:     return(cmd);
        !          2229: }
        !          2230: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.