|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.