|
|
1.1 root 1: /* sbbsexec.c */
2:
3: /* Synchronet Windows NT/2000 VDD for FOSSIL and DOS I/O Interrupts */
4:
1.1.1.2 ! root 5: /* $Id: sbbsexec.c,v 1.39 2007/03/11 01:49:15 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 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 <windows.h>
39: #include <stdio.h>
40: #include <vddsvc.h>
41: #include "uartdefs.h"
42: #include "vdd_func.h"
43: #include "ringbuf.h"
44: #include "genwrap.h"
45: #include "dirwrap.h"
46: #include "threadwrap.h"
47: #include "ini_file.h"
48:
49: #define INI_FILENAME "sbbsexec.ini"
50: #define RINGBUF_SIZE_IN 10000
51: #define DEFAULT_MAX_MSG_SIZE 4000
52: #define LINEAR_RX_BUFLEN 5000
53:
54: /* UART Parameters and virtual registers */
55: WORD uart_io_base = UART_COM1_IO_BASE; /* COM1 */
56: BYTE uart_irq = UART_COM1_IRQ;
57: BYTE uart_ier_reg = 0;
58: BYTE uart_lcr_reg = UART_LCR_8_DATA_BITS;
59: BYTE uart_mcr_reg = UART_MCR_RTS | UART_MCR_DTR;
60: BYTE uart_lsr_reg = UART_LSR_EMPTY_DATA | UART_LSR_EMPTY_XMIT;
61: BYTE uart_msr_reg = UART_MSR_CTS | UART_MSR_DSR;
62: BYTE uart_scratch_reg = 0;
63: BYTE uart_divisor_latch_lsb = 0x03; /* 38400 */
64: BYTE uart_divisor_latch_msb = 0x00;
65:
66: #if defined (_DEBUG)
67: int log_level = LOG_DEBUG;
68: #else
69: int log_level = LOG_WARNING;
70: #endif
71:
72: BOOL virtualize_uart=TRUE;
73: double yield_interval=1.0;
74: BOOL hangup_supported=TRUE;
75: HANDLE hangup_event=NULL;
76: HANDLE hungup_event=NULL;
77: HANDLE interrupt_event=NULL;
78: HANDLE rdslot=INVALID_HANDLE_VALUE;
79: HANDLE wrslot=INVALID_HANDLE_VALUE;
80: RingBuf rdbuf;
81: str_list_t ini;
82: char ini_fname[MAX_PATH+1];
83: char revision[16];
84:
85: void lputs(int level, char* msg)
86: {
87: char buf[1024];
88: if(level > log_level)
89: return;
90:
91: SAFEPRINTF(buf,"SBBS: %s\r\n", msg);
92: OutputDebugString(buf);
93: }
94:
95: static void lprintf(int level, const char *fmt, ...)
96: {
97: char sbuf[1024];
98: va_list argptr;
99:
100: if(level > log_level)
101: return;
102:
103: va_start(argptr,fmt);
104: _vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
105: sbuf[sizeof(sbuf)-1]=0;
106: va_end(argptr);
107: lputs(level,sbuf);
108: }
109:
110: void hangup()
111: {
112: if(hangup_supported && hangup_event!=NULL) {
113: lprintf(LOG_DEBUG,"Hanging-up at application request");
114: SetEvent(hangup_event);
115: }
116: }
117:
118: void parse_ini(char* program)
119: {
120: char section[MAX_PATH+1];
121:
122: if(ini==NULL) /* no initialization file */
123: return;
124:
125: /* Read the root section of the sbbsexec.ini file */
126: log_level=iniGetLogLevel(ini,program,"LogLevel",log_level);
127: if(iniGetBool(ini,program,"Debug",FALSE))
128: log_level=LOG_DEBUG;
129: yield_interval=iniGetFloat(ini,program,"YieldInterval",yield_interval);
130: hangup_supported=iniGetBool(ini,program,"CanDisconnect",hangup_supported);
131:
132: lprintf(LOG_INFO,"Parsed %s section of %s"
133: ,program==ROOT_SECTION ? "root" : program
134: ,ini_fname);
135:
136: /* [UART] section */
137: if(program==ROOT_SECTION)
138: SAFECOPY(section,"UART");
139: else
140: SAFEPRINTF(section,"%s.UART",program);
141:
142: virtualize_uart=iniGetBool(ini,section,"Virtualize",virtualize_uart);
143: switch(iniGetInteger(ini,section,"ComPort",0)) {
144: case 1: /* COM1 */
145: uart_irq =UART_COM1_IRQ;
146: uart_io_base =UART_COM1_IO_BASE;
147: break;
148: case 2: /* COM2 */
149: uart_irq =UART_COM2_IRQ;
150: uart_io_base =UART_COM2_IO_BASE;
151: break;
152: case 3: /* COM3 */
153: uart_irq =UART_COM3_IRQ;
154: uart_io_base =UART_COM3_IO_BASE;
155: break;
156: case 4: /* COM4 */
157: uart_irq =UART_COM4_IRQ;
158: uart_io_base =UART_COM4_IO_BASE;
159: break;
160: }
161: uart_irq=(BYTE)iniGetShortInt(ini,section,"IRQ",uart_irq);
162: uart_io_base=iniGetShortInt(ini,section,"Address",uart_io_base);
163:
164: lprintf(LOG_INFO,"Parsed %s section of %s"
165: ,section
166: ,ini_fname);
167: }
168:
169:
170: /* Mutex-protected pending interrupt "queue" */
171: int pending_interrupts = 0;
172: CRITICAL_SECTION interrupt_mutex;
173:
174: void set_interrupt_pending(BYTE intr, BOOL assert)
175: {
176: EnterCriticalSection(&interrupt_mutex);
177: lprintf(LOG_DEBUG,"%sasserting interrupt %02X (pending: %02X, IER: %02X)"
178: ,assert ? "" : "de-", intr
179: ,pending_interrupts
180: ,uart_ier_reg);
181: if(assert) {
182: if(uart_ier_reg&intr) { /* is interrupt enabled? */
183: pending_interrupts |= intr; /* flag as pending */
184: SetEvent(interrupt_event);
185: }
186: } else /* de-assert */
187: pending_interrupts &= ~intr; /* remove as pending */
188:
189: LeaveCriticalSection(&interrupt_mutex);
190: }
191:
192: #define assert_interrupt(i) set_interrupt_pending(i, TRUE)
193: #define deassert_interrupt(i) set_interrupt_pending(i, FALSE)
194:
195: void _cdecl interrupt_thread(void *arg)
196: {
197: while(1) {
198: if(WaitForSingleObject(interrupt_event,INFINITE)!=WAIT_OBJECT_0)
199: break;
200: if((uart_ier_reg&pending_interrupts) != 0) {
201: lprintf(LOG_DEBUG,"VDDSimulateInterrupt (pending: %02X) - IER: %02X"
202: ,pending_interrupts, uart_ier_reg);
203: VDDSimulateInterrupt(ICA_MASTER, uart_irq, /* count: */1);
204: }
205: #if 0
206: /* "Real 16550s should always reassert
207: * this interrupt whenever the transmitter is idle and
208: * the interrupt is enabled."
209: */
210: if(pending_interrupts==0 && uart_ier_reg&UART_IER_TX_EMPTY)
211: pending_interrupts|=UART_IER_TX_EMPTY;
212: #endif
213: }
214: }
215:
216: void _cdecl input_thread(void* arg)
217: {
218: char buf[LINEAR_RX_BUFLEN];
219: int count;
220:
221: while(1) {
222: count=0;
223: if(!ReadFile(rdslot,buf,sizeof(buf),&count,NULL)) {
224: if(GetLastError()==ERROR_HANDLE_EOF) /* closed by VDD_CLOSE */
225: break;
226: lprintf(LOG_ERR,"!input_thread: ReadFile Error %d (size=%d)"
227: ,GetLastError(),count);
228: continue;
229: }
230: if(count==0) {
231: lprintf(LOG_ERR,"!input_thread: ReadFile read 0");
232: continue;
233: }
234: RingBufWrite(&rdbuf,buf,count);
235:
1.1.1.2 ! root 236: if(virtualize_uart) {
! 237: /* Set the "Data ready" bit in the LSR */
! 238: uart_lsr_reg |= UART_LSR_DATA_READY;
! 239:
! 240: assert_interrupt(UART_IER_RX_DATA); /* assert rx data interrupt */
! 241: }
1.1 root 242: }
243: }
244:
245: unsigned vdd_read(BYTE* p, unsigned count)
246: {
247: sem_wait(rdbuf.sem);
248: count=RingBufRead(&rdbuf,p,count);
249: if(count==0)
250: lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0");
251:
252: return(count);
253: }
254:
255: unsigned yields=0;
256:
257: void yield()
258: {
259: yields++;
260: lprintf(LOG_DEBUG,"Yielding (yields=%u)", yields);
261: Sleep(1);
262: }
263:
264: long double last_yield=0;
265:
266: void maybe_yield()
267: {
268: long double t;
269:
270: t=xp_timer();
271:
272: if(yield_interval && (t-last_yield)*1000.0 >= yield_interval) {
273: yield();
274: last_yield=t;
275: }
276: }
277:
278: void reset_yield()
279: {
280: last_yield=xp_timer();
281: }
282:
283: /***********************/
284: /* UART Virtualization */
285: /***********************/
286:
287: static char *chr(uchar ch)
288: {
289: static char str[25];
290:
291: if(ch>=' ' && ch<='~')
292: sprintf(str,"'%c' (%02Xh)",ch,ch);
293: else if(ch<' ')
294: sprintf(str,"^%c (%02Xh)",'@'+ch,ch);
295: else
296: sprintf(str,"%u (%02Xh)",ch,ch);
297: return(str);
298: }
299:
300: VOID uart_wrport(WORD port, BYTE data)
301: {
302: int reg = port - uart_io_base;
303: int retval;
304:
305: lprintf(LOG_DEBUG,"write of port: %x (%s) <- %02X", port, uart_reg_desc[reg], data);
306:
307: switch(reg) {
308: case UART_BASE:
309: if(uart_lcr_reg&UART_LCR_DLAB) {
310: uart_divisor_latch_lsb = data;
311: lprintf(LOG_DEBUG,"set divisor latch low byte: %02X", data);
312: } else {
313: lprintf(LOG_DEBUG,"WRITE DATA: %s", chr(data));
314: if(!WriteFile(wrslot,&data,sizeof(BYTE),&retval,NULL)) {
315: lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)"
316: ,GetLastError(),retval);
317: } else {
318: assert_interrupt(UART_IER_TX_EMPTY);
319: reset_yield();
320: }
321: }
322: break;
323: case UART_IER:
324: if(uart_lcr_reg&UART_LCR_DLAB) {
325: uart_divisor_latch_msb = data;
326: lprintf(LOG_DEBUG,"set divisor latch high byte: %02X", data);
327: } else
328: uart_ier_reg = data;
329: assert_interrupt(UART_IER_TX_EMPTY); /* should this be re-asserted for all writes? */
330: break;
331: case UART_IIR: /* FCR not supported */
332: break;
333: case UART_LCR:
334: uart_lcr_reg = data;
335: break;
336: case UART_MCR:
337: uart_mcr_reg = data;
338: if((uart_mcr_reg&UART_MCR_DTR) == 0) /* Dropping DTR (i.e. "hangup") */
339: hangup();
340: break;
341: case UART_SCRATCH:
342: uart_scratch_reg = data;
343: break;
344: default:
345: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg);
346: break;
347:
348: }
349: }
350:
351: VOID uart_rdport(WORD port, PBYTE data)
352: {
353: int reg = port - uart_io_base;
354: DWORD avail;
355:
356: lprintf(LOG_DEBUG,"read of port: %x (%s)", port, uart_reg_desc[reg]);
357:
358: switch(reg) {
359: case UART_BASE:
360: if(uart_lcr_reg&UART_LCR_DLAB) {
361: lprintf(LOG_DEBUG,"reading divisor latch LSB");
362: *data = uart_divisor_latch_lsb;
363: break;
364: }
365: if((avail=RingBufFull(&rdbuf))!=0) {
366: vdd_read(data,sizeof(BYTE));
367: lprintf(LOG_DEBUG,"READ DATA: %s", chr(*data));
368: avail--;
369: reset_yield();
370: } else
371: *data=0;
372: if(avail==0) {
373: lprintf(LOG_DEBUG,"No more data");
374: /* Clear the data ready bit in the LSR */
375: uart_lsr_reg &= ~UART_LSR_DATA_READY;
376:
377: /* Clear data ready interrupt identification in IIR */
378: deassert_interrupt(UART_IER_RX_DATA);
379: } else /* re-assert RX data (increment the semaphore) */
380: assert_interrupt(UART_IER_RX_DATA);
381: break;
382: case UART_IER:
383: if(uart_lcr_reg&UART_LCR_DLAB) {
384: lprintf(LOG_DEBUG,"reading divisor latch MSB");
385: *data = uart_divisor_latch_msb;
386: } else
387: *data = uart_ier_reg;
388: break;
389: case UART_IIR:
390: /* Report IIR based on *priority* of pending interrupts */
391: if(pending_interrupts & UART_IER_LINE_STATUS)
392: *data = UART_IIR_LINE_STATUS;
393: else if(pending_interrupts & UART_IER_RX_DATA)
394: *data = UART_IIR_RX_DATA;
395: else if(pending_interrupts & UART_IER_TX_EMPTY) {
396: *data = UART_IIR_TX_EMPTY;
397: /* "Transmit Holding Register Empty" interrupt */
398: /* is reset on read of IIR */
399: deassert_interrupt(UART_IER_TX_EMPTY);
400: }
401: else if(pending_interrupts & UART_IER_MODEM_STATUS)
402: *data = UART_IIR_MODEM_STATUS;
403: else
404: *data = UART_IIR_NONE;
405: break;
406: case UART_LCR:
407: *data = uart_lcr_reg;
408: break;
409: case UART_MCR:
410: *data = uart_mcr_reg;
411: break;
412: case UART_LSR:
413: *data = uart_lsr_reg;
414: maybe_yield();
415: /* Clear line status interrupt pending */
416: deassert_interrupt(UART_IER_LINE_STATUS);
417: break;
418: case UART_MSR:
419: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
420: uart_msr_reg &=~ UART_MSR_DCD;
421: else
422: uart_msr_reg |= UART_MSR_DCD;
423: *data = uart_msr_reg;
424: maybe_yield();
425: /* Clear modem status interrupt pending */
426: deassert_interrupt(UART_IER_MODEM_STATUS);
427: break;
428: case UART_SCRATCH:
429: *data = uart_scratch_reg;
430: break;
431: default:
432: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg);
433: break;
434: }
435:
436: if(reg!=UART_BASE)
437: lprintf(LOG_DEBUG, "returning 0x%02X", *data);
438: }
439:
440: /* VDD DOS Interface (mainly for FOSSIL driver in dosxtrn.exe) */
441:
442: __declspec(dllexport) void __cdecl VDDDispatch(void)
443: {
444: char str[512];
445: DWORD count;
446: DWORD msgs;
447: int retval;
448: int node_num;
449: BYTE* p;
450: vdd_status_t* status;
451: static DWORD writes;
452: static DWORD bytes_written;
453: static DWORD reads;
454: static DWORD bytes_read;
455: static DWORD inbuf_poll;
456: static DWORD online_poll;
457: static DWORD status_poll;
458: static DWORD vdd_yields;
459: static DWORD vdd_calls;
460: VDD_IO_HANDLERS IOHandlers = { NULL };
461: static VDD_IO_PORTRANGE PortRange;
462:
463: retval=0;
464: node_num=getBH();
465:
466: lprintf(LOG_DEBUG,"VDD_OP: (handle=%d) %d (arg=%X)", getAX(),getBL(),getCX());
467: vdd_calls++;
468:
469: switch(getBL()) {
470:
471: case VDD_OPEN:
472:
1.1.1.2 ! root 473: sscanf("$Revision: 1.39 $", "%*s %s", revision);
1.1 root 474:
475: lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s"
476: ,revision, __DATE__, __TIME__);
477: #if 0
478: sprintf(str,"sbbsexec%d.log",node_num);
479: fp=fopen(str,"wb");
480: #endif
481:
482: sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d",node_num);
483: rdslot=CreateMailslot(str
484: ,LINEAR_RX_BUFLEN /* Max message size (0=any) */
485: ,MAILSLOT_WAIT_FOREVER /* Read timeout */
486: ,NULL);
487: if(rdslot==INVALID_HANDLE_VALUE) {
488: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
489: ,GetLastError(),str);
490: retval=1;
491: break;
492: }
493:
494: sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d",node_num);
495: wrslot=CreateFile(str
496: ,GENERIC_WRITE
497: ,FILE_SHARE_READ
498: ,NULL
499: ,OPEN_EXISTING
500: ,FILE_ATTRIBUTE_NORMAL
501: ,(HANDLE) NULL);
502: if(wrslot==INVALID_HANDLE_VALUE) {
503: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
504: ,GetLastError(),str);
505: retval=2;
506: break;
507: }
508:
509: if(RingBufInit(&rdbuf, RINGBUF_SIZE_IN)!=0) {
510: retval=3;
511: break;
512: }
513:
514: sprintf(str,"sbbsexec_hungup%d",node_num);
515: hungup_event=OpenEvent(
516: EVENT_ALL_ACCESS, /* access flag */
517: FALSE, /* inherit flag */
518: str); /* pointer to event-object name */
519: if(hungup_event==NULL) {
520: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
521: ,GetLastError(),str);
522: retval=4;
523: break;
524: }
525:
526: sprintf(str,"sbbsexec_hangup%d",node_num);
527: hangup_event=OpenEvent(
528: EVENT_ALL_ACCESS, /* access flag */
529: FALSE, /* inherit flag */
530: str); /* pointer to event-object name */
531: if(hangup_event==NULL) {
532: lprintf(LOG_WARNING,"!VDD_OPEN: Error %d opening %s"
533: ,GetLastError(),str);
534: }
535:
536: status_poll=0;
537: inbuf_poll=0;
538: online_poll=0;
539: yields=0;
540:
541: lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval);
542:
543: if(virtualize_uart) {
544: lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)"
545: ,uart_io_base, uart_irq);
546:
547: IOHandlers.inb_handler = uart_rdport;
548: IOHandlers.outb_handler = uart_wrport;
549: PortRange.First=uart_io_base;
550: PortRange.Last=uart_io_base + UART_IO_RANGE;
551:
552: VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers);
553:
554: interrupt_event=CreateEvent(NULL,FALSE,FALSE,NULL);
555: InitializeCriticalSection(&interrupt_mutex);
556:
557: _beginthread(interrupt_thread, 0, NULL);
558: }
559:
560: lprintf(LOG_DEBUG,"VDD_OPEN: Opened successfully");
561:
562: _beginthread(input_thread, 0, NULL);
563:
564: retval=0;
565: break;
566:
567: case VDD_CLOSE:
568: lprintf(LOG_INFO,"VDD_CLOSE: rdbuf=%u "
569: "status_poll=%u inbuf_poll=%u online_poll=%u yields=%u vdd_yields=%u vdd_calls=%u"
570: ,RingBufFull(&rdbuf),status_poll,inbuf_poll,online_poll
571: ,yields,vdd_yields,vdd_calls);
572: lprintf(LOG_INFO," read=%u bytes (in %u calls)",bytes_read,reads);
573: lprintf(LOG_INFO," wrote=%u bytes (in %u calls)",bytes_written,writes);
574:
575: if(virtualize_uart) {
576: lprintf(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook");
577: VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange);
578: }
579:
580: CloseHandle(rdslot);
581: CloseHandle(wrslot);
582: if(hungup_event!=NULL)
583: CloseHandle(hungup_event);
584: if(hangup_event!=NULL)
585: CloseHandle(hangup_event);
586:
587: #if 0 /* This isn't strictly necessary...
588: and possibly the cause of a NULL dereference in the input_thread */
589: RingBufDispose(&rdbuf);
590: #endif
591: status_poll=0;
592: retval=0;
593:
594: break;
595:
596: case VDD_READ:
597: count = getCX();
598: if(count != 1)
599: lprintf(LOG_DEBUG,"VDD_READ of %d",count);
600: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
601: ,count,FALSE);
602: retval=vdd_read(p, count);
603: reads++;
604: bytes_read+=retval;
605: reset_yield();
606: break;
607:
608: case VDD_PEEK:
609: count = getCX();
610: if(count != 1)
611: lprintf(LOG_DEBUG,"VDD_PEEK of %d",count);
612:
613: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
614: ,count,FALSE);
615: retval=RingBufPeek(&rdbuf,p,count);
616: reset_yield();
617: break;
618:
619: case VDD_WRITE:
620: count = getCX();
621: if(count != 1)
622: lprintf(LOG_DEBUG,"VDD_WRITE of %d",count);
623: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
624: ,count,FALSE);
625: if(!WriteFile(wrslot,p,count,&retval,NULL)) {
626: lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)"
627: ,GetLastError(),retval);
628: retval=0;
629: } else {
630: writes++;
631: bytes_written+=retval;
632: reset_yield();
633: }
634: break;
635:
636: case VDD_STATUS:
637:
638: status_poll++;
639: count = getCX();
640: if(count != sizeof(vdd_status_t)) {
641: lprintf(LOG_DEBUG,"!VDD_STATUS: wrong size (%d!=%d)",count,sizeof(vdd_status_t));
642: retval=sizeof(vdd_status_t);
643: break;
644: }
645: status = (vdd_status_t*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
646: ,count,FALSE);
647:
648: status->inbuf_full=RingBufFull(&rdbuf);
649:
650: /* OUTBUF FULL/SIZE */
651: if(!GetMailslotInfo(
652: wrslot, /* mailslot handle */
653: &status->outbuf_size, /* address of maximum message size */
654: &status->outbuf_full, /* address of size of next message */
655: &msgs, /* address of number of messages */
656: NULL /* address of read time-out */
657: )) {
658: status->outbuf_full=0;
659: status->outbuf_size=DEFAULT_MAX_MSG_SIZE;
660: }
661: if(status->outbuf_full==MAILSLOT_NO_MESSAGE)
662: status->outbuf_full=0;
663: status->outbuf_full*=msgs;
664:
665: /* ONLINE */
666: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
667: status->online=0;
668: else
669: status->online=1;
670:
671: retval=0; /* success */
672: break;
673:
674: case VDD_INBUF_PURGE:
675: RingBufReInit(&rdbuf);
676: retval=0;
677: break;
678:
679: case VDD_OUTBUF_PURGE:
680: lprintf(LOG_WARNING,"!VDD_OUTBUF_PURGE: NOT IMPLEMENTED");
681: retval=0;
682: break;
683:
684: case VDD_INBUF_FULL:
685: retval=RingBufFull(&rdbuf);
686: inbuf_poll++;
687: break;
688:
689: case VDD_INBUF_SIZE:
690: retval=RINGBUF_SIZE_IN;
691: break;
692:
693: case VDD_OUTBUF_FULL:
694: if(!GetMailslotInfo(
695: wrslot, /* mailslot handle */
696: NULL, /* address of maximum message size */
697: &retval, /* address of size of next message */
698: &msgs, /* address of number of messages */
699: NULL /* address of read time-out */
700: ))
701: retval=0;
702: if(retval==MAILSLOT_NO_MESSAGE)
703: retval=0;
704: retval*=msgs;
705: break;
706:
707: case VDD_OUTBUF_SIZE:
708: if(!GetMailslotInfo(
709: wrslot, /* mailslot handle */
710: &retval, /* address of maximum message size */
711: NULL, /* address of size of next message */
712: NULL, /* address of number of messages */
713: NULL /* address of read time-out */
714: ))
715: retval=DEFAULT_MAX_MSG_SIZE;
716: break;
717:
718: case VDD_ONLINE:
719: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
720: retval=0;
721: else
722: retval=1;
723: online_poll++;
724: break;
725:
726: case VDD_YIELD: /* forced yield */
727: vdd_yields++;
728: yield();
729: break;
730:
731: case VDD_MAYBE_YIELD: /* yield if YieldInterval is enabled and expired */
732: maybe_yield();
733: break;
734:
735: case VDD_LOAD_INI_FILE: /* Load and parse settings file */
736: {
737: FILE* fp;
738: char cwd[MAX_PATH+1];
739:
740: /* Load exec/sbbsexec.ini first (setting default values) */
741: count = getCX();
742: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
743: ,count,FALSE);
744: iniFileName(ini_fname, sizeof(ini_fname), p, INI_FILENAME);
745: if((fp=fopen(ini_fname,"r"))!=NULL) {
746: ini=iniReadFile(fp);
747: fclose(fp);
748: parse_ini(ROOT_SECTION);
749: }
750:
751: /* Load cwd/sbbsexec.ini second (over-riding default values) */
752: GetCurrentDirectory(sizeof(cwd),cwd);
753: iniFileName(ini_fname, sizeof(ini_fname), cwd, INI_FILENAME);
754: if((fp=fopen(ini_fname,"r"))!=NULL) {
755: ini=iniReadFile(fp);
756: fclose(fp);
757: parse_ini(ROOT_SECTION);
758: }
759: }
760: break;
761:
762: case VDD_LOAD_INI_SECTION: /* Parse (program-specific) sub-section of settings file */
763: count = getCX();
764: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
765: ,count,FALSE);
766: parse_ini(p);
767: break;
768:
769: case VDD_DEBUG_OUTPUT: /* Send string to debug output */
770: count = getCX();
771: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
772: ,count,FALSE);
773: lputs(LOG_INFO, p);
774: break;
775:
776: case VDD_HANGUP:
777: hangup();
778: break;
779:
780: default:
781: lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL());
782: break;
783: }
784: setAX((WORD)retval);
785: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.