|
|
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.