Commits (1)
  • Rob Swindell's avatar
    Remove the last remnants of Win9x/Me support · 717592bc
    Rob Swindell authored
    Allow "FOSSIL Only" as a configuration option for external programs in SCFG. This is a much easier method of disabling the virtual UART support in the Virtual UART/FOSSIL device driver (if/when necessary) than editing the sbbsexec.ini file (which is still supported).
    717592bc
/* dosxtrn.c */
/* Synchronet External DOS Program Launcher (16-bit MSVC 1.52c project) */
/* $Id: dosxtrn.c,v 1.25 2020/04/15 08:22:33 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
......@@ -42,7 +38,6 @@
#include <dos.h> /* _dos_set/getvect() */
#include <windows.h> /* BOOL, etc. */
#include "vdd_func.h"
#include "execvxd.h"
#include "isvbop.h" /* ddk\inc */
#include "fossdefs.h"
#include "../git_branch.h"
......@@ -65,7 +60,6 @@ static void truncsp(char *str)
}
short vdd=0;
BYTE node_num=0;
int mode=0;
char id_string[128];
#ifdef DEBUG_INT_CALLS
ulong int14calls=0;
......@@ -137,48 +131,6 @@ static int vdd_op(BYTE op)
return(retval);
}
union REGS inregs;
struct SREGS sregs;
BOOL inside_int14=FALSE;
/* This function is only necessary for naughty programs that call the vector
directly instead of issuing an interrupt
*/
void interrupt win95int14(
unsigned _es, unsigned _ds,
unsigned _di, unsigned _si,
unsigned _bp, unsigned _sp,
unsigned _bx, unsigned _dx,
unsigned _cx, unsigned _ax,
unsigned flags )
{
union REGS outregs;
/* prevent recursion, just incase the VXD isn't handling int14h */
if(inside_int14)
return;
inside_int14=TRUE;
inregs.x.ax=_ax;
inregs.x.bx=_bx;
inregs.x.cx=_cx;
inregs.x.dx=_dx;
inregs.x.si=_si;
inregs.x.di=_di;
inregs.x.cflag=flags;
sregs.es=_es;
sregs.ds=_ds;
int86x(0x14,&inregs,&outregs,&sregs);
/* FOSSIL driver only touches these AX and BX */
_ax= outregs.x.ax;
_bx= outregs.x.bx;
inside_int14=FALSE;
}
void vdd_getstatus(vdd_status_t* status)
{
......@@ -500,8 +452,8 @@ int main(int argc, char **argv)
char* envvar[MAX_ENVVARS];
char* arg[MAX_ARGS];
int i,c,d,envnum=0;
int mode = SBBSEXEC_MODE_UNSPECIFIED;
FILE* fp;
BOOL NT=FALSE;
BOOL x64=FALSE;
BOOL success=FALSE;
WORD buf_seg;
......@@ -513,7 +465,7 @@ int main(int argc, char **argv)
,"%s - Copyright %s Rob Swindell\n"
,id_string, __DATE__+7);
fprintf(stderr
,"usage: dosxtrn <path/dosxtrn.env> [NT|95|x64] [node_num] [mode]\n");
,"usage: dosxtrn <path/dosxtrn.env> [NT|x64] [node_num] [mode]\n");
return(1);
}
......@@ -524,16 +476,17 @@ int main(int argc, char **argv)
DllName=dll;
if(argc>2) {
if(strcmp(argv[2],"NT") == 0)
NT=TRUE;
else if(strcmp(argv[2],"x64") == 0)
NT=TRUE, x64=TRUE;
if(strcmp(argv[2],"x64") == 0)
x64=TRUE;
}
if(argc>3)
node_num=atoi(argv[3]);
if(argc>4)
mode=atoi(argv[4]);
if(mode == SBBSEXEC_MODE_UNSPECIFIED)
mode = SBBSEXEC_MODE_DEFAULT;
if((fp=fopen(argv[1],"r"))==NULL) {
fprintf(stderr,"!Error opening %s\n",argv[1]);
return(2);
......@@ -574,76 +527,71 @@ int main(int argc, char **argv)
((BYTE*)int14stub)[7] = FOSSIL_SIGNATURE>>8; /* FOSSIL sig (MSB) */
((BYTE*)int14stub)[8] = FOSSIL_FUNC_HIGHEST; /* FOSSIL highest func supported */
if(NT) { /* Windows NT/2000 */
for(i=0;i<2;i++) {
/* Register VDD */
_asm {
push es
push ds
pop es
mov si, DllName ; ds:si = dll name
mov di, InitFunc ; es:di = init routine
mov bx, DispFunc ; ds:bx = dispatch routine
for(i=0;i<2;i++) {
/* Register VDD */
_asm {
push es
push ds
pop es
mov si, DllName ; ds:si = dll name
mov di, InitFunc ; es:di = init routine
mov bx, DispFunc ; ds:bx = dispatch routine
};
if(!x64) { // NTVDMx64 (based on an older Windows NTVDM) requires an init routine
_asm { /* Vista work-around, apparently doesn't support an InitFunc (RegisterModule fails with AX=1) */
xor di,di
mov es,di
};
if(!x64) { // NTVDMx64 (based on an older Windows NTVDM) requires an init routine
_asm { /* Vista work-around, apparently doesn't support an InitFunc (RegisterModule fails with AX=1) */
xor di,di
mov es,di
};
}
RegisterModule();
_asm {
mov vdd, ax
jc err
mov success, TRUE
err:
pop es
}
if(success)
break;
DllName=VDD_FILENAME; /* try again with no path (for Windows Vista) */
}
if(!success) {
fprintf(stderr,"Error %d loading %s\n",vdd,DllName);
return(-1);
RegisterModule();
_asm {
mov vdd, ax
jc err
mov success, TRUE
err:
pop es
}
if(success)
break;
DllName=VDD_FILENAME; /* try again with no path (for Windows Vista) */
}
if(!success) {
fprintf(stderr,"Error %d loading %s\n",vdd,DllName);
return(-1);
}
#if 0
fprintf(stderr,"vdd handle=%d\n",vdd);
fprintf(stderr,"mode=%d\n",mode);
fprintf(stderr,"vdd handle=%d\n",vdd);
fprintf(stderr,"mode=%d\n",mode);
#endif
vdd_str(VDD_LOAD_INI_FILE, exec_dir);
vdd_str(VDD_LOAD_INI_FILE, exec_dir);
vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
sprintf(str,"%s, rev %u %s/%s, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, mode);
vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"%s, rev %u %s/%s, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, mode);
vdd_str(VDD_DEBUG_OUTPUT, str);
i=vdd_op(VDD_OPEN);
if(i) {
fprintf(stderr,"!VDD_OPEN ERROR: %d\n",i);
UnRegisterModule();
return(-1);
}
oldint16=_dos_getvect(0x16);
oldint21=_dos_getvect(0x21);
oldint29=_dos_getvect(0x29);
if(mode==SBBSEXEC_MODE_FOSSIL) {
*(WORD*)((BYTE*)int14stub+1) = (WORD)winNTint14 - (WORD)&int14stub - 3; /* jmp offset */
_dos_setvect(0x14,(void(interrupt *)())int14stub);
}
_dos_setvect(0x21,winNTint21);
if(mode&SBBSEXEC_MODE_DOS_IN)
_dos_setvect(0x16,winNTint16);
if(mode&SBBSEXEC_MODE_DOS_OUT)
_dos_setvect(0x29,winNTint29);
if(mode & SBBSEXEC_MODE_UART)
vdd_op(VDD_VIRTUALIZE_UART);
i=vdd_op(VDD_OPEN);
if(i) {
fprintf(stderr,"!VDD_OPEN ERROR: %d\n",i);
UnRegisterModule();
return(-1);
}
else if(mode==SBBSEXEC_MODE_FOSSIL) { /* Windows 95/98/Millennium */
*(WORD*)((BYTE*)int14stub+1) = (WORD)win95int14 - (WORD)&int14stub - 3; /* jmp offset */
oldint16=_dos_getvect(0x16);
oldint21=_dos_getvect(0x21);
oldint29=_dos_getvect(0x29);
if(mode & SBBSEXEC_MODE_FOSSIL) {
*(WORD*)((BYTE*)int14stub+1) = (WORD)winNTint14 - (WORD)&int14stub - 3; /* jmp offset */
_dos_setvect(0x14,(void(interrupt *)())int14stub);
}
_dos_setvect(0x21,winNTint21);
if(mode&SBBSEXEC_MODE_DOS_IN)
_dos_setvect(0x16,winNTint16);
if(mode&SBBSEXEC_MODE_DOS_OUT)
_dos_setvect(0x29,winNTint29);
_heapmin();
i=_spawnvp(_P_WAIT, arg[0], arg);
......@@ -659,46 +607,43 @@ int main(int argc, char **argv)
/* Restore original ISRs */
_dos_setvect(0x14,oldint14);
if(NT) {
vdd_op(VDD_CLOSE);
vdd_op(VDD_CLOSE);
_dos_setvect(0x16,oldint16);
_dos_setvect(0x21,oldint21);
_dos_setvect(0x29,oldint29);
_dos_setvect(0x16,oldint16);
_dos_setvect(0x21,oldint21);
_dos_setvect(0x29,oldint29);
sprintf(str,"%s returned %d", arg[0], i);
vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"%s returned %d", arg[0], i);
vdd_str(VDD_DEBUG_OUTPUT, str);
#ifdef DEBUG_INT_CALLS
sprintf(str,"int14h calls: %lu", int14calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int16h calls: %lu", int16calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int21h calls: %lu", int21calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int29h calls: %lu", int29calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int14h calls: %lu", int14calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int16h calls: %lu", int16calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int21h calls: %lu", int21calls); vdd_str(VDD_DEBUG_OUTPUT, str);
sprintf(str,"int29h calls: %lu", int29calls); vdd_str(VDD_DEBUG_OUTPUT, str);
#endif
#ifdef DEBUG_DOS_CALLS
for(i=0;i<0x100;i++) {
if(dos_calls[i]>100) {
sprintf(str,"int21h function %02X calls: %u"
,i, dos_calls[i]);
vdd_str(VDD_DEBUG_OUTPUT, str);
}
for(i=0;i<0x100;i++) {
if(dos_calls[i]>100) {
sprintf(str,"int21h function %02X calls: %u"
,i, dos_calls[i]);
vdd_str(VDD_DEBUG_OUTPUT, str);
}
}
#endif
#ifdef DEBUG_FOSSIL_CALLS
for(i=0;i<0x100;i++) {
if(fossil_calls[i]>0) {
sprintf(str,"int14h function %02X (%-10s) calls: %lu"
,i, fossil_func(i), fossil_calls[i]);
vdd_str(VDD_DEBUG_OUTPUT, str);
}
for(i=0;i<0x100;i++) {
if(fossil_calls[i]>0) {
sprintf(str,"int14h function %02X (%-10s) calls: %lu"
,i, fossil_func(i), fossil_calls[i]);
vdd_str(VDD_DEBUG_OUTPUT, str);
}
}
#endif
/* Unregister VDD */
_asm mov ax, vdd;
UnRegisterModule();
}
/* Unregister VDD */
_asm mov ax, vdd;
UnRegisterModule();
return(i);
}
/* execvxd.h */
/* Synchronet FOSSIL driver (VxD) for Windows 9x API */
/* $Id: execvxd.h,v 1.1.1.1 2000/10/10 11:26:23 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#define SBBSEXEC_VXD "sbbsexec.vxd"
#define SBBSEXEC_IOCTL_START 0x8001
#define SBBSEXEC_IOCTL_COMPLETE 0x8002
#define SBBSEXEC_IOCTL_READ 0x8003
#define SBBSEXEC_IOCTL_WRITE 0x8004
#define SBBSEXEC_IOCTL_DISCONNECT 0x8005
#define SBBSEXEC_IOCTL_STOP 0x8006
#define SBBSEXEC_MODE_FOSSIL (0)
#define SBBSEXEC_MODE_DOS_IN (1<<0)
#define SBBSEXEC_MODE_DOS_OUT (1<<1)
#define SBBSEXEC_MODE_UART (1<<2)
enum {
SBBSEXEC_ERROR_INUSE=1
,SBBSEXEC_ERROR_INBUF
,SBBSEXEC_ERROR_INDATA
,SBBSEXEC_ERROR_IOCTL
,SBBSEXEC_ERROR_OUTBUF
};
typedef struct {
DWORD mode;
HANDLE event;
} sbbsexec_start_t;
extern HANDLE exec_mutex;
@echo off
xcopy sbbsexec.vxd c:\sbbs\exec
/* DEBUGOUT.H */
/* $Id: debugout.h,v 1.1.1.1 2000/10/10 11:27:22 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#ifndef _DEBUGOUT_H_
#define _DEBUGOUT_H_
#ifndef DEBUG_VAR // Pre-define to use different/dynamic debug enable var
#define DEBUG_VAR 0x1
#endif
#ifndef DEVICENAME // Pre-define to display devicename on output
#define DEVICENAME "DBTRACE"
#endif
#ifndef DBTRACEDPF // Pre-define if using other printf type function
#define DBTRACEDPF dprintf
#endif
#ifndef DBTFILEOFF // Pre-define if __FILE__ offset required != 2
#define DBTFILEOFF 2
#endif
#ifndef TEXT // Windows Unicode support
#define TEXT(x) x
#endif
#ifndef DBTRACENL // Pre-define if \n required
#define DBTRACENL TEXT("")
#endif
#if !defined(DBG) && !defined(DEBUG)
#define DBTRACE(b,s); { /* DBTRACE */ }
#define DBTRACEd(b,s,d); { /* DBTRACE */ }
#define DBTRACEs(b,s,t); { /* DBTRACE */ }
#define DBTRACEx(b,s,x); { /* DBTRACE */ }
#define DBTRACEdd(b,s,x,y); { /* DBTRACE */ }
#define DBTRACEds(b,s,x,y); { /* DBTRACE */ }
#define DBTRACEsd(b,s,x,y); { /* DBTRACE */ }
#define DBTRACEdx(b,s,x,y); { /* DBTRACE */ }
#define DBTRACExd(b,s,x,y); { /* DBTRACE */ }
#define DBTRACExx(b,s,x,y); { /* DBTRACE */ }
#define DBTRACEsx(b,s,x,y); { /* DBTRACE */ }
#define DBTRACExs(b,s,x,y); { /* DBTRACE */ }
#define DBTRACEss(b,s,x,y); { /* DBTRACE */ }
#define DBTRACExxd(b,s,x,y,z); { /* DBTRACE */ }
#define DBTRACEddx(b,s,x,y,z); { /* DBTRACE */ }
#define DBTRACEdds(b,s,x,y,z); { /* DBTRACE */ }
#define DBTRACExdd(b,s,x,y,z); { /* DBTRACE */ }
#define DBTRACExxx(b,s,x,y,z); { /* DBTRACE */ }
#define DBTRACExsx(b,s,x,y,z); { /* DBTRACE */ }
#else /* DBG or DEBUG */
#define DBTRACE(b,s); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s) \
,DBTRACENL); } }
#define DBTRACEd(b,s,d); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ") \
TEXT("%d%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),d \
,DBTRACENL); } }
#define DBTRACEs(b,s,t); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%s%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),t \
,DBTRACENL); } }
#define DBTRACEx(b,s,x); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%02X%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x \
,DBTRACENL); } }
#define DBTRACEdd(b,s,x,y); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%d %d%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,y \
,DBTRACENL); } }
#define DBTRACEds(b,s,x,y); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%d %s%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,y \
,DBTRACENL); } }
#define DBTRACEsd(b,s,x,y); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%s %d%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,y \
,DBTRACENL); } }
#define DBTRACEdx(b,s,x,y); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%d %X%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,y \
,DBTRACENL); } }
#define DBTRACExd(b,s,x,y); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %d%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,y \
,DBTRACENL); } }
#define DBTRACExx(b,s,x,y); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %X%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,y \
,DBTRACENL); } }
#define DBTRACEsx(b,s,t,x); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%s %X%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),t,x \
,DBTRACENL); } }
#define DBTRACExs(b,s,x,t); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %s%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,t \
,DBTRACENL); } }
#define DBTRACEss(b,s,x,t); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%s %s%s") \
,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) \
,__LINE__,TEXT(s),x,t \
,DBTRACENL); } }
#define DBTRACEddx(b,s,x,y,z); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%d %d %X%s") \
,DEVICENAME \
,TEXT(__FILE__+DBTFILEOFF),__LINE__ \
,TEXT(s),x,y,z \
,DBTRACENL); } }
#define DBTRACEdds(b,s,x,y,z); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%d %d %s%s") \
,DEVICENAME \
,TEXT(__FILE__+DBTFILEOFF),__LINE__ \
,TEXT(s),x,y,z \
,DBTRACENL); } }
#define DBTRACExdd(b,s,x,y,z); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %d %d%s") \
,DEVICENAME \
,TEXT(__FILE__+DBTFILEOFF),__LINE__ \
,TEXT(s),x,y,z \
,DBTRACENL); } }
#define DBTRACExxd(b,s,x,y,z); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %X %d%s") \
,DEVICENAME \
,TEXT(__FILE__+DBTFILEOFF),__LINE__ \
,TEXT(s),x,y,z \
,DBTRACENL); } }
#define DBTRACExxx(b,s,x,y,z); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %X %X%s") \
,DEVICENAME \
,TEXT(__FILE__+DBTFILEOFF),__LINE__ \
,TEXT(s),x,y,z \
,DBTRACENL); } }
#define DBTRACExsx(b,s,x,t,z); { if(DEBUG_VAR&(1<<b)) { \
DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
TEXT("%X %s %X%s") \
,DEVICENAME \
,TEXT(__FILE__+DBTFILEOFF),__LINE__ \
,TEXT(s),x,t,z \
,DBTRACENL); } }
#endif
#endif // Don't add anything after this line
# makefile for SBBSEXEC.VXD
DEVICENAME = SBBSEXEC
FRAMEWORK = CPP
XFLAGS = -I..
OBJECTS = sbbsexec.obj ringbuf.obj
SOURCEINCPATH = ..
DEBUG = 0
DYNAMIC = 1
!include $(VTOOLSD)\include\vtoolsd.mak
!include $(VTOOLSD)\include\vxdtarg.mak
sbbsexec.obj: sbbsexec.cpp makefile
ringbuf.obj: ..\ringbuf.c ..\ringbuf.h
// SBBSEXEC.cpp - SBBSEXEC.VXD main module
/* Synchronet Windows 9X FOSSIL driver (requires VtoolsD C++ framework) */
/* $Id: sbbsexec.cpp,v 1.3 2018/07/24 01:11:52 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#define DEVICE_MAIN
#include "sbbsexec.h"
#include "debugout.h"
#include "..\ringbuf.h"
#define RINGBUF_SIZE_IN 10000
#define RINGBUF_SIZE_OUT 10000
#undef DEVICENAME
#define DEVICENAME "SBBSEXEC" // For debug output
#include LOCKED_CODE_SEGMENT
#include LOCKED_DATA_SEGMENT
#define MAX_VM 250
typedef struct {
VMHANDLE handle;
SEMHANDLE input_sem;
SEMHANDLE output_sem;
DWORD mode;
BOOL online;
BOOL overrun;
RingBuf in;
RingBuf out;
} vm_t;
vm_t vm[MAX_VM];
Declare_Virtual_Device(SBBSExec)
//////////////////////////////////////////////////////////////////////////
#include LOCKED_CODE_SEGMENT
#include LOCKED_DATA_SEGMENT
vm_t* new_vm;
sbbsexec_start_t start;
vm_t* find_vm(VMHANDLE hVM)
{
int i;
for(i=0;i<MAX_VM;i++)
if(vm[i].handle==hVM)
return(&vm[i]);
#if 0
if(hVM!=Get_Sys_VM_Handle()) {
DBTRACEx(0,"!VM NOT FOUND",hVM);
}
#endif
return(NULL);
}
BOOL SBBSExec::OnSysDynamicDeviceInit()
{
DBTRACE(0,"OnSysDynamicDeviceInit");
return(OnDeviceInit(NULL,NULL));
}
BOOL SBBSExec::OnDeviceInit(VMHANDLE hSysVM, PCHAR pszCmdTail)
{
DBTRACE(0,"SBBSExec::OnDeviceInit");
pInt10 = NULL; // BIOS I/O
pInt14 = NULL; // FOSSIL
pInt16 = NULL; // Keyboard input
pInt21 = NULL; // DOS I/O
pInt29 = NULL; // Direct console I/O (PKZIP/UNZIP)
memset(&start,0,sizeof(start));
#if 1
if ( (pInt21 = new SBBSExecInt21()) == NULL) {
DBTRACE(0,"!Failed to create int 21 handler");
UnhookInts();
return(FALSE);
}
if ( !pInt21->hook()) {
DBTRACE(0,"!Failed to hook int 21");
UnhookInts();
return(FALSE);
}
if ( (pInt29 = new SBBSExecInt29()) == NULL) {
DBTRACE(0,"!Failed to create int 29 handler");
UnhookInts();
return(FALSE);
}
if ( !pInt29->hook()) {
DBTRACE(0,"!Failed to hook int 29");
UnhookInts();
return(FALSE);
}
if ( (pInt16 = new SBBSExecInt16()) == NULL) {
DBTRACE(0,"!Failed to create int 16 handler");
UnhookInts();
return(FALSE);
}
if ( !pInt16->hook()) {
DBTRACE(0,"!Failed to hook int 16");
UnhookInts();
return(FALSE);
}
if ( (pInt14 = new SBBSExecInt14()) == NULL) {
DBTRACE(0,"!Failed to create int 14 handler");
UnhookInts();
return(FALSE);
}
if ( !pInt14->hook()) {
DBTRACE(0,"!Failed to hook int 14");
UnhookInts();
return(FALSE);
}
if ( (pInt10 = new SBBSExecInt10()) == NULL) {
DBTRACE(0,"!Failed to create int 10 handler");
UnhookInts();
return(FALSE);
}
if ( !pInt10->hook()) {
DBTRACE(0,"!Failed to hook int 10");
UnhookInts();
return(FALSE);
}
#endif
return TRUE;
}
//****************************************************************************
//****************************************************************************
VOID SBBSExec::OnSystemExit(VMHANDLE hSysVM)
{
DBTRACE(0,"OnSystemExit");
OnSysDynamicDeviceExit();
}
void SBBSExec::UnhookInts()
{
if(pInt10!=NULL) {
pInt10->unhook();
delete pInt10;
pInt10=NULL;
}
if(pInt14!=NULL) {
pInt14->unhook();
delete pInt14;
pInt14=NULL;
}
if(pInt16!=NULL) {
pInt16->unhook();
delete pInt16;
pInt16=NULL;
}
if(pInt21!=NULL) {
pInt21->unhook();
delete pInt21;
pInt21=NULL;
}
if(pInt29!=NULL) {
pInt29->unhook();
delete pInt29;
pInt29=NULL;
}
}
//****************************************************************************
// Handle control message SYS_DYNAMIC_DEVICE_EXIT
//****************************************************************************
BOOL SBBSExec::OnSysDynamicDeviceExit()
{
DBTRACE(0,"OnSysDynamicDeviceExit");
UnhookInts();
return(TRUE);
}
//////////////////////////////////////////////////////////////////////////
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExec::OnCreateVM(VMHANDLE hVM)
{
DBTRACExd(0,"CreateVM, handle, time",hVM,Get_System_Time());
DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle());
if(start.event) {
new_vm=find_vm(NULL);
if(new_vm==NULL) {
DBTRACE(0,"!NO AVAILABLE VM structures");
return(FALSE);
}
new_vm->handle=hVM;
new_vm->mode=start.mode;
new_vm->online = true;
new_vm->overrun = false;
new_vm->input_sem = NULL;
new_vm->output_sem = NULL;
if(RingBufInit(&new_vm->in, RINGBUF_SIZE_IN)!=0
|| RingBufInit(&new_vm->out, RINGBUF_SIZE_OUT)!=0) {
DBTRACE(0,"!FAILED to create I/O buffers");
return(FALSE);
}
if(!VWIN32_SetWin32Event(start.event)) {
DBTRACEx(0,"!FAILED TO SET EVENT handle", start.event);
return(FALSE);
}
if(!VWIN32_CloseVxDHandle(start.event)) {
DBTRACEx(0,"!FAILED TO CLOSE EVENT handle", start.event);
return(FALSE);
}
start.event=0;
}
return(TRUE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt29::SBBSExecInt29() : VPreChainV86Int(0x29)
{
DBTRACE(0,"SBBSExecInt29 constructor");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExecInt29::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
vm_t* vm = find_vm(hVM);
if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
return(FALSE); // Tells VMM that interrupt was not handled
}
if(!RingBufFree(&vm->out)) {
DBTRACEx(0,"!Int29 OUTPUT BUFFER OVERFLOW, hVM", hVM);
vm->overrun=true;
return(FALSE);
}
DBTRACEx(1,"Int29 OUTPUT", _clientAL);
BYTE ch=_clientAL;
RingBufWrite(&vm->out,&ch,1);
vm->overrun=false;
return(FALSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt21::SBBSExecInt21() : VPreChainV86Int(0x21)
{
DBTRACE(0,"SBBSExecInt21 constructor");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExecInt21::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
BYTE ch;
BYTE* buffer;
WORD buflen;
vm_t* vm = find_vm(hVM);
if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
#if 0
if(vm && !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
DBTRACEx(0,"Int21 on unsupported VM", hVM);
}
#endif
return(FALSE); // Tells VMM that interrupt was not handled
}
DBTRACEx(1,"Int21 function", _clientAH);
DWORD avail = RingBufFree(&vm->out);
switch(_clientAH) {
case 0x01:
DBTRACE(0,"!Int21 Char input WITH echo");
break;
case 0x06: // Direct console I/O
DBTRACEx(0,"DOS DIRECT CONSOLE IO, DL", _clientDL);
if(_clientDL==0xff) {
avail=RingBufFull(&vm->in);
if(avail) {
DBTRACEd(0,"avail",avail);
RingBufRead(&vm->in, &ch, 1);
_clientFlags&=~(1<<6); // clear zero flag
_clientAX=ch;
return(TRUE);
}
break;
}
// fall-through
case 0x02: // Character output
DBTRACEx(1,"Int21 function", _clientAH);
if(!avail) {
DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
vm->overrun=true;
break;
}
ch=_clientDL;
RingBufWrite(&vm->out,&ch,1);
vm->overrun=false;
break;
case 0x09: // Display string
DBTRACE(0,"!Int21 func 09 - DISPLAY STRING");
break;
case 0x0A: // Buffered keyboard input
DBTRACE(0,"Int21 Func 0A - Buffered Keyboard Input");
/* Need to get a string from the user, echo, and copy to DS:DX */
/* byte 0 = max length, byte 1 = actual read (minus CR) */
break;
case 0x40: // Write file or device
if(_clientBX!=1 && _clientBX!=2) { // !stdout and !stderr
DBTRACEd(1,"!Int21 write to unsupported device", _clientBX);
break;
}
DBTRACEdd(1,"Int21 write file", _clientBX, _clientCX);
buffer = (BYTE*)MAPFLAT(CRS.Client_DS, CWRS.Client_DX);
buflen = _clientCX;
if(avail<buflen) {
DBTRACEd(0,"!OUTPUT BUFFER OVERFLOW, avail", avail);
vm->overrun=true;
if(!avail)
break;
buflen=avail;
}
RingBufWrite(&vm->out,buffer,buflen);
vm->overrun=false;
break;
}
return(FALSE); // Tells VMM that interrupt was not handled
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt16::SBBSExecInt16() : VPreChainV86Int(0x16)
{
DBTRACE(0,"SBBSExecInt16 constructor");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExecInt16::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
BYTE ch;
DWORD avail;
vm_t* vm = find_vm(hVM);
if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_IN)) {
return(FALSE); // Tells VMM that interrupt was not handled
}
// DBTRACExx(0,"Int16 (hVM, AX)", hVM, _clientAX);
avail=RingBufFull(&vm->in);
switch(_clientAH) {
case 0x00: // Read char from keyboard
case 0x10: // Read char from enhanced keyboard
if(avail) {
RingBufRead(&vm->in, &ch, 1);
_clientAX=ch;
return(TRUE);
}
break;
case 0x01: // Get keyboard status
case 0x11: // Get enhanced keyboard status
if(avail) {
RingBufPeek(&vm->in, &ch, 1);
_clientFlags&=~(1<<6); // clear zero flag
_clientAX=ch;
return(TRUE);
}
break;
default:
DBTRACEx(0,"!UNHANDLED INT16 function", _clientAH);
break;
}
return(FALSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt14::SBBSExecInt14() : VPreChainV86Int(0x14)
{
DBTRACE(0,"SBBSExecInt14 constructor");
}
WORD PortStatus(vm_t* vm)
{
WORD status=0x0008; // AL bit 3 (change in DCD) always set
if(vm->online) // carrier detect
status|=0x0080; // DCD
if(RingBufFull(&vm->in)) // receive data ready
status|=0x0100; // RDA
if(vm->overrun) // overrun error detected
status|=0x0200; // OVRN
if(RingBufFree(&vm->out)> // room available in output buffer
RINGBUF_SIZE_OUT/2)
status|=0x2000; // THRE
if(!RingBufFull(&vm->out)) // output buffer is empty
status|=0x4000; // TSRE
return(status);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* fossil_id="Synchronet SBBSEXEC.VXD Fossil";
BOOL SBBSExecInt14::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
BYTE* buffer;
BYTE ch;
WORD buflen;
WORD rd,wr;
WORD avail;
vm_t* vm = find_vm(hVM);
if(vm==NULL || vm->mode!=SBBSEXEC_MODE_FOSSIL) {
return(FALSE); // Tells VMM that interrupt was not handled
}
DBTRACEx(4,"Int14 func",_clientAH);
switch(_clientAH) {
case 0x00: /* Initialize/Set baud rate */
DBTRACE(0,"Int14 init");
_clientAX=PortStatus(vm);
break;
case 0x01: /* write char to com port */
if(RingBufFree(&vm->out)<2) {
DBTRACEx(1,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
vm->output_sem=Create_Semaphore(0);
Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE);
Destroy_Semaphore(vm->output_sem);
vm->output_sem=NULL;
if(!vm->online) {
DBTRACE(0,"!USER HUNG UP");
return(true);
}
}
ch=_clientAL;
RingBufWrite(&vm->out,&ch,1);
#if 0 /* Now done in SBBS.DLL/XTRN.CPP */
if(ch==0xff) { /* escape TELNET IAC */
RingBufWrite(&vm->out,&ch,1);
DBTRACE(1,"Escaped IAC in output stream");
}
#endif
vm->overrun=false;
_clientAX=PortStatus(vm);
break;
case 0x02: /* read char from com port */
if(!RingBufFull(&vm->in)) {
DBTRACEx(0,"Waiting on input semaphore, hVM", hVM);
vm->input_sem=Create_Semaphore(0);
Wait_Semaphore(vm->input_sem,BLOCK_THREAD_IDLE);
Destroy_Semaphore(vm->input_sem);
vm->input_sem=NULL;
#if 0
_clientAH=0x80; /* timed-out */
return(TRUE);
#endif
}
RingBufRead(&vm->in,&ch,1);
_clientAH=0;
_clientAL=ch;
break;
case 0x03: /* request status */
_clientAX=PortStatus(vm);
break;
case 0x04: /* initialize */
DBTRACE(0,"Int14 func 4 init");
_clientAX=0x1954; /* magic number = success */
_clientBH=5; /* FOSSIL rev */
_clientBL=0x1B; /* maximum FOSSIL func supported */
break;
case 0x08: // flush output buffer
DBTRACE(0,"Int14 FLUSH OUTPUT BUFFER");
vm->output_sem=Create_Semaphore(0);
Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE);
Destroy_Semaphore(vm->output_sem);
vm->output_sem=NULL;
break;
case 0x09: // purge output buffer
DBTRACE(0,"Int14 PURGE OUTPUT BUFFER");
RingBufReInit(&vm->out);
break;
case 0x0A: // purge input buffer
DBTRACE(0,"Int14 PURGE INPUT BUFFER");
RingBufReInit(&vm->in);
break;
case 0x0B: /* write char to com port, no wait */
if(RingBufFree(&vm->out)<2) {
_clientAX=0; // char was not accepted
break;
}
ch=_clientAL;
RingBufWrite(&vm->out,&ch,1);
#if 0 /* Now done in SBBS.DLL/XTRN.CPP */
if(ch==0xff) { /* escape TELNET IAC */
RingBufWrite(&vm->out,&ch,1);
DBTRACE(1,"Escaped IAC in output stream");
}
#endif
_clientAX=1; // char was accepted
break;
case 0x0C: // non-destructive read-ahead
if(!RingBufFull(&vm->in)) {
_clientAX=0xffff; // no char available
break;
}
RingBufPeek(&vm->in,&ch,1);
_clientAH=0;
_clientAL=ch;
break;
case 0x13: /* write to display */
dprintf("%c",_clientAL);
break;
case 0x18: /* read bock */
rd=_clientCX;
avail=RingBufFull(&vm->in);
if(rd>avail)
rd=avail;
if(rd) {
buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
rd = RingBufRead(&vm->in, buffer, rd);
}
_clientAX = rd;
break;
case 0x19: /* write block */
wr=_clientCX;
avail=RingBufFree(&vm->out);
if(wr>avail)
wr=avail;
if(wr) {
buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
wr = RingBufWrite(&vm->out, buffer, wr);
}
_clientAX = wr;
break;
#if 1
case 0x1B: // driver info
{
DBTRACE(1,"Int14 driver info");
struct {
WORD info_size;
BYTE curr_fossil;
BYTE curr_rev;
DWORD id_string;
WORD inbuf_size;
WORD inbuf_free;
WORD outbuf_size;
WORD outbuf_free;
BYTE screen_width;
BYTE screen_height;
BYTE baud_rate;
} info={ sizeof(info), 5, 1, 0
,RINGBUF_SIZE_IN-1, RingBufFree(&vm->in)
,RINGBUF_SIZE_OUT-1, RingBufFree(&vm->out)
,80,25
,1 // 38400
};
// Map_Lin_To_VM_Addr
buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
wr=sizeof(info);
if(wr>_clientCX)
wr=_clientCX;
memcpy(buffer, &info, wr);
_clientAX=wr;
break;
}
#endif
default:
DBTRACEx(0,"!UNHANDLED INTERRUPT 14h function",_clientAH);
break;
}
return(TRUE); // Tells VMM that interrupt was handled
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt10::SBBSExecInt10() : VPreChainV86Int(0x10)
{
DBTRACE(0,"SBBSExecInt10 constructor");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExecInt10::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
BYTE ch;
DWORD avail;
vm_t* vm = find_vm(hVM);
if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
return(FALSE); // Tells VMM that interrupt was not handled
}
avail=RingBufFree(&vm->out);
switch(_clientAH) {
case 0x02: // Set Cursor Position
DBTRACE(1,"Int10 func 2 - Set cursor position");
break;
case 0x09: // Write char and attr at cursor
DBTRACE(1,"Int10 func 9 - Write char and attr at curosr");
case 0x10: // Write char at cursor
#if 0
DBTRACE(1,"Int10 func 9 - Write char at curosr");
if(!avail) {
DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
vm->overrun=true;
break;
}
ch=_clientAL;
RingBufWrite(&vm->out,&ch,1);
vm->overrun=false;
#endif
break;
}
return(FALSE);
}
DWORD SBBSExec::OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL)
{
DWORD rd;
DWORD wr;
DWORD avail;
vm_t* vm;
// DBTRACEd(0,"SBBSEXEC ioctl"
//,pIOCTL->dioc_IOCtlCode);
switch(pIOCTL->dioc_IOCtlCode) {
case DIOC_OPEN:
DBTRACEd(0,"IOCTL: OPEN",Get_System_Time());
break;
case DIOC_CLOSEHANDLE:
DBTRACEd(0,"IOCTL: CLOSE",Get_System_Time());
break;
case SBBSEXEC_IOCTL_START:
DBTRACEd(0,"IOCTL: START",Get_System_Time());
DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle());
if(start.event) {
DBTRACE(0,"Exec already started!");
return(SBBSEXEC_ERROR_INUSE);
}
if (pIOCTL->dioc_InBuf==NULL
|| pIOCTL->dioc_cbInBuf!=sizeof(start)) {
return(SBBSEXEC_ERROR_INBUF);
}
start=*(sbbsexec_start_t*)pIOCTL->dioc_InBuf;
break;
case SBBSEXEC_IOCTL_COMPLETE:
DBTRACEd(0,"IOCTL: COMPLETE",Get_System_Time());
if(start.event || new_vm==NULL) {
DBTRACE(0,"!VM never created");
start.event=0;
return(SBBSEXEC_ERROR_INUSE);
}
if(pIOCTL->dioc_OutBuf==NULL
|| pIOCTL->dioc_cbOutBuf<sizeof(VMHANDLE)) {
DBTRACE(0,"!Invalid OUTBUF");
return(SBBSEXEC_ERROR_OUTBUF);
}
*(VMHANDLE*)pIOCTL->dioc_OutBuf=new_vm->handle;
DBTRACEx(0,"CREATED VM HANDLE", new_vm->handle);
new_vm=NULL;
if(pIOCTL->dioc_bytesret!=NULL)
*pIOCTL->dioc_bytesret = sizeof(VMHANDLE);
break;
case SBBSEXEC_IOCTL_READ:
if (pIOCTL->dioc_InBuf==NULL
|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
DBTRACE(0,"!INVALID INBUF");
return(SBBSEXEC_ERROR_INBUF);
}
if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf==0) {
DBTRACE(0,"!INVALID OUTBUF");
return(SBBSEXEC_ERROR_OUTBUF);
}
vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
if(vm==NULL) {
DBTRACE(0,"!NO VM LIST");
return(SBBSEXEC_ERROR_INDATA);
}
rd = RingBufFull(&vm->out);
if(rd>pIOCTL->dioc_cbOutBuf) {
DBTRACEdd(0,"Reducing read size"
,rd, pIOCTL->dioc_cbOutBuf);
rd=pIOCTL->dioc_cbOutBuf;
}
RingBufRead(&vm->out, (BYTE*)pIOCTL->dioc_OutBuf, rd);
if(pIOCTL->dioc_bytesret!=NULL)
*pIOCTL->dioc_bytesret = rd;
if(vm->output_sem!=NULL) // Wake up int14 handler
Signal_Semaphore(vm->output_sem);
if(rd>1) {
DBTRACEd(1,"IOCTL_READ bytes", rd);
}
break;
case SBBSEXEC_IOCTL_WRITE:
if (pIOCTL->dioc_InBuf==NULL
|| pIOCTL->dioc_cbInBuf<sizeof(VMHANDLE)+1) {
DBTRACE(0,"!INVALID INBUF");
return(SBBSEXEC_ERROR_INBUF);
}
if (pIOCTL->dioc_OutBuf==NULL
|| pIOCTL->dioc_cbOutBuf!=sizeof(DWORD)) {
DBTRACE(0,"!INVALID OUTBUF");
return(SBBSEXEC_ERROR_OUTBUF);
}
vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
if(vm==NULL) {
DBTRACE(0,"!NO VM LIST");
return(SBBSEXEC_ERROR_INDATA);
}
wr = pIOCTL->dioc_cbInBuf-sizeof(VMHANDLE);
avail = RingBufFree(&vm->in);
if(wr>avail) {
DBTRACEdd(0,"Reducing write size", wr, avail);
wr=avail;
}
RingBufWrite(&vm->in, (BYTE*)pIOCTL->dioc_InBuf+sizeof(VMHANDLE), wr);
*(DWORD *)pIOCTL->dioc_OutBuf = wr;
if(pIOCTL->dioc_bytesret!=NULL)
*pIOCTL->dioc_bytesret = sizeof(DWORD);
if(vm->input_sem!=NULL) // Wake up int14 handler
Signal_Semaphore(vm->input_sem);
// Wake up the VDM (improves keyboard response - dramatically!)
Wake_Up_VM(vm->handle);
break;
case SBBSEXEC_IOCTL_DISCONNECT:
DBTRACEd(0,"IOCTL: DISCONNECT",Get_System_Time());
if (pIOCTL->dioc_InBuf==NULL
|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
DBTRACE(0,"!INVALID INBUF");
return(SBBSEXEC_ERROR_INBUF);
}
vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
if(vm==NULL) {
DBTRACE(0,"!NO VM LIST");
return(SBBSEXEC_ERROR_INDATA);
}
vm->online=false;
if(vm->input_sem!=NULL) // Wake up int14 handler
Signal_Semaphore(vm->input_sem);
if(vm->output_sem!=NULL) // Wake up int14 handler
Signal_Semaphore(vm->output_sem);
break;
case SBBSEXEC_IOCTL_STOP:
DBTRACEd(0,"IOCTL: STOP",Get_System_Time());
if (pIOCTL->dioc_InBuf==NULL
|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
DBTRACE(0,"!INVALID INBUF");
return(SBBSEXEC_ERROR_INBUF);
}
vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
if(vm==NULL) {
DBTRACE(0,"!NO VM LIST");
return(SBBSEXEC_ERROR_INDATA);
}
DBTRACEx(0,"CLOSING VM HANDLE", vm->handle);
vm->handle=NULL; // Mark as available
RingBufDispose(&vm->in);
RingBufDispose(&vm->out);
if(vm->input_sem!=NULL) // Wake up int14 handler
Signal_Semaphore(vm->input_sem);
if(vm->output_sem!=NULL) // Wake up int14 handler
Signal_Semaphore(vm->output_sem);
vm->input_sem=NULL;
vm->output_sem=NULL;
break;
default:
DBTRACEdx(0,"!UNKNOWN IOCTL"
,pIOCTL->dioc_IOCtlCode,pIOCTL->dioc_IOCtlCode);
return(SBBSEXEC_ERROR_IOCTL);
}
return (0); // DEVIOCTL_NOERROR);
}
// sbbsexec.h - include file for SBBSEXEC
/* Synchronet Windows 9X FOSSIL driver (requires VtoolsD C++ framework) */
/* $Id: sbbsexec.h,v 1.2 2001/05/02 01:58:31 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
////////////////////////////////////////////////////////////////////////
// Basic defintions for VToolsD framework
#include <vtoolscp.h>
#define DEVICE_CLASS SBBSExec
#define SBBSExec_DeviceID UNDEFINED_DEVICE_ID
#define SBBSExec_Major 1
#define SBBSExec_Minor 1
#define SBBSExec_Init_Order UNDEFINED_INIT_ORDER
#include "..\execvxd.h" // sbbsexec_start_t definition
#include "..\ringbuf.h" // RingBuf/RingBuffer
////////////////////////////////////////////////////////////////////////
class SBBSExec : public VDevice
{
public:
virtual BOOL OnDeviceInit(VMHANDLE hSysVM, PCHAR pszCmdTail);
virtual BOOL OnSysDynamicDeviceInit();
virtual void OnSystemExit(VMHANDLE hSysVM);
virtual BOOL OnSysDynamicDeviceExit();
virtual BOOL OnCreateVM(VMHANDLE hVM);
virtual DWORD OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL);
void UnhookInts(void);
// Variables
class SBBSExecInt29* pInt29;
class SBBSExecInt21* pInt21;
class SBBSExecInt16* pInt16;
class SBBSExecInt14* pInt14;
class SBBSExecInt10* pInt10;
};
class SBBSExecInt29 : public VPreChainV86Int
{
public:
SBBSExecInt29();
virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
};
class SBBSExecInt21 : public VPreChainV86Int
{
public:
SBBSExecInt21();
virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
};
class SBBSExecInt16 : p