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

1.1       root        1: /* xtrn.cpp */
                      2: 
                      3: /* Synchronet external program support routines */
                      4: 
                      5: /* $Id: xtrn.cpp,v 1.27 2000/12/06 22:10:20 rswindell Exp $ */
                      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:  *                                                                                                                                                     *
                     11:  * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html         *
                     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: 
                     42: #ifdef __unix__
                     43:        #include <sys/wait.h>   // WEXITSTATUS
                     44: #endif
                     45: 
                     46: /*****************************************************************************/
                     47: /* Interrupt routine to expand WWIV Ctrl-C# codes into ANSI escape sequences */
                     48: /*****************************************************************************/
                     49: BYTE* wwiv_expand(BYTE* buf, ulong buflen, BYTE* outbuf, ulong& newlen
                     50:        ,ulong user_misc, bool& ctrl_c)
                     51: {
                     52:     char       ansi_seq[32];
                     53:        ulong   i,j,k;
                     54: 
                     55:     for(i=j=0;i<buflen;i++) {
                     56:         if(buf[i]==3) {        /* ctrl-c, WWIV color escape char */
                     57:             ctrl_c=true;
                     58:             continue;
                     59:         }
                     60:         if(!ctrl_c) {
                     61:             outbuf[j++]=buf[i];
                     62:             continue;
                     63:         }
                     64:         ctrl_c=false;
                     65:         if(user_misc&ANSI) {
                     66:             switch(buf[i]) {
                     67:                 default:
                     68:                     strcpy(ansi_seq,"\x1b[0m");          /* low grey */
                     69:                     break;
                     70:                 case '1':
                     71:                     strcpy(ansi_seq,"\x1b[0;1;36m");     /* high cyan */
                     72:                     break;
                     73:                 case '2':
                     74:                     strcpy(ansi_seq,"\x1b[0;1;33m");     /* high yellow */
                     75:                     break;
                     76:                 case '3':
                     77:                     strcpy(ansi_seq,"\x1b[0;35m");       /* low magenta */
                     78:                     break;
                     79:                 case '4':
                     80:                     strcpy(ansi_seq,"\x1b[0;1;44m");     /* white on blue */
                     81:                     break;
                     82:                 case '5':
                     83:                     strcpy(ansi_seq,"\x1b[0;32m");       /* low green */
                     84:                     break;
                     85:                 case '6':
                     86:                     strcpy(ansi_seq,"\x1b[0;1;5;31m");   /* high blinking red */
                     87:                     break;
                     88:                 case '7':
                     89:                     strcpy(ansi_seq,"\x1b[0;1;34m");     /* high blue */
                     90:                     break;
                     91:                 case '8':
                     92:                     strcpy(ansi_seq,"\x1b[0;34m");       /* low blue */
                     93:                     break;
                     94:                 case '9':
                     95:                     strcpy(ansi_seq,"\x1b[0;36m");       /* low cyan */
                     96:                     break;
                     97:             }
                     98:             for(k=0;ansi_seq[k];k++)
                     99:                 outbuf[j++]=ansi_seq[k];
                    100:         }
                    101:     }
                    102:     newlen=j;
                    103:     return(outbuf);
                    104: }
                    105: 
                    106: /*****************************************************************************/
                    107: // Escapes Telnet IAC (255) by doubling the IAC char
                    108: /*****************************************************************************/
                    109: BYTE* telnet_expand(BYTE* inbuf, ulong inlen, BYTE* outbuf, ulong& newlen, bool& iac)
                    110: {
                    111:        BYTE*   first_iac;
                    112:        ulong   i,outlen;
                    113: 
                    114:     first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
                    115: 
                    116:        if(first_iac==NULL && !iac) {   /* Nothing to expand */
                    117:                newlen=inlen;
                    118:                return(inbuf);
                    119:        }
                    120: 
                    121:        if(first_iac!=NULL) {
                    122:                outlen=first_iac-inbuf;
                    123:                memcpy(outbuf, inbuf, outlen);
                    124:        } else
                    125:                outlen=0;
                    126: 
                    127:     for(i=outlen;i<inlen;i++) {
                    128:                if(iac==true) {
                    129:                        outbuf[outlen++]=TELNET_IAC;
                    130: //                     lprintf("Telnet IAC escaped");
                    131:                }
                    132:                if(inbuf[i]==TELNET_IAC)
                    133:                        iac=true;
                    134:                else
                    135:                        iac=false;
                    136:                outbuf[outlen++]=inbuf[i];
                    137:        }
                    138:     newlen=outlen;
                    139:     return(outbuf);
                    140: }
                    141: 
                    142: 
                    143: #ifdef _WIN32
                    144: 
                    145: #include "execvxd.h"   /* Win9X FOSSIL VxD API */
                    146: 
                    147: #define XTRN_IO_BUF_LEN 5000
                    148: 
                    149: extern SOCKET node_socket[];
                    150: 
                    151: // -------------------------------------------------------------------------
                    152: // GetAddressOfOpenVxDHandle
                    153: //
                    154: // This function returns the address of OpenVxDHandle. OpenVxDHandle is a 
                    155: // KERNEL32 function that returns a ring 0 event handle that corresponds to a
                    156: // given ring 3 event handle. The ring 0 handle can be used by VxDs to
                    157: // synchronize with the Win32 app.
                    158: //
                    159: typedef HANDLE (WINAPI *OPENVXDHANDLE)(HANDLE);
                    160: 
                    161: OPENVXDHANDLE GetAddressOfOpenVxDHandle(void)
                    162: {
                    163:        HINSTANCE hK32;
                    164: 
                    165:        if ((hK32 = LoadLibrary("KERNEL32")) == NULL)
                    166:                return NULL;
                    167: 
                    168:        return((OPENVXDHANDLE)GetProcAddress(hK32, "OpenVxDHandle"));
                    169: }
                    170: 
                    171: /****************************************************************************/
                    172: /* Runs an external program                                                                                            */
                    173: /****************************************************************************/
                    174: int sbbs_t::external(char* cmdline, long mode, char* startup_dir)
                    175: {
                    176:        char    str[256],*p,*p_startup_dir;
                    177:        char    fname[128];
                    178:     char       fullcmdline[256];
                    179:        char    realcmdline[256];
                    180:        char    comspec_str[128];
                    181:        char    title[256];
                    182:        BYTE    buf[XTRN_IO_BUF_LEN],*bp;
                    183:     BYTE       telnet_buf[XTRN_IO_BUF_LEN*2];
                    184:     BYTE       wwiv_buf[XTRN_IO_BUF_LEN*2];
                    185:     bool       wwiv_flag=false;
                    186:        bool    telnet_flag=false;
                    187:     bool       native=false;                   // DOS program by default
                    188:     bool       was_online=true;
                    189:     uint       i;
                    190:     time_t     hungup=0;
                    191:        bool    nt=false;
                    192:        HANDLE  vxd=INVALID_HANDLE_VALUE;
                    193:        HANDLE  rdslot=INVALID_HANDLE_VALUE;
                    194:        HANDLE  wrslot=INVALID_HANDLE_VALUE;
                    195:        HANDLE  start_event;
                    196:        HANDLE  hungup_event=NULL;
                    197:     PROCESS_INFORMATION process_info;
                    198:        DWORD   hVM;
                    199:        DWORD   rd;
                    200:     DWORD      wr;
                    201:     DWORD      len;
                    202:     DWORD      avail;
                    203:        DWORD   dummy;  
                    204:        DWORD   retval;
                    205:        DWORD   last_error;
                    206:        DWORD   loop_since_io=0;
                    207:        struct  tm * tm_p;
                    208:        sbbsexec_start_t start;
                    209:        OPENVXDHANDLE OpenVxDHandle;
                    210: 
                    211:        if(cmdline[0]=='*') {   /* Baja module */
                    212:                sprintf(str,"%.*s",sizeof(str)-1,cmdline+1);
                    213:                p=strchr(str,SP);
                    214:                if(p) {
                    215:                        strcpy(main_csi.str,p+1);
                    216:                        *p=0; }
                    217:                return(exec_bin(str,&main_csi)); 
                    218:        }
                    219: 
                    220:        attr(cfg.color[clr_external]);        /* setup default attributes */
                    221: 
                    222:     strcpy(str,cmdline);               /* Set str to program name only */
                    223:     p=strchr(str,SP);
                    224:     if(p) *p=0;
                    225:     strcpy(fname,str);
                    226: 
                    227:     p=strrchr(fname,'/');
                    228:     if(!p) p=strrchr(fname,'\\');
                    229:     if(!p) p=strchr(fname,':');
                    230:     if(!p) p=fname;
                    231:     else   p++;
                    232: 
                    233:     for(i=0;i<cfg.total_natvpgms;i++)
                    234:         if(!stricmp(p,cfg.natvpgm[i]->name))
                    235:             break;
                    236:     if(i<cfg.total_natvpgms || mode&EX_NATIVE)
                    237:         native=true;
                    238: 
                    239:        if(strcspn(cmdline,"<>|")!=strlen(cmdline)) 
                    240:                sprintf(comspec_str,"%s /C ", comspec);
                    241:        else
                    242:                comspec_str[0]=0;
                    243: 
                    244:     if(startup_dir && cmdline[1]!=':' && cmdline[0]!='/'
                    245:        && cmdline[0]!='\\' && cmdline[0]!='.')
                    246:                sprintf(fullcmdline, "%s%s%s", comspec_str, startup_dir, cmdline);
                    247:     else
                    248:        sprintf(fullcmdline, "%s%s", comspec_str, cmdline);
                    249: 
                    250:        strcpy(realcmdline, fullcmdline);       // for errormsg if failed to execute
                    251: 
                    252:        now=time(NULL);
                    253:        tm_p=gmtime(&now);
                    254: 
                    255:        if(native) { // Native (32-bit) external
                    256: 
                    257:                // Current environment passed to child process
                    258:                sprintf(dszlog,"DSZLOG=%sPROTOCOL.LOG",cfg.node_dir);
                    259:                if(putenv(dszlog))              /* Makes the DSZ LOG active */
                    260:                errormsg(WHERE,ERR_WRITE,"environment",0);
                    261:                sprintf(sbbsnode,"SBBSNODE=%s",cfg.node_dir);
                    262:                putenv(sbbsnode);               /* create environment var to contain node num */
                    263:                sprintf(sbbsnnum,"SBBSNNUM=%d",cfg.node_num);
                    264:                putenv(sbbsnnum);          /* create environment var to contain node num */
                    265: 
                    266:     } else { // DOS external
                    267: 
                    268:                sprintf(str,"%sDOSXTRN.RET", cfg.node_dir);
                    269:                remove(str);
                    270: 
                    271:        // Create temporary environment file
                    272:        sprintf(str,"%sDOSXTRN.ENV", cfg.node_dir);
                    273:         FILE* fp=fopen(str,"w");
                    274:         if(fp==NULL) {
                    275:                errormsg(WHERE, ERR_CREATE, str, 0);
                    276:             return(1);
                    277:         }
                    278:         fprintf(fp, "%s\n", fullcmdline);
                    279:                fprintf(fp, "DSZLOG=%sPROTOCOL.LOG\n", cfg.node_dir);
                    280:         fprintf(fp, "SBBSCTRL=%s\n", cfg.ctrl_dir);
                    281:         fprintf(fp, "SBBSNODE=%s\n", cfg.node_dir);
                    282:         fprintf(fp, "SBBSNNUM=%d\n", cfg.node_num);
                    283:                if(tm_p!=NULL) {
                    284:                        fprintf(fp, "DAY=%02u\n", tm_p->tm_mday);
                    285:                        fprintf(fp, "WEEKDAY=%s\n",wday[tm_p->tm_wday]);
                    286:                        fprintf(fp, "MONTHNAME=%s\n",mon[tm_p->tm_mon]);
                    287:                        fprintf(fp, "MONTH=%02u\n",tm_p->tm_mon+1);
                    288:                        fprintf(fp, "YEAR=%u\n",1900+tm_p->tm_year);
                    289:                }
                    290:         fclose(fp);
                    291: 
                    292:         sprintf(fullcmdline, "%sDOSXTRN.EXE %s", cfg.exec_dir, str);
                    293: 
                    294:                if((retval=WaitForSingleObject(exec_mutex,5000))!=WAIT_OBJECT_0) {
                    295:                        errormsg(WHERE, ERR_TIMEOUT, "exec_mutex", retval);
                    296:                        return(GetLastError());
                    297:                }
                    298: 
                    299:                OpenVxDHandle=GetAddressOfOpenVxDHandle();
                    300: 
                    301:                if(!(mode&EX_OFFLINE) && OpenVxDHandle==NULL) { // Windows NT/2000
                    302:                        nt=true;
                    303:                        i=SBBSEXEC_MODE_FOSSIL;
                    304:                        if(mode&EX_INR)
                    305:                        i|=SBBSEXEC_MODE_DOS_IN;
                    306:                        if(mode&EX_OUTR)
                    307:                        i|=SBBSEXEC_MODE_DOS_OUT;
                    308:                        sprintf(str," NT %d %d",cfg.node_num,i);
                    309:                        strcat(fullcmdline,str);
                    310: 
                    311:                        sprintf(str,"sbbsexec_hungup%d",cfg.node_num);
                    312:                        if((hungup_event=CreateEvent(
                    313:                                 NULL   // pointer to security attributes
                    314:                                ,TRUE   // flag for manual-reset event
                    315:                                ,FALSE  // flag for initial state
                    316:                                ,str    // pointer to event-object name
                    317:                                ))==NULL) {
                    318:                                last_error=GetLastError();
                    319:                                ReleaseMutex(exec_mutex);
                    320:                                SetLastError(last_error);
                    321:                                errormsg(WHERE, ERR_CREATE, "exec start event", 0);
                    322:                                return(GetLastError());
                    323:                        }
                    324: 
                    325:                        sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d"
                    326:                                ,cfg.node_num);
                    327:                        rdslot=CreateMailslot(str
                    328:                                ,sizeof(buf)                    // Maximum message size (0=unlimited)
                    329:                                ,0                                              // Read time-out
                    330:                                ,NULL);                 // Security
                    331:                        if(rdslot==INVALID_HANDLE_VALUE) {
                    332:                                last_error=GetLastError();
                    333:                                ReleaseMutex(exec_mutex);
                    334:                                CloseHandle(hungup_event);
                    335:                                SetLastError(last_error);
                    336:                                errormsg(WHERE, ERR_CREATE, str, 0);
                    337:                                return(GetLastError());
                    338:                        }
                    339:                }
                    340:                else if(!(mode&EX_OFFLINE)) {
                    341: 
                    342:                        // Load vxd to intercept interrupts
                    343: 
                    344:                        sprintf(str,"\\\\.\\%s%s",cfg.exec_dir, SBBSEXEC_VXD);
                    345:                        if((vxd=CreateFile(str,0,0,0
                    346:                                ,CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE,0))
                    347:                                 ==INVALID_HANDLE_VALUE) {
                    348:                                last_error=GetLastError();
                    349:                                ReleaseMutex(exec_mutex);
                    350:                                SetLastError(last_error);
                    351:                                errormsg(WHERE, ERR_OPEN, str, 0);
                    352:                                return(GetLastError());
                    353:                        }
                    354: 
                    355:                        if((start_event=CreateEvent(
                    356:                                 NULL   // pointer to security attributes
                    357:                                ,TRUE   // flag for manual-reset event
                    358:                                ,FALSE  // flag for initial state
                    359:                                ,NULL   // pointer to event-object name
                    360:                                ))==NULL) {
                    361:                                last_error=GetLastError();
                    362:                                ReleaseMutex(exec_mutex);
                    363:                                CloseHandle(vxd);
                    364:                                SetLastError(last_error);
                    365:                                errormsg(WHERE, ERR_CREATE, "exec start event", 0);
                    366:                                return(GetLastError());
                    367:                        }
                    368: 
                    369:                        if(OpenVxDHandle!=NULL)
                    370:                                start.event=OpenVxDHandle(start_event);
                    371:                        else
                    372:                                start.event=start_event;
                    373: 
                    374:                        start.mode=SBBSEXEC_MODE_FOSSIL;
                    375:                        if(mode&EX_INR)
                    376:                        start.mode|=SBBSEXEC_MODE_DOS_IN;
                    377:                        if(mode&EX_OUTR)
                    378:                        start.mode|=SBBSEXEC_MODE_DOS_OUT;
                    379: 
                    380:                        if(!DeviceIoControl(
                    381:                                vxd,                                    // handle to device of interest
                    382:                                SBBSEXEC_IOCTL_START,   // control code of operation to perform
                    383:                                &start,                                 // pointer to buffer to supply input data
                    384:                                sizeof(start),                  // size of input buffer
                    385:                                NULL,                                   // pointer to buffer to receive output data
                    386:                                0,                                              // size of output buffer
                    387:                                &rd,                                    // pointer to variable to receive output byte count
                    388:                                NULL                                    // Overlapped I/O
                    389:                                )) {
                    390:                                last_error=GetLastError();
                    391:                                ReleaseMutex(exec_mutex);
                    392:                                CloseHandle(vxd);
                    393:                                SetLastError(last_error);
                    394:                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_START);
                    395:                                return(GetLastError());
                    396:                        }
                    397:                }
                    398:     }
                    399: 
                    400:        if(startup_dir!=NULL && startup_dir[0])
                    401:                p_startup_dir=startup_dir;
                    402:        else
                    403:                p_startup_dir=NULL;
                    404:     STARTUPINFO startup_info={0};
                    405:     startup_info.cb=sizeof(startup_info);
                    406:        if(mode&EX_OFFLINE)
                    407:                startup_info.lpTitle=NULL;
                    408:        else {
                    409:                sprintf(title,"%s running %s on node %d"
                    410:                        ,useron.number ? useron.alias : "Event"
                    411:                        ,realcmdline
                    412:                        ,cfg.node_num);
                    413:                startup_info.lpTitle=title;
                    414:        }
                    415:     if(cfg.startup->options&BBS_OPT_XTRN_MINIMIZED) {
                    416:        startup_info.wShowWindow=SW_SHOWMINNOACTIVE;
                    417:         startup_info.dwFlags|=STARTF_USESHOWWINDOW;
                    418:     }
                    419: 
                    420:        if(native) {
                    421:                /* temporary */
                    422:                FILE* fp;
                    423:                sprintf(fname,"%sDOOR32.SYS",cfg.node_dir);
                    424:                fp=fopen(fname,"wb");
                    425:                fprintf(fp,"2\r\n%d\r\n38400\r\nSynchronet %s%c\r\n%d\r\n%s\r\n%s\r\n%d\r\n%d\r\n"
                    426:                        "%d\r\n%d\r\n"
                    427:                        ,client_socket_dup
                    428:                        ,VERSION,REVISION
                    429:                        ,useron.number
                    430:                        ,useron.name
                    431:                        ,useron.alias
                    432:                        ,useron.level
                    433:                        ,timeleft/60
                    434:                        ,useron.misc&ANSI ? 1 : 0
                    435:                        ,cfg.node_num);
                    436:                fclose(fp);
                    437: 
                    438:                /* not temporary */
                    439: #if 0
                    440:                SuspendThread(input_thread);
                    441: #else
                    442:                pthread_mutex_lock(&input_thread_mutex);
                    443: #endif
                    444:        }
                    445: 
                    446:     if(!CreateProcess(
                    447:                NULL,                   // pointer to name of executable module
                    448:                fullcmdline,    // pointer to command line string
                    449:                NULL,                   // process security attributes
                    450:                NULL,                   // thread security attributes
                    451:                TRUE,                   // handle inheritance flag
                    452:                CREATE_NEW_CONSOLE|CREATE_SEPARATE_WOW_VDM, // creation flags
                    453:         NULL,                          // pointer to new environment block
                    454:                p_startup_dir,  // pointer to current directory name
                    455:                &startup_info,  // pointer to STARTUPINFO
                    456:                &process_info   // pointer to PROCESS_INFORMATION
                    457:                )) {
                    458:                last_error=GetLastError();
                    459:         ReleaseMutex(exec_mutex);
                    460:                if(vxd!=INVALID_HANDLE_VALUE)
                    461:                        CloseHandle(vxd);
                    462:                if(hungup_event!=NULL)
                    463:                        CloseHandle(hungup_event);
                    464:                if(native)
                    465:                        ResumeThread(input_thread);
                    466:                SetLastError(last_error);
                    467:         errormsg(WHERE, ERR_EXEC, realcmdline, mode);
                    468:         return(GetLastError());
                    469:     }
                    470: 
                    471:        if(!native) {
                    472: 
                    473:                if(!(mode&EX_OFFLINE) && !nt) {
                    474:                // Wait for notification from VXD that new VM has started
                    475:                        if((retval=WaitForSingleObject(start_event, 5000))!=WAIT_OBJECT_0) {
                    476:                                last_error=GetLastError();
                    477:                                ReleaseMutex(exec_mutex);
                    478:                                CloseHandle(vxd);
                    479:                                CloseHandle(start_event);
                    480:                                SetLastError(last_error);
                    481:                                errormsg(WHERE, ERR_TIMEOUT, "start_event", retval);
                    482:                                return(GetLastError());
                    483:                        }
                    484: 
                    485:                        CloseHandle(start_event);
                    486: 
                    487:                        if(!DeviceIoControl(
                    488:                                vxd,                                    // handle to device of interest
                    489:                                SBBSEXEC_IOCTL_COMPLETE,        // control code of operation to perform
                    490:                                NULL,                                   // pointer to buffer to supply input data
                    491:                                0,                                              // size of input buffer
                    492:                                &hVM,                                   // pointer to buffer to receive output data
                    493:                                sizeof(hVM),                    // size of output buffer
                    494:                                &rd,                                    // pointer to variable to receive output byte count
                    495:                                NULL                                    // Overlapped I/O
                    496:                                )) {
                    497:                                last_error=GetLastError();
                    498:                                ReleaseMutex(exec_mutex);
                    499:                                CloseHandle(vxd);
                    500:                                SetLastError(last_error);
                    501:                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_COMPLETE);
                    502:                                return(GetLastError());
                    503:                        }
                    504:                }
                    505:         ReleaseMutex(exec_mutex);
                    506:        }
                    507: 
                    508:     // Executing app, monitor
                    509:     retval=STILL_ACTIVE;
                    510:     while(1) {
                    511:         if(!online && !(mode&EX_OFFLINE)) { // Tell VXD/VDD and external that user hung-up
                    512:                if(was_online) {
                    513:                                logline("X!","Hung-up in external program");
                    514:                hungup=time(NULL);
                    515:                                if(!native) {
                    516:                                        if(nt)
                    517:                                                SetEvent(hungup_event);
                    518:                                        else if(!DeviceIoControl(
                    519:                                                vxd,            // handle to device of interest
                    520:                                                SBBSEXEC_IOCTL_DISCONNECT,      // operation to perform
                    521:                                                &hVM,           // pointer to buffer to supply input data
                    522:                                                sizeof(hVM),// size of input buffer
                    523:                                                NULL,           // pointer to buffer to receive output data
                    524:                                                0,                      // size of output buffer
                    525:                                                &rd,            // pointer to variable to receive output byte count
                    526:                                                NULL            // Overlapped I/O
                    527:                                                )) {
                    528:                                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_DISCONNECT);
                    529:                                                break;
                    530:                                        }
                    531:                                }
                    532:                    was_online=false;
                    533:             }
                    534:             if(hungup && time(NULL)-hungup>5) 
                    535:                 TerminateProcess(process_info.hProcess, 2112);
                    536:         }
                    537:                if(native || mode&EX_OFFLINE) {
                    538:             if(GetExitCodeProcess(process_info.hProcess, &retval)==FALSE) {
                    539:                 errormsg(WHERE, ERR_CHK, "ExitCodeProcess"
                    540:                    ,(DWORD)process_info.hProcess);
                    541:                 break;
                    542:             }
                    543:             if(retval!=STILL_ACTIVE)
                    544:                 break;
                    545:                Sleep(500);
                    546:                } else {
                    547: 
                    548:                        if(nt) {        // Windows NT/2000
                    549: 
                    550:                                /* Write to VDD */
                    551: 
                    552:                                wr=RingBufPeek(&inbuf,buf,sizeof(buf));
                    553:                                if(wr) {
                    554:                                        if(wrslot==INVALID_HANDLE_VALUE) {
                    555:                                                sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d"
                    556:                                                        ,cfg.node_num);
                    557:                                                wrslot=CreateFile(str
                    558:                                                        ,GENERIC_WRITE
                    559:                                                        ,FILE_SHARE_READ
                    560:                                                        ,NULL
                    561:                                                        ,OPEN_EXISTING
                    562:                                                        ,FILE_ATTRIBUTE_NORMAL
                    563:                                                        ,(HANDLE) NULL);
                    564: #if 0
                    565:                                                if(wrslot==INVALID_HANDLE_VALUE) {
                    566:                                                        errormsg(WHERE,ERR_OPEN,str,0);
                    567:                                                        break;
                    568:                                                }
                    569: #endif
                    570:                                        }
                    571:                                        if(wrslot!=INVALID_HANDLE_VALUE
                    572:                                                && WriteFile(wrslot,buf,wr,&len,NULL)==TRUE) {
                    573:                                                RingBufRead(&inbuf, NULL, len);
                    574:                                                wr=len;
                    575:                                        } else          // VDD not loaded yet
                    576:                                                wr=0;
                    577:                                }
                    578: 
                    579:                                /* Read from VDD */
                    580: 
                    581:                                len=sizeof(buf);
                    582:                                avail=RingBufFree(&outbuf);
                    583:                                if(len>avail)
                    584:                        len=avail;
                    585:                                if(ReadFile(rdslot,buf,len,&rd,NULL)==TRUE && rd>0) {
                    586:                                        if(mode&EX_WWIV) {
                    587:                                bp=wwiv_expand(buf, rd, wwiv_buf, rd, useron.misc, wwiv_flag);
                    588:                                                if(rd>sizeof(wwiv_buf))
                    589:                                                        errorlog("WWIV_BUF OVERRUN");
                    590:                                        } else {
                    591:                                bp=telnet_expand(buf, rd, telnet_buf, rd, telnet_flag);
                    592:                                                if(rd>sizeof(telnet_buf))
                    593:                                                        errorlog("TELNET_BUF OVERRUN");
                    594:                                        }
                    595:                                        RingBufWrite(&outbuf, bp, rd);
                    596:                                        sem_post(&output_sem);
                    597:                                }
                    598:                        } else {        // Windows 9x
                    599: 
                    600:                                /* Write to VXD */
                    601: 
                    602:                                wr=RingBufPeek(&inbuf, buf+sizeof(hVM),sizeof(buf)-sizeof(hVM));
                    603:                                if(wr) {
                    604:                                        *(DWORD*)buf=hVM;
                    605:                                        wr+=sizeof(hVM);
                    606:                                        if(!DeviceIoControl(
                    607:                                                vxd,                                    // handle to device of interest
                    608:                                                SBBSEXEC_IOCTL_WRITE,   // control code of operation to perform
                    609:                                                buf,                                    // pointer to buffer to supply input data
                    610:                                                wr,                                             // size of input buffer
                    611:                                                &rd,                                    // pointer to buffer to receive output data
                    612:                                                sizeof(rd),                             // size of output buffer
                    613:                                                &dummy,                                 // pointer to variable to receive output byte count
                    614:                                                NULL                                    // Overlapped I/O
                    615:                                                )) {
                    616:                                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_READ);
                    617:                                                break;
                    618:                                        }
                    619:                                        RingBufRead(&inbuf, NULL, rd);
                    620:                                        wr=rd;
                    621:                                }
                    622:                        /* Read from VXD */
                    623:                                rd=0;
                    624:                                len=sizeof(buf);
                    625:                                avail=RingBufFree(&outbuf);
                    626:                                if(len>avail)
                    627:                        len=avail;
                    628:                                if(len && avail>=RingBufFull(&outbuf)) {
                    629:                                        if(!DeviceIoControl(
                    630:                                                vxd,                                    // handle to device of interest
                    631:                                                SBBSEXEC_IOCTL_READ,    // control code of operation to perform
                    632:                                                &hVM,                                   // pointer to buffer to supply input data
                    633:                                                sizeof(hVM),                    // size of input buffer
                    634:                                                buf,                                    // pointer to buffer to receive output data
                    635:                                                len,                                    // size of output buffer
                    636:                                                &rd,                                    // pointer to variable to receive output byte count
                    637:                                                NULL                                    // Overlapped I/O
                    638:                                                )) {
                    639:                                                errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_READ);
                    640:                                                break;
                    641:                                        }
                    642: #if 0
                    643:                                        if(rd>1)
                    644:                                lprintf("read %d bytes from xtrn", rd);
                    645: #endif
                    646: 
                    647:                                        if(mode&EX_WWIV)
                    648:                                bp=wwiv_expand(buf, rd, wwiv_buf, rd, useron.misc, wwiv_flag);
                    649:                                        else
                    650:                                bp=telnet_expand(buf, rd, telnet_buf, rd, telnet_flag);
                    651:                                        RingBufWrite(&outbuf, bp, rd);
                    652:                                        sem_post(&output_sem);
                    653:                                }
                    654:                        }
                    655:             if(!rd && !wr) {
                    656:                                if(++loop_since_io>=1000) {
                    657:                        if(GetExitCodeProcess(process_info.hProcess, &retval)==FALSE) {
                    658:                            errormsg(WHERE, ERR_CHK, "ExitCodeProcess"
                    659:                                                ,(DWORD)process_info.hProcess);
                    660:                                                break;
                    661:                                        }
                    662:                                        if(retval!=STILL_ACTIVE)  {
                    663: #if 0
                    664:                                                if(hungup)
                    665:                                                        Sleep(5000);    // Give the application time to close files
                    666: #endif
                    667:                            break;
                    668:                                        }
                    669:                                        if(!(loop_since_io%3000)) {
                    670: //                                             OutputDebugString(".");
                    671:                                                getnodedat(cfg.node_num,&thisnode,0);
                    672:                                                if(thisnode.misc&NODE_INTR)
                    673:                                                        break;
                    674:                                        }
                    675:                                        Sleep(1);
                    676:                                }
                    677:             } else
                    678:                                loop_since_io=0;
                    679:         }
                    680:        }
                    681: 
                    682:        if(!native && !(mode&EX_OFFLINE) && !nt) {
                    683:                if(!DeviceIoControl(
                    684:                        vxd,                                    // handle to device of interest
                    685:                        SBBSEXEC_IOCTL_STOP,    // control code of operation to perform
                    686:                        &hVM,                                   // pointer to buffer to supply input data
                    687:                        sizeof(hVM),                    // size of input buffer
                    688:                        NULL,                                   // pointer to buffer to receive output data
                    689:                        0,                                              // size of output buffer
                    690:                        &rd,                                    // pointer to variable to receive output byte count
                    691:                        NULL                                    // Overlapped I/O
                    692:                        )) {
                    693:                        errormsg(WHERE, ERR_IOCTL, SBBSEXEC_VXD, SBBSEXEC_IOCTL_STOP);
                    694:                }
                    695:        }
                    696: 
                    697:     if(retval==STILL_ACTIVE)
                    698:            TerminateProcess(process_info.hProcess, GetLastError());
                    699: 
                    700:     if(vxd!=INVALID_HANDLE_VALUE)
                    701:                CloseHandle(vxd);
                    702: 
                    703:        if(rdslot!=INVALID_HANDLE_VALUE)
                    704:                CloseHandle(rdslot);
                    705: 
                    706:        if(wrslot!=INVALID_HANDLE_VALUE)
                    707:                CloseHandle(wrslot);
                    708: 
                    709:        if(hungup_event!=NULL)
                    710:                CloseHandle(hungup_event);
                    711: 
                    712:        if(native)
                    713: #if 0
                    714:                ResumeThread(input_thread);
                    715: #else
                    716:                pthread_mutex_unlock(&input_thread_mutex);
                    717: #endif
                    718:        else {  // Get return value
                    719:        sprintf(str,"%sDOSXTRN.RET", cfg.node_dir);
                    720:         FILE* fp=fopen(str,"r");
                    721:         if(fp!=NULL) {
                    722:                        fscanf(fp,"%d",&retval);
                    723:                        fclose(fp);
                    724:                }
                    725:        }
                    726: 
                    727:        curatr=0;       // Can't guarantee current attributes
                    728: 
                    729: //     lprintf("%s returned %d",realcmdline, retval);
                    730: 
                    731:        return(retval);
                    732: }
                    733: 
                    734: #else  /* !WIN32 */
                    735: 
                    736: int sbbs_t::external(char* cmdline, long mode, char* startup_dir)
                    737: {
                    738:        char    str[256];
                    739:        char    fname[128];
                    740:        char*   argv[30];
                    741:        char*   p;
                    742:     bool       native=false;                   // DOS program by default
                    743:        int             i;
                    744:        int             argc;
                    745:        pid_t   pid;
                    746:                
                    747:        if(cmdline[0]=='*') {   /* Baja module */
                    748:                sprintf(str,"%.*s",sizeof(str)-1,cmdline+1);
                    749:                p=strchr(str,SP);
                    750:                if(p) {
                    751:                        strcpy(main_csi.str,p+1);
                    752:                        *p=0; }
                    753:                return(exec_bin(str,&main_csi)); 
                    754:        }
                    755: 
                    756:        attr(cfg.color[clr_external]);        /* setup default attributes */
                    757: 
                    758:     strcpy(str,cmdline);               /* Set str to program name only */
                    759:     p=strchr(str,SP);
                    760:     if(p) *p=0;
                    761:     strcpy(fname,str);
                    762: 
                    763:     p=strrchr(fname,'/');
                    764:     if(!p) p=strrchr(fname,'\\');
                    765:     if(!p) p=strchr(fname,':');
                    766:     if(!p) p=fname;
                    767:     else   p++;
                    768: 
                    769:     for(i=0;i<cfg.total_natvpgms;i++)
                    770:         if(!stricmp(p,cfg.natvpgm[i]->name))
                    771:             break;
                    772:     if(i<cfg.total_natvpgms || mode&EX_NATIVE)
                    773:         native=true;
                    774: 
                    775:        if(!native) {
                    776:                bprintf("\r\nExternal DOS programs are not yet supported in Synchronet for Linux\r\n");
                    777:                return(-1);
                    778:        }
                    779: 
                    780:        if(native) { // Native (32-bit) external
                    781: 
                    782:                // Current environment passed to child process
                    783:                sprintf(dszlog,"DSZLOG=%sPROTOCOL.LOG",cfg.node_dir);
                    784:                if(putenv(dszlog))              /* Makes the DSZ LOG active */
                    785:                errormsg(WHERE,ERR_WRITE,"environment",0);
                    786:                sprintf(sbbsnode,"SBBSNODE=%s",cfg.node_dir);
                    787:                putenv(sbbsnode);               /* create environment var to contain node num */
                    788:                sprintf(sbbsnnum,"SBBSNNUM=%d",cfg.node_num);
                    789:                putenv(sbbsnnum);          /* create environment var to contain node num */
                    790: 
                    791:        } else {
                    792:                /* setup DOSemu env here */
                    793:        }
                    794: 
                    795:        pthread_mutex_lock(&input_thread_mutex);
                    796: 
                    797:        if((pid=fork())==-1) {
                    798:                pthread_mutex_unlock(&input_thread_mutex);
                    799:                errormsg(WHERE,ERR_EXEC,cmdline,0);
                    800:                return(-1);
                    801:        }
                    802: 
                    803:        if(pid==0) {    /* child process */
                    804:                if(startup_dir!=NULL && startup_dir[0])
                    805:                        chdir(startup_dir);
                    806: 
                    807:                lprintf("Node %02d executing external: %s",cfg.node_num,cmdline);
                    808: 
                    809:                argv[0]=cmdline;        /* point to the beginning of the string */
                    810:                argc=1;
                    811:                for(i=0;cmdline[i];i++) /* Break up command line */
                    812:                        if(cmdline[i]==SP) {
                    813:                                cmdline[i]=0;                   /* insert nulls */
                    814:                                argv[argc++]=cmdline+i+1; /* point to the beginning of the next arg */
                    815:                        }
                    816:                argv[argc]=0;
                    817: 
                    818:                if(mode&EX_INR) 
                    819:                        dup2(client_socket,0);  /* redirect stdin to socket */
                    820: 
                    821:                if(mode&EX_OUTR) {
                    822:                        dup2(client_socket,1);  /* stdout */
                    823:                        dup2(client_socket,2);  /* stderr */
                    824:                }       
                    825: 
                    826:                execvp(argv[0],argv);
                    827:                exit(-1);       /* should never get here */
                    828:        }
                    829: 
                    830:        waitpid(pid, &i, 0);
                    831: 
                    832:        pthread_mutex_unlock(&input_thread_mutex);
                    833: 
                    834:        return(WEXITSTATUS(i));
                    835: }
                    836: 
                    837: #endif /* !WIN32 */
                    838: 
                    839: uint fakeriobp=0xffff;
                    840: 
                    841: /*****************************************************************************/
                    842: /* Returns command line generated from instr with %c replacments             */
                    843: /*****************************************************************************/
                    844: char * sbbs_t::cmdstr(char *instr, char *fpath, char *fspec, char *outstr)
                    845: {
                    846:        char    str[256],*cmd;
                    847:     int                i,j,len;
                    848: 
                    849:     if(outstr==NULL)
                    850:         cmd=cmdstr_output;
                    851:     else
                    852:         cmd=outstr;
                    853:     len=strlen(instr);
                    854:     for(i=j=0;i<len && j<sizeof(cmdstr_output);i++) {
                    855:         if(instr[i]=='%') {
                    856:             i++;
                    857:             cmd[j]=0;
                    858:             switch(toupper(instr[i])) {
                    859:                 case 'A':   /* User alias */
                    860:                     strcat(cmd,useron.alias);
                    861:                     break;
                    862:                 case 'B':   /* Baud (DTE) Rate */
                    863:                     strcat(cmd,ultoa(dte_rate,str,10));
                    864:                     break;
                    865:                 case 'C':   /* Connect Description */
                    866:                     strcat(cmd,connection);
                    867:                     break;
                    868:                 case 'D':   /* Connect (DCE) Rate */
                    869:                     strcat(cmd,ultoa((ulong)cur_rate,str,10));
                    870:                     break;
                    871:                 case 'E':   /* Estimated Rate */
                    872:                     strcat(cmd,ultoa((ulong)cur_cps*10,str,10));
                    873:                     break;
                    874:                 case 'F':   /* File path */
                    875:                     strcat(cmd,fpath);
                    876:                     break;
                    877:                 case 'G':   /* Temp directory */
                    878:                     strcat(cmd,cfg.temp_dir);
                    879:                     break;
                    880:                 case 'H':   /* Port Handle or Hardware Flow Control */
                    881:                     strcat(cmd,ultoa(client_socket_dup,str,10));
                    882:                     break;
                    883:                 case 'I':   /* UART IRQ Line */
                    884:                     strcat(cmd,ultoa(cfg.com_irq,str,10));
                    885:                     break;
                    886:                 case 'J':
                    887:                     strcat(cmd,cfg.data_dir);
                    888:                     break;
                    889:                 case 'K':
                    890:                     strcat(cmd,cfg.ctrl_dir);
                    891:                     break;
                    892:                 case 'L':   /* Lines per message */
                    893:                     strcat(cmd,ultoa(cfg.level_linespermsg[useron.level],str,10));
                    894:                     break;
                    895:                 case 'M':   /* Minutes (credits) for user */
                    896:                     strcat(cmd,ultoa(useron.min,str,10));
                    897:                     break;
                    898:                 case 'N':   /* Node Directory (same as SBBSNODE environment var) */
                    899:                     strcat(cmd,cfg.node_dir);
                    900:                     break;
                    901:                 case 'O':   /* SysOp */
                    902:                     strcat(cmd,cfg.sys_op);
                    903:                     break;
                    904:                 case 'P':   /* COM Port */
                    905:                     strcat(cmd,ultoa(online==ON_LOCAL ? 0:cfg.com_port,str,10));
                    906:                     break;
                    907:                 case 'Q':   /* QWK ID */
                    908:                     strcat(cmd,cfg.sys_id);
                    909:                     break;
                    910:                 case 'R':   /* Rows */
                    911:                     strcat(cmd,ultoa(rows,str,10));
                    912:                     break;
                    913:                 case 'S':   /* File Spec */
                    914:                     strcat(cmd,fspec);
                    915:                     break;
                    916:                 case 'T':   /* Time left in seconds */
                    917:                     gettimeleft();
                    918:                     strcat(cmd,ultoa(timeleft,str,10));
                    919:                     break;
                    920:                 case 'U':   /* UART I/O Address (in hex) */
                    921:                     strcat(cmd,ultoa(cfg.com_base,str,16));
                    922:                     break;
                    923:                 case 'V':   /* Synchronet Version */
                    924:                     sprintf(str,"%s%c",VERSION,REVISION);
                    925:                     break;
                    926:                 case 'W':   /* Time-slice API type (mswtype) */
                    927: #if 0 //ndef __FLAT__
                    928:                     strcat(cmd,ultoa(mswtyp,str,10));
                    929: #endif
                    930:                     break;
                    931:                 case 'X':
                    932:                     strcat(cmd,cfg.shell[useron.shell]->code);
                    933:                     break;
                    934:                 case '&':   /* Address of msr */
                    935:                     sprintf(str,"%lu",&fakeriobp);
                    936:                     strcat(cmd,str);
                    937:                     break;
                    938:                 case 'Y':
                    939:                     strcat(cmd,
                    940:                     comspec
                    941:                     );
                    942:                     break;
                    943:                 case 'Z':
                    944:                     strcat(cmd,cfg.text_dir);
                    945:                     break;
                    946:                 case '!':   /* EXEC Directory */
                    947:                     strcat(cmd,cfg.exec_dir);
                    948:                     break;
                    949:                 case '#':   /* Node number (same as SBBSNNUM environment var) */
                    950:                     sprintf(str,"%d",cfg.node_num);
                    951:                     strcat(cmd,str);
                    952:                     break;
                    953:                 case '*':
                    954:                     sprintf(str,"%03d",cfg.node_num);
                    955:                     strcat(cmd,str);
                    956:                     break;
                    957:                 case '$':   /* Credits */
                    958:                     strcat(cmd,ultoa(useron.cdt+useron.freecdt,str,10));
                    959:                     break;
                    960:                 case '%':   /* %% for percent sign */
                    961:                     strcat(cmd,"%");
                    962:                     break;
                    963:                                case '?':       /* Platform */
                    964: #ifdef __OS2__
                    965:                                        strcpy(str,"OS2");
                    966: #else
                    967:                                        strcpy(str,PLATFORM_DESC);
                    968: #endif
                    969:                                        strlwr(str);
                    970:                                        strcat(cmd,str);
                    971:                                        break;
                    972:                 default:    /* unknown specification */
                    973:                     if(isdigit(instr[i])) {
                    974:                         sprintf(str,"%0*d",instr[i]&0xf,useron.number);
                    975:                         strcat(cmd,str); }
                    976:                     break; }
                    977:             j=strlen(cmd); }
                    978:         else
                    979:             cmd[j++]=instr[i]; }
                    980:     cmd[j]=0;
                    981: 
                    982:     return(cmd);
                    983: }
                    984: 

unix.superglobalmegacorp.com

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