PAGE 75,128 TITLE MSGSYST - RBBS Message Subsystem V0.84 PAGE .XLIST INCLUDE CCBBS.DEF INCLUDE CCBBS.MAC .LIST ;----------------------------------------------- ;SYSTEM DATA SEGMENT ;----------------------------------------------- SYSDATA SEGMENT PARA PUBLIC 'DATA' EXTRN MSSGH:WORD EXTRN DEBUGF:BYTE PUBLIC MSGUCNT,MSGUSR,ADDCNT PUBLIC MSGINX1,MSGINX2 CTBL2 DB 'FBARKNMHEL' ;MSG COMMAND STRING JTBL2 DW RMS40 ;FORWARD DW RMS50 ;BACKWARD DW RMS80 ;APPEND DW RMS60 ;REPLY DW RMS70 ;KILL DW RMS25 ;NEXT STRING DW RMS95 ;MAIN MENU DW RMSHF ;HELP TEXT DW REEDIT ;EDIT MESSAGE HEADER DW RMS35 ;RE-DISPLAY MESSAGE CTBL5 DB 'ACDEHILMSNU?' ;MSG SUBFUNCTION CMD STR JTBL5 DW MSFA00 ;ABORT MESSAGE DW MSFC00 ;CONTINUE MESSAGE ENTRY DW MSFD00 ;DELETE LINE DW MSFE00 ;EDIT LINE DW MSFH00 ;HELP DW MSFI00 ;INSERT LINE DW MSFL00 ;LIST MESSAGE DW MSFM00 ;RESET MARGIN DW MSFS00 ;SAVE MESSAGE DW MSFN00 ;NEW SUBJECT DW MSFU00 ;UNTHREAD MESSAGE DW BLDM51 ;FULL PROMPT ;------------------------------------------------ ;MESSAGE FILE INDEX TABLES ;------------------------------------------------ MSGUSR DW 0 ;CURRENT MSG FILE LOCK HOLDER DW 0 ;MSG FILE WAIT LIST PTR MSGUCNT DW 0 ;NUMBER OF MESSAGE FILE USERS KILLCNT DW 0 ;MESSAGES KILLED SINCE INDEX REORG ADDCNT DW 0 ;MESSAGES ADDED SINCE INDEX SAVE MSGINX1 DW 0 ;ADDRESS OF MESSAGE NUMBER ARRAY MSGINX2 DW 0 ;ADDRESS OF BLOCK NUMBER ARRAY SYSDATA ENDS ;----------------------------------------------- ;CODE SEGMENT ;----------------------------------------------- CSEG SEGMENT PARA PUBLIC 'CODE' EXTRN GETBUF:NEAR,FREBUF:NEAR,MMENU1:NEAR,APPBYT:NEAR EXTRN ASCBIN:NEAR,BINASP:NEAR,CONR:NEAR,CONW:NEAR EXTRN CMPSTR:NEAR,DATASC:NEAR,DOSTIM:NEAR,DQCMD:NEAR EXTRN ERROR:NEAR,FRELBF:NEAR,GDBYE:NEAR,ILINEB:NEAR EXTRN MOVSTL:NEAR,MOVMSG:NEAR,QUERY:NEAR,YIELD:NEAR EXTRN SENDHF:NEAR,SETMGN:NEAR,STRIP:NEAR,DQTIOA:NEAR EXTRN TAYSOP:NEAR,TXPRT:NEAR,TIMHM:NEAR,PADB:NEAR EXTRN WRLIN:NEAR,WRMSG:NEAR,XLATE:NEAR,FRETIO:NEAR EXTRN BINASC:NEAR,TSYSOP:NEAR,CONT:NEAR,WRLF:NEAR EXTRN BLANKF:NEAR,WMSGNO:NEAR,QMSGNO:NEAR,TSIGOP:NEAR EXTRN PSECNO:NEAR,MMENU2:NEAR,DTEASC:NEAR,DOSDAT:NEAR EXTRN LOCKWT:NEAR,UNLOCK:NEAR,DSPSEC:NEAR,CKCTLK:NEAR EXTRN GETSBF:NEAR,MOVSTR:NEAR,ARANGE:NEAR,RDUSER:NEAR EXTRN FNAM:NEAR,CMPSTA:NEAR,GETMSG:NEAR,LOGDSK:NEAR EXTRN CKFSPC:NEAR,FREUSR:NEAR,mvcstr:near EXTRN ATOINX:NEAR,DTOINX:NEAR,LALIGN:NEAR PUBLIC QUICKS,READTM,SCANM,ENTCMT,ENTMSG,DELETE PUBLIC BUILDM,INSTRG,QVALUE,WRITM,READM,CKMSG,QYES PUBLIC FEOF,READCM,QYESNO,QVALNO,CKPTM,ENTFM PUBLIC SAVINX,PKINX,ENTAPP,ENTREP,EDITFM,DISPFM PUBLIC ARCMSG,QPRMPT,RPRMPT,SPRMPT,REVFM,VALSEC,RCPRMP PUBLIC QDFLT,FINDMN ASSUME CS:CSEG,DS:NOTHING,ES:SYSDATA MSGSYST PROC NEAR ;-------------------------------------------------------- ;READ OR SCAN MESSAGES ; BP-2 OPTION FLAGS ; BP-4 HOME MESSAGE INDEX ; BP-6 FORWARD POINTER ; BP-8 BACKWARD POINTER ; BP-10 MSGS READ BIT STRING ; BP-12 # OF BLOCKS IN MESSAGE ; BP-14 SAVED POSITION INDEX ; BP-16 LAST READ MSG INDEX ; BP-18 ARCHIEVE FILE HANDLE ; BP-20 USER PAGE SIZE ; BP-22 SEARCH STRING ; BP-24 SEARCH SECTION NUMBER ; BP-26 UPPER BOUND ; BP-28 STARTING MESSAGE ;-------------------------------------------------------- WFQS EQU 1 ;QUICK SCAN FLAG WFRM EQU 2 ;READ MESSAGE FLAG WFSM EQU 4 ;SCAN MESSAGES FLAG WFFO EQU 8 ;FORWARD SCAN FLAG WFRV EQU 10H ;BACKWARD SCAN FLAG WFAPP EQU 20H ;REPLY/APPEND FLAG WFRC EQU 40H ;READ CONTINUOUS WFSBF EQU 80H ;INVOKE SUBFUNCTION WFDFM EQU 100H ;DISPLAY FLASH MESSAGES WFEFM EQU 200H ;EDIT FLASH MESSAGES WFNOM EQU 400H ;NO MORE OUTPUT WFRET EQU 800H ;RETURN TO CURRENT MSG WFPRMT EQU 1000H ;PROMPT FOR SEARCH CRITEREA WFPRVT EQU 2000H ;DISPLAY PRIVATE MESSAGES WFARC EQU 4000H ;ARCHIEVE MESSAGES WFCALL EQU 8000H ;ROUTINE WAS CALLED MSNOGO: TEST AX,WFCALL ;CALL INTERFACE? JZ MSNOGM ;NO PROBLEM STC ;SHOW ERROR RET MSNOGM: MOV AX,58 ;FILE BEING COMPRESSED CALL WMSGNO ;TELL USER JMP MMENU1 ;TELL USER REVFM: MOV AX,WFRM+WFFO+WFDFM ;REVIEW FLASH MESSAGES JMP SHORT RMSGS EDITFM: MOV AX,WFRM+WFFO+WFEFM ;EDIT FLASH MESSAGES CALL TAYSOP ;PRIVILEDGED? JNZ RMSGS ;YES JMP MMENU2 ;INVALID COMMAND ;NOTE: DISPFM IS CALLED - NOT JUMPED TO DISPFM: MOV AX,WFRM+WFFO+WFDFM+WFCALL ;DISPLAY FLASH MESSAGES JMP SHORT RMSGS QUICKS: MOV AX,WFQS+WFFO ;QUICK SCAN FLAG JMP SHORT RMSGS ;GO HANDLE READTM: MOV AX,WFRM ;READ MESSAGES JMP SHORT RMSGS ;GO HANDLE ARCMSG: MOV AX,WFRM+WFRC+WFARC ;ARCHIEVE MSGS CALL TAYSOP ;PRIVILEDGED? JNZ RMSGS ;YES JMP MMENU2 ;INVALID READCM: MOV AX,WFRM+WFRC+WFFO ;READ CONTINUOUS JMP SHORT RMSGS ;GO HANDLE ENTAPP: MOV AX,WFSBF+WFAPP ;CALL APPEND FUNCTION JMP SHORT RMSGS ENTREP: MOV AX,WFSBF ;CALL REPLY FUNCTION JMP SHORT RMSGS ;GO HANDLE QPRMPT: MOV AX,WFQS+WFFO+WFPRMT ;PROMPTING QUICKSCAN JMP SHORT RMSGS RPRMPT: MOV AX,WFRM+WFFO+WFPRMT ;PROMPTING READ JMP SHORT RMSGS SPRMPT: MOV AX,WFSM+WFFO+WFPRMT ;PROMPTING SCAN JMP SHORT RMSGS RCPRMP: MOV AX,WFRM+WFRC+WFFO+WFPRMT ;PROMPTING RC JMP SHORT RMSGS SCANM: MOV AX,WFSM+WFFO ;SCAN FLAG RMSGS: CMP MSGUCNT,-1 ;FILE UNAVAILABLE? JZ MSNOGO ;YES - ABORT REQUEST INC MSGUCNT ;COUNT ACTIVE USERS PUSH BP ;SAVE PREVIOUS FRAME MOV BP,SP ;SET LOCAL FRAME SUB SP,28 ;RESERVE LOCAL STORAGE MOV [BP-2],AX ;OPTION FLAGS XOR AX,AX MOV [BP-10],AX ;NO BIT STRING MOV [BP-20],AX ;NO USER PAGE LENGTH MOV [BP-22],AX ;NO SEARCH STRING MOV [BP-24],AX ;NO SECTION # MOV [BP-26],AX ;NO RANGE TEST WORD PTR [BP-2],WFRC+WFSBF+WFDFM+WFEFM ;THREADING? JNZ RMS00 ;NO MOV AX,DS:MSGCKPT+MDIMAX ;MAXIMUM MESSAGES MOV CL,3 ;SHIFT FACTOR SHR AX,CL ;ROOM FOR MAX MSGS CALL GETBUF ;GET ARRAY MOV [BP-10],SI ;SAVE ADDRESS MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+UEXPL] ;PAGE LENGTH MOV [BP-20],AX RMS00: TEST WORD PTR [BP-2],WFDFM+WFEFM ;FLASH MESSAGES? JZ RMS02 ;NO MOV AX,DS:MSGCKPT+MFLASH ;1ST FLASH MESSAGE MOV [BP-28],AX ;STARTING MESSAGE OR AX,AX ;ANY? JNZ RMS01 ;YES TEST WORD PTR [BP-2],WFCALL ;CALLED INTERFACE? JNZ RMSJ95 ;YES - NO MESSAGE MOV AX,327 ;NO FLASH MESSAGES CALL WMSGNO ;DISPLAY MESSAGE RMSJ95: JMP RMS95 ;EXIT RMS01: JMP RMS18 ;PROCESS CHAIN RMS02: CALL DQCMD ;GET STARTING MSG # JNC RMS10 ;PROCESS MSG # CALL ILINEB ;LINE BUFFER CALL TXPRT ;EXPERT? JNZ RMS06 ;YES TEST WORD PTR [BP-2],WFRM ;READ MSG? JNZ RMS06 ;YES MOV AX,165 ;STARTING AT CALL MOVMSG RMS06: MOV AX,167 ;MSG # CALL MOVMSG MOV DI,DS:MSGCKPT+MIFRST PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;1ST MESSAGE NUMBER POP BX CALL BINASP MOV AX,168 ;TO CALL MOVMSG MOV DI,DS:MSGCKPT+MILAST ;LAST MESSAGE INDEX PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;LAST MSG NUMBER POP BX CALL BINASP MOV AX,169 ;, *, elp CALL MOVMSG CALL TXPRT ;EXPERT MODE? JNZ RMS07 ;YES TEST WORD PTR [BP-2],WFRM ;READ MSG? JZ RMS07 ;NO MOV AX,166 ;TO RETRIEVE CALL MOVMSG RMS07: MOV AL,'?' CALL APPBYT INC WORD PTR [SI-2] ;LEAVE ONE SPACE CALL QUERY JC RMS09 ;EXIT JMP RMS00 ;TEST RESPONSE RMS09: JMP RMS95 ;LOST CARRIER RMS10: MOV CX,WORD PTR [SI-2] ;DATA LENGTH JCXZ RMS09 ;EXIT TEST BYTE PTR [BP-2],WFFO ;FORWARD ALREADY SET? JNZ RMS12 ;YES AND BYTE PTR [BP-2],255-(WFFO+WFRV) PUSH SI ADD SI,CX ;POINT PAST END MOV AL,BYTE PTR [SI-1] ;LAST CHARACTER POP SI CMP AL,'+' ;FORWARD? JNZ RMS11 ;NO OR BYTE PTR [BP-2],WFFO ;SET FORWARD FLAG RMS11: CMP AL,'-' ;BACKWARD? JNZ RMS12 OR BYTE PTR [BP-2],WFRV ;SET BACKWARD FLAG RMS12: CALL ARANGE ;GET VALUES JB RMS12B ;NOT NUMERIC MOV [BP-28],AX ;MESSAGE NUMBER OR DX,DX ;RANGE? JZ RMS12A ;NO MOV [BP-26],DX ;SAVE BOUND OR WORD PTR [BP-2],WFFO ;SET FORWARD POINTER RMS12A: CMP AX,0 ;NUMERIC? JNZ RMS17 ;YES RMS12B: LODSB ;GET COMMAND CHAR CMP AL,'*' ;NEXT MSG? JNZ RMS13 ;NO MOV DI,WORD PTR [BX+USRST] ;SIGN-ON ENTRY MOV AX,WORD PTR [DI+UELMSG] ;LAST MSG READ INC AX ;POINT TO NEXT MOV [BP-28],AX ;MESSAGE NUMBER OR WORD PTR [BP-2],WFFO ;SET FORWARD POINTER JMP RMS17 RMS13: CMP AL,'h' ;HELP? JZ RMS16 ;YES CMP AL,'H' ;HELP? JZ RMS16 ;YES JMP RMS95 ;INVALID RESPONSE RMS16: JMP RMS30 ;SEND HELP FILE RMS17: MOV DI,[BP-10] ;ARRAY ADDRESS OR DI,DI ;EXIST? JZ RMS17A ;NO MOV AX,DS:MSGCKPT+MDIMAX ;MAXIMUM MSGS MOV CL,4 ;SHIFT FACTOR SHR AX,CL ;LENGTH IN WORDS XOR AX,AX ;CLEAR PUSH ES PUSH DS POP ES REP STOSW ;CLEAR ARRAY POP ES RMS17A: TEST WORD PTR [BP-2],WFFO ;FORWARD? JZ RMS18 ;NO TEST WORD PTR [BP-2],WFPRMT ;PROMPT? JZ RMS18 ;NO MOV SI,60 ;ENTER SECTION # CALL VALSEC ;VALID SECTIONS MOV DX,AX ;REMEMBER CALL PSECNO ;GET NEW VALUE MOV WORD PTR [BP-24],AX ;SAVE FOR SEARCH OR AX,AX ;SECTION 0 JZ RMS17B ;YES - SET FLAG CMP AX,DX ;ANY CHANGE? JNZ RMS17C ;YES - NO SECTION 0 RMS17B: OR WORD PTR [BP-2],WFPRVT ;DISPLAY SECTION 0 RMS17C: MOV AX,258 ;ENTER SEARCH STRING CALL QMSGNO ;GET RESPONSE CALL DQTIOA ;DEQUEUE BUFFER CMP WORD PTR [SI-2],0 ;ANYTHING? JNZ RMS17F ;YES CALL FREBUF ;FREE STRING JMP SHORT RMS18 ;NO SEARCH STRING RMS17F: CALL XLATE ;UPPER CASE CALL LALIGN ;STRIP LEADING BLANKS MOV [BP-22],SI ;SEARCH STRING ADDR RMS18: MOV AX,[BP-28] ;MESSAGE NUMBER RMS18A: CALL FINDMN ;FIND MSG # IN INDEX MOV [BP-4],DI ;SET HOME POSITION MOV WORD PTR [BP-14],0 ;CLEAR CURRENT POS JNC RMS20 ;FOUND MESSAGE TEST WORD PTR [BP-2],WFFO ;FORWARD? JZ RMS18B ;MESSAGE NOT FOUND MOV DI,DS:MSGCKPT+MILAST PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX CMP AX,[BX+DI] ;TOO HIGH? POP BX JA RMS18B ;YES INC AX ;NEXT MSG NUMBER MOV DI,DS:MSGCKPT+MIFRST PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX CMP AX,[BX+DI] ;TOO LOW? POP BX JAE RMS18A ;NO PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;START WITH FIRST POP BX JMP RMS18A ;TRY IT RMS18B: TEST WORD PTR [BP-2],WFDFM+WFEFM ;FLASH MSGS? JZ RMS19 ;NO JMP RMS95 ;EXIT RMS19: CALL NOMSGN ;NO SUCH MSG JMP RMS00 ;GET NEXT MSG # RMS20: CALL SETRDB ;MARK MSG READ RMS21: MOV [BP-16],DI ;CURRENT MSG INDEX TEST WORD PTR [BP-2],WFSBF ;SUBFUNCTION CALL? JZ RMS21D ;NO JMP RMS61 ;ENTER REPLY/APP CODE RMS21D: CALL DSPMSG ;DISPLAY MSG JNC RMS22 ;NO PROBLEM TEST WORD PTR [BP-2],WFFO ;FORWARD? JNZ RMS24 ;NO PROBLEM MOV DI,[BP-16] ;CURRENT POSITION PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;GET MESSAGE NUMBER POP BX CALL NOMSGN ;NO SUCH MESSAGE JMP RMS00 ;GET NEXT MSG # RMS22: TEST WORD PTR [BP-2],WFRM ;READ MESSAGE? JZ RMS24 ;NO TEST WORD PTR [BP-2],WFRC+WFDFM ;CONTINUOUS? JNZ RMS24 ;YES - SKIP PROMPT RMS23: MOV AX,30 ;MESSAGE MENU CALL QMSGNO ;GET USER COMMAND JNC RMS23A JMP RMS95 ;LOST CARRIER RMS23A: CALL DQCMD ;DEQUEUE RESPONSE CMP WORD PTR [SI-2],0 ;NULL RESPONSE? JZ RMS24 ;YES - CONTINUE CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE ;FORCE UPPER CASE MOV CX,6 ;MAX FIELD SIZE CALL ASCBIN ;GET VALUE OR AX,AX ;ANYTHING? JZ RMS23C ;NO - CHECK CMD JMP RMS51 ;DISPLAY MESSAGE RMS23C: LODSB ;GET COMMAND MOV DI,OFFSET CTBL2 ;MESSAGE CMD TABLE MOV CX,(JTBL2-CTBL2) ;TABLE LENGTH REPNZ SCASB ;CHECK FOR MATCH JNZ RMS23 ;UNKNOWN COMMAND SUB DI,OFFSET CTBL2+1 ;OFFSET IN STRING SHL DI,1 ;TABLE WIDTH JMP JTBL2[DI] ;EXECUTE COMMAND RMS24: TEST WORD PTR [BP-2],WFRM ;READ MESSAGE? JZ RMS25 ;NO TEST WORD PTR [BP-2],WFRET ;RETURN TO SAME MSG? JZ RMS24A ;NO JMP RMS35 ;REDISPLAY MSG RMS24A: TEST WORD PTR [BP-2],WFRC ;READ CONTINUOUS? JNZ RMS25 ;YES - SKIP THREADING CMP WORD PTR [BP-14],0 ;AWAY FROM HOME? JZ RMS24B ;NO MOV DI,[BP-14] ;GET POSITION MOV WORD PTR [BP-14],0 ;CLEAR FLAG PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;BLOCK NUMBER POP BX JMP RMS20 ;GO DISPLAY RMS24B: TEST WORD PTR [BP-2],WFFO ;FORWARD? JNZ RMS24D ;YES RMS24C: JMP RMS00 ;GET NEXT MSG # RMS24D: MOV AX,[BP-6] ;FORWARD POINTER CALL FINDMN ;GET INDEX JC RMS25 ;NOT FOUND CALL TSTRDB ;ALREADY SEEN JNZ RMS25 ;YES - END OF THREAD JMP RMS20 ;DISPLAY IT RMS25: TEST WORD PTR [BP-2],WFFO ;FORWARD? JZ RMS24C ;GET NXT MSG # ;CHECK FOR LOST CARRIER TEST BYTE PTR [BX+CBFLG],SFLC ;LOST CARRIER? JZ RMS25A ;NO PROBLEM JMP RMS27 ;EXIT RMS25A: TEST WORD PTR [BP-2],WFDFM+WFEFM ;FLASH MESSAGES? JZ RMS25B ;NO JMP RMS95 ;DONE ;CHECK FOR ABORT REQUEST RMS25B: CALL CKCTLK ;ABORT REQUEST? JC RMS27 ;YES TEST WORD PTR [BP-2],WFNOM ;NO MORE? JNZ RMS27 ;YES RMS25C: ADD WORD PTR [BP-4],2 ;NEXT INDEX VALUE MOV DI,[BP-4] ;HOME POSITION CMP DI,DS:MSGCKPT+MILAST ;LAST ACTIVE ENTRY JA RMS26 ;DONE PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;GET NUMBER POP BX OR AX,AX ;DELETED? JZ RMS25 ;YES - SKIP CALL TSTRDB ;ALREADY SEEN? JNZ RMS25 ;YES - SKIP CMP WORD PTR [BP-26],0 ;RANGE CHECK? JZ RMS25D ;NO CMP AX,[BP-26] ;END OF RANGE? JA RMS26 ;YES RMS25D: PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;NEXT BLOCK NUMBER POP BX JMP RMS20 ;NEXT MESSAGE RMS26: MOV AX,31 ;END OF MESSAGES CALL WMSGNO ;DISPLAY TEST WORD PTR [BP-2],WFRM ;READ MESSAGES? JZ RMS27 ;NO TEST WORD PTR [BP-2],WFPRMT ;PROMPTED SEARCH? JNZ RMS27 ;YES CMP WORD PTR [BP-26],0 ;RANGE CHECK? JNZ RMS27 ;YES MOV DI,DS:MSGCKPT+MILAST ;INDEX TO LAST MSG PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;LAST MESSAGE NUMBER POP BX MOV DI,WORD PTR [BX+USRST] ;SIGN ON RECORD MOV WORD PTR [DI+UEHMSG],AX ;ALL MESSAGES READ RMS27: JMP RMS95 ;EXIT RMS30: MOV AX,7 ;HELP FILE NUMBER CALL SENDHF ;XMIT HELP FILE JMP RMS00 ;REPEAT PROMPT RMS35: MOV DI,[BP-16] ;CURRENT MESSAGE INX PUSH BX MOV BX,MSGINX2 ;BLOCK NUMBER ARRAY MOV AX,[DI+BX] ;MSG BLOCK POP BX AND WORD PTR [BP-2],NOT WFRET ;SAME MSG FLAG JMP RMS21 ;DISPLAY RMS40: MOV AX,[BP-6] ;FORWARD POINTER MOV DX,146 ;ERROR MSG JMP SHORT RMS51 RMS50: MOV AX,[BP-8] ;BACKWARD POINTER MOV DX,147 ;ERROR MSG RMS51: OR AX,AX ;ANY POINTER? JNZ RMS53 ;NO PROBLEM MOV AX,DX ;ERROR MSG CALL WMSGNO ;DISPLAY MESSAGE JMP RMS23 ;REPEAT PROMPT RMS53: CMP WORD PTR [BP-14],0 ;SAVED POSITION? JNZ RMS55 ;YES MOV DI,[BP-16] ;GET LAST USED INDEX MOV [BP-14],DI ;SAVE IT RMS55: CALL FINDMN ;GET INDEX JC RMS59 ;DOES NOT EXIST JMP RMS21 ;DISPLAY W/O MARKING RMS59: JMP RMS23 ;REPEAT PROMPT ;REPLY COMMAND RMS60: AND WORD PTR [BP-2],NOT WFAPP ;TURN OFF APPEND FLAG RMS61: MOV DI,[BP-16] ;LAST MESSAGE READ PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;BLOCK NUMBER POP BX MOV WORD PTR [BX+USRMP],AX ;SET FOR READ CALL READM ;READ HEADER PUSH SI MOV SI,WORD PTR [BX+USRST] ;USER RECORD TEST BYTE PTR [SI+UESTAT],12 ;REG PEND OR REJ? POP SI JZ RMS62 ;NO PROBLEM TEST WORD PTR [SI+MPFLAG],2 ;PRIVATE MESSAGE? JNZ RMS62 ;YES - LET HIM REPLY MOV AX,406 ;WHEN APPROVED ... CALL WMSGNO ;WRITE MSG JMP RMS23 ;REPEAT PROMPT RMS62: MOV WORD PTR [BX+USRMB],0 ;SHOW NO BUFFER MOV DX,SI ;SAVE HEADER ADDRESS CALL BLDHDR ;BUILD NEW HEADER JNC RMS63 ;OK MOV SI,DX ;BUFFER ADDRESS CALL FREBUF ;FREE BUFFER JMP RMS24 ;NEXT MESSAGE RMS63: LEA DI,[SI+MTNAME] ;TO: MOV SI,DX ;OLD HEADER ADD SI,MFNAME ;FROM: TEST WORD PTR [BP-2],WFAPP ;APPEND? JZ RMS64 ;NO ADD SI,MTNAME-MFNAME ;USE ORIGINAL 'TO' NAME RMS64: MOV CX,MTSTMP-MTNAME ;TO: LENGTH PUSH ES PUSH DS POP ES REP MOVSB POP ES MOV DI,WORD PTR [BX+USRMB] ;NEW HEADER ADD DI,MFSUBJ ;SUBJECT MOV SI,DX ;OLD HEADER ADD SI,MFSUBJ ;SUBJECT MOV CX,MFBPTR-MFSUBJ ;SUBJECT LENGTH PUSH ES PUSH DS POP ES REP MOVSB POP ES MOV DI,WORD PTR [BX+USRMB] ;NEW HEADER MOV SI,DX ;OLD HEADER MOV AX,WORD PTR [SI+MMNUMB] ;MESSAGE NUMBER MOV WORD PTR [DI+MFBPTR],AX ;BACK POINTER MOV AL,BYTE PTR [SI+MPFLAG] ;PROTECTION FLAG MOV BYTE PTR [DI+MPFLAG],AL ;SET SAME MOV AX,WORD PTR [SI+MFSECT] ;SECTION NUMBER MOV WORD PTR [DI+MFSECT],AX ;SET SAME OR AX,AX ;SECTION 0? JNZ RMS67 ;NO PROBLEM MOV BYTE PTR [DI+MPFLAG],2 ;MARK PROTECTED RMS67: CALL FREBUF ;FREE OLD HEADER CALL BLDMSG ;ENTER MESSAGE JNC RMS67A ;OK OR WORD PTR [BP-2],WFRET ;RETURN TO SAME MSG JMP SHORT RMS68 RMS67A: CALL SETRDB ;MARK IT READ RMS68: TEST WORD PTR [BP-2],WFSBF ;SUBFUNCTION CALL? JZ RMS69 ;NO JMP RMS95 ;EXIT RMS69: JMP RMS24 ;NEXT MESSAGE RMS70: MOV DI,[BP-16] ;LAST MESSAGE READ PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;MESSAGE NUMBER POP BX MOV DX,70H ;DELETE ALL MSG TYPES PUSH DX ;FLAGS MOV DX,-1 ;DELETE ALL SECTIONS PUSH DX ;SECTION MASK XOR DX,DX ;SINGLE MSG ONLY PUSH DX ;END OF RANGE PUSH AX ;MESSAGE NUMBER CALL KILL00 ;GO DELETE IT JMP RMS24 ;NEXT ACTION ;APPEND COMMAND RMS80: OR WORD PTR [BP-2],WFAPP ;SET APPEND FLAG JMP RMS61 ;ENTER REPLY CODE RMS95: MOV SI,[BP-10] ;BIT ARRAY CALL FREBUF ;GIVE IT BACK MOV SI,[BP-22] ;SEARCH STRING CALL FREBUF ;GIVE IT BACK MOV AX,[BP-2] ;SESSION FLAGS MOV SP,BP ;DELETE LOCAL STORAGE POP BP ;RESTORE PREVIOUS FRAME DEC MSGUCNT ;USER COUNT CALL FRETIO ;PURGE STACKED REQUESTS TEST AX,WFCALL ;CALLED ENTRY? JZ RMS99 ;NO RET RMS99: JMP MMENU1 ;MAIN MENU RMSHF: MOV AL,2 ;MESSAGE HELP FILE CALL SENDHF ;DISPLAY IT JMP RMS23 ;REPEAT MESSAGE ;-------------------------------------------------------------- ;RE-EDIT MESSAGE HEADER ;-------------------------------------------------------------- REEDIT: MOV DI,[BP-16] ;LAST MSG READ PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;BLOCK NUMBER POP BX MOV WORD PTR [BX+USRMP],AX ;SET FOR READ CALL READM ;READ HEADER MOV AX,[SI+MFSECT] ;SECTION # CALL TSIGOP ;PRIVILEGED USER? JNZ REED10 ;YES CALL INFROM ;AUTHOR? JNC REED10 ;YES MOV AX,391 ;'ONLY AUTHOR ... CALL WMSGNO ;DISPLAY MESSAGE JMP REED90 ;EXIT REED10: MOV AX,87H ;ENTER ALL BUT SECTION PUSH AX CALL VALSEC ;MORE THAN ONE SECTION? POP AX JNC REED20 ;NO CHOICE ON SECTIONS OR AX,8 ;EDIT SECTION # REED20: CALL ENTHDR ;GET NEW VALUES CALL WRITM ;RE-WRITE HEADER REED90: OR WORD PTR [BP-2],WFRET ;RETURN TO SAME MESSAGE JMP RMS24 ;NEXT ACTION ;--------------------------------------------------------- ;ENTER COMMENT ;--------------------------------------------------------- ENTCMT: CMP MSGUCNT,-1 ;FILE UNAVAILABLE? JNZ ENTC00 ;NO PROBLEM JMP MSNOGO ;YES - ABORT REQUEST ENTC00: INC MSGUCNT ;ACTIVE USER COUNT MOV AX,34 ;COMMENTS ARE ... CALL QMSGNO JC ENTC05 ;LOST CARRIER CALL DQCMD ;GET RESPONSE CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE ;TO UC CMP BYTE PTR [SI],'Y' ;YES? JZ ENTC10 ;GO DO IT ENTC05: MOV AX,35 ;NO COMMENT CALL WMSGNO DEC MSGUCNT ;ACTIVE USER COUNT JMP MMENU1 ;BACK TO MENU ENTC10: CALL BLDHDR ;BUILD DUMMY HEADER JC ENTC90 ;TOO MANY MESSAGES MOV SI,WORD PTR [BX+USRMB] ;HEADER MOV BYTE PTR [SI+MPFLAG],2 ;MARK PROTECTED MOV WORD PTR [SI-2],MTNAME ;TO NAME MOV AX,170 ;SYSOP CALL MOVMSG MOV WORD PTR [SI-2],MFSUBJ ;SUBJECT MOV AX,171 ;COMMENTS CALL MOVMSG CALL BLDMSG ;GO EDIT MESSAGE JC ENTC05 ;USER ABORTED MSG CALL ILINEB ;GET LINE BUFFER MOV AX,172 ;MANY THANKS ... CALL MOVMSG MOV DI,WORD PTR [BX+USR1N] ;FIRST NAME CALL MOVSTR CALL WRMSG ;DISPLAY MSG CALL FRELBF ;FREE RESPONSE BUFFER ENTC90: DEC MSGUCNT ;ACTIVE USER COUNT JMP MMENU1 ;BACK TO MAIN MENU ;--------------------------------------------------------- ;ENTER MESSAGE ; BP-2 FLAGS ;--------------------------------------------------------- ENTFM: MOV AX,1 ;MARK FOR FLASH MSG CALL TAYSOP ;PRIVILEGED? JNZ ENTM00 ;YES JMP MMENU2 ;INVALID COMMAND ENTMSG: XOR AX,AX ;CLEAR FLAGS MOV SI,WORD PTR [BX+USRST] ;USER RECORD TEST BYTE PTR [SI+UESTAT],12 ;REJECTED OR PENDING? JZ ENTM00 ;NO JMP ENTCMT ;FORCE COMMENT ENTM00: CMP MSGUCNT,-1 ;FILE UNAVAILABLE? JNZ ENTM03 ;NO PROBLEM JMP MSNOGO ;YES - ABORT REQUEST ENTM03: PUSH BP ;SAVE CALLER'S FRAME MOV BP,SP ;ALLOCATE LOCAL FRAME SUB SP,2 ;RESERVE LOCAL STORAGE MOV [BP-2],AX ;STORE FLAGS INC MSGUCNT ;COUNT ACTIVE USERS CALL BLDHDR ;BUILD DUMMY HEADER JNC ENTM05 ;OK JMP ENTM95 ;TOO MANY MESSAGES ENTM05: MOV AX,0FH ;ENTER ALL FIELDS CALL ENTHDR ;GET USER VALUES JC ENTM95 ;LOST CARRIER MOV SI,WORD PTR [BX+USRMB] ;MESSAGE HEADER TEST WORD PTR [BP-2],1 ;ENTER FLASH MSG? JZ ENTM90 ;NO OR BYTE PTR [SI+MPFLAG],1 ;MARK AS FLASH MSG MOV AX,DS:MSGCKPT+MLASTF ;LAST FLASH MSG MOV WORD PTR [SI+MFBPTR],AX ;SET BACKWARD POINTER ENTM90: CALL BLDMSG ;EDIT MESSAGE JC ENTM95 ;MESSAGE ABORTED TEST WORD PTR [BP-2],1 ;FLASH MSG? JZ ENTM95 ;NO PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;NEW MESSAGE NUMBER POP BX MOV DS:MSGCKPT+MLASTF,AX ;LAST FLASH MSG CMP DS:MSGCKPT+MFLASH,0 ;ANY PREVIOUS? JNZ ENTM95 ;YES MOV DS:MSGCKPT+MFLASH,AX ;SET FIRST FLASH MSG ENTM95: DEC MSGUCNT ;ACTIVE USER COUNT MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME JMP MMENU1 ;RETURN TO MAIN MENU ;----------------------------------------------------------------- ;GET MESSAGE HEADER INFO FROM USER ;ENTRY: SI -> MESSAGE HEADER ; AX = FIELDS TO UPDATE ; 01 = ADDRESSEE ; 02 = SUBJECT ; 04 = PROTECTION ; 08 = SECTION ; 80 = UPDATE EXISTING HEADER ;RETURNS: AX = FIELDS UPDATED ;LOCAL STORAGE: BP-2 FIELDS TO UPDATE ; BP-4 FIELDS UPDATED ; BP-6 A(MSG HEADER) ; BP-8 A(DEFAULT STRING) ; BP-10 DEFAULT SECTION # ;----------------------------------------------------------------- ENTHDR: PUSH BP ;SAVE CALLER'S FRAME MOV BP,SP ;ESTABLISH LOCAL FRAME SUB SP,10 ;ALLOCATE LOCAL STORAGE MOV [BP-2],AX ;SAVE FLAGS MOV [BP-6],SI ;SAVE HEADER XOR AX,AX ;NULL MOV [BP-4],AX MOV [BP-8],AX TEST WORD PTR [BP-2],1 ;UPDATE ADDRESSEE? JNZ ENTH00 ;YES JMP ENTH40 ;NO ENTH00: MOV DI,[BP-6] ;MSG HEADER ADD DI,MTNAME ;TO NAME MOV CX,MTSTMP-MTNAME ;FIELD LENGTH CALL MAKSTR ;MAKE INTO STRING MOV [BP-8],SI ;PARK OR CX,CX ;NULL? JNZ ENTH05 ;NO PROBLEM MOV AX,174 ;ALL CALL MOVMSG ;MOVE TO BUFFER CALL STRIP ;STRIP TRAILING BLANKS MOV CX,[SI-2] ;LENGTH PUSH ES PUSH DS POP ES REP MOVSB ;MOVE TO HEADER POP ES ENTH05: MOV AX,38 ;TO? MOV DI,[BP-8] ;DEFAULT STRING CALL QDFLT ;QUERY USER JNC ENTH07 ;OK JMP ENTH95 ;LOST CARRIER ENTH07: CALL DQCMD CALL FNAM ;FILTER NAME MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ ENTH40 ;USE DEFAULT OR WORD PTR [BP-4],1 ;SHOW NAME CHANGED CMP CX,23 ;MAX LENGTH JNA ENTH20 ;NO PROBLEM MOV AX,39 ;23 CHAR MAX CALL WMSGNO JMP ENTH05 ;REPEAT QUERY ENTH20: mov cx,23 ;field length call padb ;pad field MOV DI,SI ;STRING DATA MOV SI,WORD PTR [BX+USRMB] ;MESSAGE HEADER TEST WORD PTR [BP-2],80H ;CHANGING EXISTING HEADER? JZ ENTH22 ;NO - DON'T DELETE OLD ENTRY CALL DTOINX ;DELETE FROM TO INDEX AND BYTE PTR [SI+MRSTAT],NOT 12 ;RESET MSG READ ENTH22:MOV WORD PTR [SI-2],MTNAME ;TO NAME CALL MOVSTR ;MOVE TO BUFFER CALL VALNAM ;VALIDATE NAME JNC ENTH30 ;OK CALL ILINEB ;INITIALIZE A BUFFER MOV AX,142 ;THE NAME CALL MOVMSG ;MOVE TO BUFFER CALL MOVSTR ;MOVE NAME STRING MOV AX,143 ;IS NOT REGISTERED CALL MOVMSG ;MOVE TO BUFFER CALL WRMSG ;DISPLAY MESSAGE MOV AX,366 ;DO YOU WANT TO CHANGE ... CALL QMSGNO ;QUERY USER JC ENTH30 ;LOST CARRIER CALL DQCMD ;GET RESPONSE CALL XLATE CALL LALIGN ;STRIP LEADING BLANKS MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ ENTH05 ;DEFAULT TO YES CMP BYTE PTR [SI],'N' ;NO? JZ ENTH30 ;ACCEPT NAME JMP ENTH05 ;GET NEW NAME ENTH30: MOV SI,[BP-6] ;MESSAGE HEADER CALL ATOINX ;ADD TO INDEX ENTH40: TEST WORD PTR [BP-2],2 ;UPDATE SUBJECT? JZ ENTH60 ;NO MOV SI,[BP-8] ;DEFAULT STRING CALL FREBUF ;FREE IT MOV WORD PTR [BP-8],0 ;SHOW FREE MOV DI,[BP-6] ;MSG HEADER ADD DI,MFSUBJ ;SUBJECT MOV CX,MFBPTR-MFSUBJ ;FIELD LENGTH CALL MAKSTR ;MAKE INTO STRING MOV [BP-8],SI ;PARK MOV AX,40 ;SUBJECT MOV DI,[BP-8] ;DEFAULT STRING CALL QDFLT ;GET USER INPUT JNC ENTH42 ;OK ENTH41: JMP ENTH95 ;LOST CARRIER ENTH42: CALL DQCMD ;GET RESPONSE CMP WORD PTR [SI-2],0 ;ANYTHING? JNZ ENTH43 ;YES MOV SI,[BP-8] ;DEFAULT STRING CMP WORD PTR [SI-2],0 ;ANYTHING? JZ ENTH40 ;NO - INVALID ENTH43: CALL XLATE CALL LALIGN ;STRIP LEADING BLANKS MOV DI,SI ;STRING DATA MOV CX,WORD PTR [DI-2] ;LENGTH CMP CX,25 ;MAX LENGTH JNA ENTH50 ;NO PROBLEM MOV WORD PTR [DI-2],25 ;TRUNCATE MOV AX,41 ;SUBJECT TRUNCATED CALL WMSGNO ;DISPLAY MSG ENTH50: JCXZ ENTH40 ;REPEAT QUERY MOV CX,25 ;FIELD LENGTH CALL PADB ;PAD WITH BLANKS MOV SI,[BP-6] ;MESSAGE HEADER MOV WORD PTR [SI-2],MFSUBJ ;SUBJECT CALL MOVSTR OR WORD PTR [BP-4],2 ;SHOW SUBJECT CHANGED ENTH60: TEST WORD PTR [BP-2],4 ;UPDATE PROTECTION? JNZ ENTH61 ;YES JMP ENTH80 ;NO ENTH61: MOV SI,[BP-8] ;DEFAULT STRING CALL FREBUF ;FREE IT MOV WORD PTR [BP-8],0 ;SHOW FREE MOV SI,[BP-6] ;MSG HEADER ADD SI,MTNAME ;TO NAME MOV AX,174 ;ALL MSG CALL GETMSG ;GET IN BUFFER CALL CMPSTR ;EQUAL? PUSHF MOV SI,DI CALL FREBUF ;FREE STRING POPF JZ ENTH80 ;YES - SKIP PROTECTION MOV AX,1 ;SHORT BUFFER CALL GETBUF ;GET BUFFER MOV [BP-8],SI ;PARK MOV AL,'N' ;ASSUME NO MOV SI,[BP-6] ;MESSAGE HEADER TEST BYTE PTR [SI+MPFLAG],2 ;PROTECTED? JZ ENTH65 ;NO MOV AL,'Y' ;BAD GUESS ENTH65: MOV SI,[BP-8] ;DEFAULT STRING CALL APPBYT ;SET DEFAULT STRING MOV AX,42 ;SHORT QUERY CALL TXPRT ;EXPERT? JNZ ENTH70 ;YES ENTH69: MOV AX,43 ;LONG QUERY ENTH70: MOV DI,[BP-8] ;DEFAULT STRING CALL QDFLT ;GET USER RESPONSE JNC ENTH71 ;GOOD READ JMP ENTH95 ;LOST CARRIER ENTH71: CALL DQCMD CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ ENTH80 ;NO CHANGE LODSB ;GET CMD CHAR CMP AL,'?' ;FULL PROMPT? JZ ENTH69 ;YES CMP AL,'H' ;HELP? JNZ ENTH72 ;NO MOV AL,3 ;PROTECTION HELP FILE CALL SENDHF ;SEND IT JMP ENTH60 ;PROMPT AGAIN ENTH72: MOV SI,[BP-6] ;MESSAGE HEADER MOV AH,0 ;ASSUME NO PROTECTION CMP AL,'Y' ;YES? JNZ ENTH75 ;NO PROTECTION MOV AH,2 ;PROTECTED MOV WORD PTR [BP-10],0 ;DEFAULT TO SECTION 0 MOV WORD PTR [SI+MFSECT],0 ;SET SECTION NUMBER ENTH75: AND BYTE PTR [SI+MPFLAG],0FDH ;CLEAR OLD PROTECTION OR BYTE PTR [SI+MPFLAG],AH ;SET NEW PROTECTION FLAG ENTH80: TEST WORD PTR [BP-2],8 ;UPDATE SECTION? JNZ ENTH8A ;YES JMP ENTH90 ;NO ENTH8A: MOV SI,[BP-6] ;MESSAGE HEADER MOV AX,WORD PTR [SI+MFSECT] ;MSG SECTION TEST BYTE PTR [SI+MPFLAG],2 ;PROTECTED? JZ ENTH8B ;NO XOR AX,AX ;SECTION 0 MOV WORD PTR [SI+MFSECT],AX ;SET SECTION 0 CALL TAYSOP ;SYSOP AUTHORITY? JNZ ENTH83 ;YES - CAN CHANGE JMP ENTH90 ;EXIT ENTH8B: TEST WORD PTR [BP-2],80H ;SECTION PREVIOUSLY SET? JNZ ENTH83 ;YES CALL VALSEC ;CHECK VALID SECTION #S JC ENTH81 ;PROMPT FOR SECTION MOV WORD PTR [SI+MFSECT],AX ;SET SECTION NUMBER JMP ENTH90 ENTH81: OR AX,AX ;ANY VALID SECTIONS? JNZ ENTH82 ;YES MOV BYTE PTR [SI+MPFLAG],2 ;MARK PRIVATE JMP ENTH90 ;USE SECTION ZERO ENTH82: CALL NUMSEC ;GET DEFAULT SECTION MOV CX,AX ;SECTION NUMBER XOR AX,AX ;CLEAR MASK STC ;WILL SHIFT FROM CARRY RCL AX,CL ;SHIFT TO FLAG POSITION MOV WORD PTR [SI+MFSECT],AX ;SET DEFAULT SECTION NUMBER ENTH83: MOV [BP-10],AX ;REMEMBER MOV SI,[BP-8] ;DEFAULT STRING CALL FREBUF ;FREE IT MOV WORD PTR [BP-8],0 ;SHOW FREE MOV AX,2 ;BUFFER LENGTH CALL GETBUF ;GET BUFFER MOV [BP-8],SI ;PARK MOV AX,[BP-10] ;DEFAULT SECTION CALL NUMSEC ;CONVERT TO VALUE MOV [BP-10],AX ;DEFAULT MSG SECTION CALL BINASP ;PUT IN STRING ENTH8P: MOV AX,60 ;SECTION # PROMPT MOV DI,[BP-8] ;DEFAULT STRING CALL QDFLT ;ASK USER JNC ENTH84 ;GOOD READ JMP MMENU1 ;LOST CARRIER ENTH84: CALL DQCMD ;GET RESPONSE MOV AX,[BP-10] ;RESTORE DEFAULT MOV CX,WORD PTR [SI-2] ;RESPONSE LENGTH JCXZ ENTH8E ;USE DEFAULT CMP BYTE PTR [SI],'?' ;LIST SECTIONS? JNZ ENTH8D ;NO CALL VALSEC ;GET AVAILABLE SECTIONS MOV DX,AX ;SECTIONS TO LIST CALL DSPSEC ;LIST AVAILABLE SECTIONS JMP ENTH83 ;REPEAT PROMPT ENTH8D: CALL ASCBIN ;CONVERT TO BINARY ENTH8E: OR AX,AX ;ZERO? JNZ ENTH86 ;NO PROBLEM CALL TAYSOP ;SYSOP AUTHORITY? JNZ ENTH89 ;YES - ZERO IS OK JMP ENTH87 ;PROMPT AGAIN ENTH85: CALL VALSEC ;GET VALID SECTIONS CALL NUMSEC ;GET LOWEST VALID SECTION ENTH86: CMP AX,16 ;VALID? JA ENTH87 ;NO MOV CX,AX ;SECTION NUMBER XOR AX,AX ;CLEAR MASK STC ;WILL SHIFT FROM CARRY RCL AX,CL ;SHIFT TO FLAG POSITION OR AX,AX ;VALID? JNZ ENTH88 ;YES - GO STORE ENTH87: MOV AX,61 ;INVALID SECTION MSG CALL WMSGNO ;WRITE TO TERMINAL JMP ENTH8P ;PROMPT AGAIN ENTH88: MOV SI,[BP-6] ;MESSAGE HEADER MOV DI,WORD PTR [BX+USRST] ;USER RECORD TEST WORD PTR [DI+UESECT],AX ;VALID SECTION? JNZ ENTH89 ;YES TEST DS:MSGCKPT+MDPSECT,AX ;PUBLIC SECTION? JZ ENTH87 ;NO - INVALID ENTH89: MOV SI,[BP-6] ;MESSAGE HEADER MOV WORD PTR [SI+MFSECT],AX ;SET SECTION NUMBER ENTH90: CLC ;SHOW GOOD RETURN ENTH95: PUSHF MOV SI,[BP-8] ;DEFAULT STRING CALL FREBUF ;FREE IT MOV WORD PTR [BP-8],0 ;SHOW FREE MOV SI,[BP-6] ;MESSAGE HEADER MOV AX,[BP-4] ;UPDATE FLAGS POPF MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME RET ;MAKE STRING FROM FIELD IN BUFFER MAKSTR: PUSH AX MOV AX,CX ;BUFFER LENGTH CALL GETBUF ;GET BUFFER CALL MOVSTL ;MOVE FIELD CALL STRIP ;STRIP BLANKS MOV CX,WORD PTR [SI-2] ;STRING LENGTH POP AX RET ;QUERY USER WITH DEFAULT RESPONSE SHOWN QDFLT: PUSH AX CALL ILINEB ;INIT LINE BUFFER CALL MOVMSG ;MOVE MESSAGE TO BUFFER CMP WORD PTR [DI-2],0 ;NULL STRING? JZ QDFL10 ;YES - SKIP APPEND MOV AL,'[' CALL APPBYT CALL MOVSTR ;APPEND DEFAULT MOV AL,']' CALL APPBYT MOV AL,' ' CALL APPBYT QDFL10: CALL QUERY ;QUERY USER POP AX RET ;-------------------------------------------------------- ;KILL MESSAGE COMMAND ; BP-2 START OF RANGE ; BP-4 END OF RANGE ; BP-6 SECTION MASK ; BP-8 FLAGS ;-------------------------------------------------------- DELETE: FRAME 4 XOR AX,AX ;NULL MOV [BP-2],AX MOV [BP-4],AX MOV [BP-6],AX MOV [BP-8],AX DELE00: CALL DQCMD ;GET # TO DELETE JNC DELE10 ;NUMBER AVAILABLE MOV AX,55 ;NUMBER TO KILL CALL QMSGNO ;GET RESPONSE JC DELE90 ;LOST CARRIER JMP DELE00 ;GO PROCESS DELE10: MOV CX,WORD PTR [SI-2] ;STRING LENGTH JCXZ DELE90 ;NULL RESPONSE CALL ARANGE ;GET VALUES JB DELE90 ;NOT VALID MOV [BP-2],AX ;START OF RANGE MOV [BP-4],DX ;END OF RANGE OR DX,DX ;RANGE SUPPLIED? JNZ DELE15 ;YES - PROMPT FOR SECTIONS OR WORD PTR [BP-8],60H ;DELETE ALL BUT FLASH MSGS MOV WORD PTR [BP-6],-1 ;DELETE ALL SECTIONS JMP DELE80 ;GO DO IT DELE15: OR WORD PTR [BP-8],80H ;DELETE RANGE MOV SI,60 ;ENTER SECTION # CALL VALSEC ;GET VALID SECTIONS MOV DX,AX ;REMEMBER CALL PSECNO ;GET NEW VALUE MOV [BP-6],AX ;SECTION FLAGS OR AX,AX ;PRIVATE MESSAGES? JZ DELE18 ;YES - SET FLAG CMP AX,DX ;ANY CHANGE? JNZ DELE20 ;YES - NO SECTION 0 DELE18: OR WORD PTR [BP-8],40H ;DELETE PRIVATE MESSAGES DELE20: MOV AX,409 ;DELETE UNREAD MAIL? CALL QMSGNO ;GET RESPONSE JC DELE90 ;LOST CARRIER CALL DQCMD ;GET RESPONSE MOV CX,WORD PTR [SI-2] ;STRING LENGTH JCXZ DELE80 ;NULL RESPONSE CALL XLATE ;MAKE UPPER CASE CMP BYTE PTR [SI],'Y' ;YES? JNZ DELE80 ;NO OR WORD PTR [BP-8],20H ;DELETE UNREAD MAIL DELE80: MOV AX,[BP-8] PUSH AX ;FLAGS MOV AX,[BP-6] PUSH AX ;SECTION MASK MOV AX,[BP-4] PUSH AX ;END OF RANGE MOV AX,[BP-2] PUSH AX ;START OF RANGE CALL KILL00 ;GO KILL MESSAGE CALL DQCMD ;ANY MORE TO KILL? JNC DELE10 ;YES DELE90: EXITF MMENU1 ;MENU PROMPT ;-------------------------------------------------------- ;DISPLAY MESSAGE ;-------------------------------------------------------- DSPMSG: MOV WORD PTR [BX+USRMP],AX ;BLOCK NUMBER MOV WORD PTR [BP-6],0 ;KILL FORWARD POINTER CALL READM ;READ BLOCK JNZ DSPM02 ;IF INVALID READ MOV DI,WORD PTR [BX+USRMB] ;HEADER ADDRESS TEST WORD PTR [BP-2],WFDFM+WFEFM ;FLASH MESSAGES? JZ DSPM00 ;NO MOV AX,WORD PTR [DI+MFPTR1] ;FORWARD POINTER MOV [BP-6],AX ;SAVE TEST WORD PTR [BP-2],WFCALL ;LOGON TIME? JZ DSPM01 ;NO - SKIP DATE CHECK MOV SI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+MHDAT] ;YEAR OF MESSAGE CMP AX,WORD PTR [SI+UEPDAT] ;PREVIOUS YEAR JC DSPM02 ;SUPPRESS MSG JNZ DSPM01 ;TEST PROTECTION MOV AX,WORD PTR [DI+MHDAT+2] ;DAY & MONTH CMP AX,WORD PTR [SI+UEPDAT+2] ;LOGON MO/DAY JC DSPM02 ;SUPPRESS MSG JNZ DSPM01 ;TEST PROTECTION MOV AX,WORD PTR [DI+MHTIM] ;HOUR/MIN CMP AX,WORD PTR [SI+UEPTIM] ;LOGON HOUR/MIN JC DSPM02 ;SUPPRESS MSG JMP SHORT DSPM01 ;TEST PROTECTION DSPM00: TEST BYTE PTR [DI+MPFLAG],1 ;FLASH MSG? JNZ DSPM02 ;YES - SUPPRESS DSPM01: MOV SI,WORD PTR [BX+USRST] ;USER RECORD TEST BYTE PTR [SI+UESTAT],4 ;REJECTED? JNZ DSPM1A ;YES TEST BYTE PTR [DI+MPFLAG],2 ;PROTECTED? JZ DSPM03 ;NO PROBLEM MOV AX,WORD PTR [DI+MFSECT] ;MESSAGE SECTION # CALL TSIGOP ;PRIVILEDGED USER? JNZ DSPM04 ;YES DSPM1A: CALL ROWN ;CHECK READ OWNERSHIP JNC DSPM03 ;OK DSPM02: STC ;SHOW SUPPRESSED JMP DSPM91 ;EXIT DSPM03: MOV AX,WORD PTR [DI+MFSECT] ;MESSAGE SECTION # OR AX,AX ;SECTION 0? JZ DSPM04 ;YES MOV SI,WORD PTR [BX+USRST] ;USER RECORD TEST WORD PTR [SI+UESECT],AX ;AUTHORIZED SECTION? JNZ DSPM04 ;YES STC ;SHOW SUPPRESSED JMP DSPM91 ;EXIT DSPM04: CMP WORD PTR [BP-22],0 ;SEARCH? JZ DSPM06 ;NO MOV SI,[BP-22] ;SEARCH STRING MOV CX,WORD PTR [SI-2] ;STRING LENGTH ADD DI,MFNAME ;FROM NAME MOV AX,MFBPTR-MFNAME ;LENGTH TO SEARCH CALL INSTRG ;CHECK STRING MOV DI,WORD PTR [BX+USRMB] ;RESTORE HEADER ADDR JNC DSPM06 ;FOUND MATCH DSPM05: STC ;SHOW NO MATCH JMP DSPM91 ;EXIT DSPM06: TEST WORD PTR [BP-2],WFPRMT ;SEARCH SECTION? JZ DSPM08 ;NO MOV DI,WORD PTR [BX+USRMB] ;HEADER ADDRESS MOV AX,WORD PTR [DI+MFSECT] ;SECTION NUMBER OR AX,AX ;SECTION 0? JNZ DSPM07 ;NO TEST WORD PTR [BP-2],WFPRVT ;DISPLAY SECTION 0? JNZ DSPM08 ;YES DSPM07: AND AX,WORD PTR [BP-24] ;SELECTED SECTION? JZ DSPM05 ;NO DSPM08: TEST WORD PTR [BP-2],WFRC ;READ CONTINUOUS? JZ DSPM10 ;NO OR WORD PTR [BX+CBFLG],SFNOPL ;SUPPRESS PAGE LENGTH DSPM10: CALL ILINEB ;GET LINE BUFFER TEST WORD PTR [BP-2],WFQS ;QUICK SCAN? JZ DSPM20 ;NO ;PRINT SINGLE LINE HEADER FOR QUICK SCAN MOV AX,WORD PTR [DI+MMNUMB] ;MESSAGE NUMBER MOV CX,6 ;LENGTH CALL BINASC ;PLACE IN STRING CALL VALSEC ;MULTIPLE SECTIONS? JNC DSPM12 ;NO MOV AL,'-' ;DASH CALL APPBYT ;ADD TO STRING MOV AX,WORD PTR [DI+MFSECT] ;SECTION NUMBER CALL NUMSEC ;CONVERT TO BIT NUMBER CALL BINASP ;ADD TO STRING ADD WORD PTR [SI-2],1 ;LEAVE SPACE INC AX ;CONVERT TO SECT MSG # CALL MOVMSG ;ADD TITLE TO LINE DSPM12: MOV AL,' ' ;ASSUME NOT PROTECTED TEST BYTE PTR [DI+MPFLAG],2 ;IS IT? JZ DSPM13 ;NO MOV AL,'*' ;PROTECTION INDICATOR DSPM13: MOV BYTE PTR [SI],AL ;PLACE IN MESSAGE ADD WORD PTR [SI-2],2 ;LEAVE SPACE ADD DI,MFSUBJ ;SUBJECT MOV CX,25 ;LENGTH OF MESSAGE CALL MOVSTL ;MOVE TO BUFFER CALL WRMSG ;WRITE TO TERMINAL JNC DSPM15 ;OK OR WORD PTR [BP-2],WFNOM ;NO MORE PLEASE DSPM15: JMP DSPM90 ;EXIT ;PRINT FULL HEADER DSPM20: MOV AL,13 ;C/R CALL APPBYT TEST WORD PTR [BP-2],WFDFM ;DISPLAY FLASH MSGS? JZ DSPM21 ;NO ;PRINT FLASH HEADER MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER ADD DI,MFSUBJ ;SUBJECT MOV CX,25 ;FIELD LENGTH CALL MOVSTL ;MOVE TO MESSAGE ADD WORD PTR [SI-2],2 ;LEAVE TWO SPACES MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER MOV CX,WORD PTR [DI+MHDAT] ;YEAR MOV DX,WORD PTR [DI+MHDAT+2] ;MONTH & DAY CALL DTEASC ;FORMAT DATE JMP DSPM28 ;SKIP HEADER DSPM21: MOV AX,155 ;'MSG #' CALL MOVMSG ;MOVE TO BUFFER MOV DI,WORD PTR [BX+USRMB] ;MSG BUFFER MOV AX,WORD PTR [DI+MMNUMB] ;MSG NUMBER CALL BINASP ;PLACE IN STRING MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER CALL VALSEC ;MULTIPLE SECTIONS? JNC DSPM22 ;NO MOV AL,'-' ;DASH CALL APPBYT ;ADD TO STRING MOV AX,WORD PTR [DI+MFSECT] ;MESSAGE SECTION CALL NUMSEC ;CONVERT TO BIT NUMBER CALL BINASP ;PUT IN STRING ADD WORD PTR [SI-2],1 ;LEAVE SPACE INC AX ;CONVERT TO SECT MSG # CALL MOVMSG ;ADD TITLE TO LINE DSPM22: MOV AL,' ' ;ASSUME UNPROTECTED TEST BYTE PTR [DI+MPFLAG],2 ;PROTECTED? JZ DSPM23 ;NO MOV AL,'*' ;PROTECTION INDICATOR DSPM23: CALL APPBYT ;ADD TO STRING INC WORD PTR [SI-2] ;LEAVE SPACE MOV AX,156 ;'DATED' CALL MOVMSG ;MOVE TO PRINT LINE MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER ADD DI,MTSTMP ;TIME STAMP MOV CX,8 ;FIELD SIZE CALL MOVSTL ;MOVE TO MESSAGE ADD WORD PTR [SI-2],2 ;NEXT FIELD MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER ADD DI,MDSTMP ;DATE STAMP MOV CX,8 ;FIELD SIZE CALL MOVSTL ;MOVE TO MESSAGE ADD WORD PTR [SI-2],2 ;NEXT FIELD MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER MOV AX,WORD PTR [DI+MFBPTR] ;BACKWARD POINTER MOV [BP-8],AX ;SAVE BACK POINTER CALL EXIST ;DOES IT EXIST? JC DSPM24 ;NO CALL BINASP ;PUT IN HEADER PUSH DI MOV AX,162 ;ARROW CALL MOVMSG ;MOVE TO STRING POP DI DSPM24: MOV AX,WORD PTR [DI+MFPTR1] ;FORWARD POINTER MOV [BP-6],AX ;SAVE FORWARD POINTER CALL EXIST ;DOES IT EXIST? JC DSPM26 ;NO CMP WORD PTR [DI+MFSECT],0 ;MSG SECT 0? JNZ DSPM25 ;NO PROBLEM TEST BYTE PTR [DI+MPFLAG],2 ;PROTECTED? JZ DSPM26 ;NO - HIDE POINTER DSPM25: PUSH AX ;SAVE MSG NUMBER MOV AX,163 ;ARROW CALL MOVMSG ;MOVE TO STRING POP AX ;MESSAGE NUMBER CALL BINASP ;PUT IN HEADER DSPM26: CALL WRMSG JNC DSP26A ;OK JMP DSPM53 ;NO MORE DSP26A: CALL ILINEB ;BLANK BUFFER MOV AX,157 ;'FROM:' CALL MOVMSG ;MOVE TO MESSAGE MOV DI,WORD PTR [BX+USRMB] ;MESSAGE BUFFER ADD DI,MFNAME ;FROM NAME MOV CX,31 ;FIELD LENGTH CALL MOVSTL ;MOVE TO BUFFER CALL WRMSG ;WRITE TO TERMINAL JNC DSP26C ;OK JMP DSPM53 ;NO MORE PLEASE DSP26C: CALL ILINEB ;GET BLANK BUFFER MOV AX,158 ;'TO:' CALL MOVMSG ;MOVE TO MESSAGE MOV DI,[BX+USRMB] ;MESSAGE BUFFER ADD DI,MTNAME ;TO NAME MOV CX,23 ;FIELD LENGTH CALL MOVSTL ;MOVE TO MESSAGE CALL STRIP ;TRIM TRAILING BLANKS ;SEE IF MESSAGE HAS BEEN READ MOV DI,[BX+USRMB] ;MESSAGE HEADER TEST BYTE PTR [DI+MRSTAT],8 ;READ STATUS JZ DSPM27 ;NOT DELIVERED MOV AX,164 ;'(X)' CALL MOVMSG DSPM27: MOV SI,WORD PTR [BX+USRLB] ;BUFFER ADDRESS CALL WRMSG ;WRITE TO TERMINAL JNC DSP27A ;OK JMP DSPM53 ;NO MORE PLEASE DSP27A: CALL ILINEB ;BLANK BUFFER MOV AX,159 ;'RE:' CALL MOVMSG ;MOVE TO MESSAGE MOV DI,[BX+USRMB] ;MESSAGE BUFFER ADD DI,MFSUBJ ;SUBJECT MOV CX,25 ;FIELD LENGTH CALL MOVSTL ;MOVE TO MESSAGE DSPM28: MOV SI,WORD PTR [BX+USRLB] ;BUFFER ADDRESS CALL WRMSG ;WRITE TO TERMINAL JNC DSP28A ;OK JMP DSPM53 ;NO MORE PLEASE DSP28A: CALL ILINEB ;BLANK LINE CALL WRMSG ;WRITE TO TERMINAL JNC DSP28B ;OK JMP DSPM53 ;NO MORE PLEASE DSP28B: TEST WORD PTR [BP-2],WFRM ;READ MSG? JNZ DSPM29 ;YES JMP DSPM90 ;DONE DSPM29: CALL MRKMSG ;MARK MESSAGE READ MOV DI,WORD PTR [BX+USRMB] ;MESSAGE BUFFER MOV AX,WORD PTR [DI+MRSIZE] ;SIZE IN BLOCKS MOV [BP-12],AX XOR DX,DX ;CLEAR COUNT REG MOV DI,WORD PTR [BX+USRLB] ;LINE BUFFER DSPM30: DEC WORD PTR [BP-12] ;ANY MORE BLOCKS? JZ DSPM90 ;NO - DONE INC WORD PTR [BX+USRMP] ;NEXT MESSAGE BLOCK CALL READM ;READ BLOCK ;CHECK FOR OVERRUN OF PREVIOUS MESSAGE TEST BYTE PTR [SI],80H ;MESSAGE HEADER? JZ DSPM32 ;NO CMP BYTE PTR [SI+2],0 ;REASONABLE BLOCK SIZE? JNZ DSPM32 ;NO - TREAT AS TEXT JMP DSPM90 ;INVALID BLOCK COUNT DSPM32: MOV CX,MSGSIZ ;BLOCK SIZE CMP WORD PTR [BP-12],1 ;LAST BLOCK? JNZ DSPM40 ;NO PUSH SI ADD SI,MSGSIZ ;END OF BUFFER DSPM35: DEC SI ;PREVIOUS CHAR CMP BYTE PTR [SI],' ' ;BLANK? JNZ DSPM36 ;NO LOOP DSPM35 ;TRUNCATE BLANK DSPM36: POP SI DSPM40: LODSB ;NEXT CHAR CMP AL,227 ;END OF LINE? JZ DSPM50 ;YES - GO PRINT MOV [DI],AL ;PUT IN BUFFER INC DI ;NEXT BUFFER POS INC DX ;COUNT CHARS CMP DX,80 ;FULL? JNZ DSPM60 ;NO - KEEP TRUCKING DSPM50: PUSH SI MOV SI,WORD PTR [BX+USRLB] ;LINE BUFFER MOV WORD PTR [SI-2],DX ;SET DATA LENGTH CALL CKCTLK ;ABORT REQUEST? JNC DSPM51 ;NO AND WORD PTR [BP-2],NOT WFRC ;ABORT READ CONT. POP SI ;CLEAN UP STACK JMP SHORT DSPM53 ;TERMINATE PRINT DSPM51: CALL WRMSG ;WRITE TO TERMINAL POP SI JNC DSPM55 ;CONTINUE JMP SHORT DSPM90 ;EXIT ;TERMINATE PRINT DSPM53: OR WORD PTR [BP-2],WFNOM ;NO MORE PLEASE JMP DSPM90 ;EXIT DSPM55: XOR DX,DX ;CLEAR COUNT MOV DI,WORD PTR [BX+USRLB] ;LINE BUFFER DSPM60: LOOP DSPM40 ;GET NEXT CHAR JMP DSPM30 ;GET NEW BLOCK DSPM90: CLC ;SHOW GOOD RETURN DSPM91: PUSHF ;REMEMBER CARRY FLAG CALL FRELBF ;FREE LINE BUFFER POPF ;RESTORE CARRY RET ;ACCOUNT FOR MESSAGE READ MRKMSG: MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV SI,WORD PTR [BX+USRMB] ;MESSAGE HEADER TEST WORD PTR [BP-2],WFDFM+WFEFM ;FLASH MESSAGE? JNZ MRKM10 ;YES - DON'T UPDATE INC WORD PTR [DI+UEMSGR] ;RECORDS READ MOV AX,WORD PTR [SI+MMNUMB] ;MESSAGE NUMBER CMP AX,WORD PTR [DI+UEHMSG] ;LAST MESSAGE READ JLE MRKM10 ;LESS THAN POINTER MOV WORD PTR [DI+UEHMSG],AX ;UPDATE POINTER MRKM10: CALL INTOST ;ADDRESSEE? JNZ MRKM20 ;NO OR BYTE PTR [SI+MRSTAT],8 ;MARK MSG DELIVERED CALL WRITM ;RE-WRITE HEADER MRKM20: RET ;CHECK FOR UNREAD MESSAGES ; BP-2 # OF MSGS FOUND ; BP-4 UNUSED ; BP-6 INDEX TO MSG HEADERS ; BP-8 USER SECTION MASK ; BP-10 USER STATUS MASK CKMSG: CMP MSGUCNT,-1 ;FILE UNAVAILABLE? JNZ CKMSG0 ;NO PROBLEM MOV AX,58 ;BEING COMPRESSED CALL WMSGNO ;TELL USER RET CKMSG0: PUSH BP ;SAVE CALLER'S FRAME MOV BP,SP ;CREATE LOCAL FRAME SUB SP,10 ;ALLOCATE LOCAL STORAGE INC MSGUCNT ;SHOW FILE IN USE PUSH AX MOV AX,32 ;CHECKING ... CALL WMSGNO MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+UESECT] ;AUTHORIZED SECTIONS MOV [BP-8],AX XOR AX,AX MOV AL,BYTE PTR [DI+UESTAT] ;USER STATUS MOV [BP-10],AX POP AX MOV WORD PTR [BP-2],-1 ;CLEAR COUNTER CKMSG1: CALL FINDMN ;LOCATE MSG # JNC CKMSG2 ;FOUND IT MOV DI,DS:MSGCKPT+MILAST PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX CMP AX,[BX+DI] ;TOO HIGH? POP BX JBE CKMS1A ;NO PROBLEM JMP CKMSG6 ;DONE CKMS1A: INC AX ;NEXT MSG NUMBER MOV DI,DS:MSGCKPT+MIFRST PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX CMP AX,[BX+DI] ;TOO LOW? POP BX JAE CKMSG1 ;NO PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;START WITH FIRST POP BX JMP CKMSG1 ;TRY NEXT # CKMSG2: PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;BLOCK NUMBER POP BX MOV [BP-6],DI ;MESSAGE INDEX MOV WORD PTR [BX+USRMP],AX ;STARTING BLOCK CALL READM ;READ MESSAGE HEADER JZ CKMS2A ;GOOD READ JMP CKMSG6 ;END OF FILE CKMS2A: TEST BYTE PTR [SI+MPFLAG],1 ;FLASH MSG? JNZ CKMSG5 ;YES - SKIP CMP WORD PTR [SI+MFSECT],0 ;GLOBAL MSG? JZ CKMS2B ;YES MOV AX,[BP-8] ;USER SECTION MASK TEST WORD PTR [SI+MFSECT],AX ;VALID SECTION FOR USER? JZ CKMSG5 ;NO CKMS2B: TEST BYTE PTR [BP-10],4 ;VALIDATION REJECTED? JNZ CKMS2C ;YES TEST BYTE PTR [SI+MRSTAT],8 ;ALREADY READ? JNZ CKMSG5 ;YES - SKIP CALL CKALL ;GENERAL MESSAGE? JNC CKMSG3 ;YES CKMS2C: CALL INTOST ;CHECK ADDRESSEE JC CKMSG5 ;NOT FOR US OR WORD PTR [BP-10],8000H ;FLAG PERSONAL CKMSG3: CMP WORD PTR [BP-2],-1 ;FIRST ONE? JNZ CKMSG4 ;NO MOV AX,33 ;FOLLOWING MSGS ... CALL WMSGNO INC WORD PTR [BP-2] ;MARK MSGS FOUND CALL ILINEB ;GET LINE BUFFER CKMSG4: MOV SI,WORD PTR [BX+USRMB] ;MESSAGE HEADER MOV AX,WORD PTR [SI+MMNUMB] ;MESSAGE NUMBER MOV SI,WORD PTR [BX+USRLB] ;LINE BUFFER CALL BINASP ;PUT NUMBER IN BUFFER TEST WORD PTR [BP-10],8000H ;PERSONAL? JZ CKMS4A ;NO MOV AL,'!' ;PERSONAL MAIL CALL APPBYT ;FLAG MESSAGE AND WORD PTR [BP-10],7FFFH ;CLEAR FLAG CKMS4A: INC WORD PTR [SI-2] ;ALLOW ONE SPACE INC WORD PTR [BP-2] ;COUNT MSG CMP WORD PTR [BP-2],12 ;LINE FULL? JBE CKMSG5 ;NO MOV SI,WORD PTR [BX+USRLB] ;START OF LINE CALL WRMSG ;DISPLAY CALL ILINEB ;GET NEW BUFFER MOV WORD PTR [BP-2],0 ;CLEAR COUNT CKMSG5: ADD WORD PTR [BP-6],2 ;NEXT MSG INX MOV DI,[BP-6] ;MSG INX CMP DI,DS:MSGCKPT+MILAST ;END OF FILE? JA CKMSG6 ;YES JMP CKMSG2 ;CHECK NEXT MESSAGE CKMSG6: CMP WORD PTR [BP-2],0 ;ANY MSGS FOUND? JZ CKMSG8 ;ALREADY PRINTED JG CKMSG7 ;YES - GO PRINT CALL ILINEB ;GET BUFFER MOV AX,160 ;'SORRY CALL MOVMSG ;PUT IN BUFFER MOV DI,WORD PTR [BX+USR1N] ;1ST NAME CALL MOVSTR ;PUT IN BUFFER MOV AX,186 ;'NO MAIL CALL MOVMSG ;PUT IN BUFFER CKMSG7: MOV SI,WORD PTR [BX+USRLB] ;START OF BUFFER CALL WRMSG ;DISPLAY CKMSG8: CALL FRELBF ;FREE LINE BUFFER MOV SI,WORD PTR [BX+USRMB] ;MESSAGE BUFFER CALL FREBUF ;FREE IT MOV WORD PTR [BX+USRMB],0 ;MARK FREE MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME DEC MSGUCNT ;NO LONGER USING RET NOMSGN: PUSH BP ;SAVE PREVIOUS FRAME MOV BP,SP ;SET LOCAL FRAME SUB SP,2 ;CREATE LOCAL STORAGE MOV [BP-2],AX ;MESSAGE INDEX CALL ILINEB ;GET LINE BUFFER MOV AX,160 ;'SORRY, ' CALL MOVMSG ;PUT IN STRING MOV DI,WORD PTR [BX+USR1N] ;FIRST NAME CALL MOVSTR ;PUT IN STRING MOV AX,161 ;'NO MSG #' CALL MOVMSG ;PUT IN STRING MOV AX,[BP-2] ;MSG NUMBER CALL BINASP CALL WRMSG ;WRITE TO TERMINAL CALL FRELBF ;FREE LINE BUFFER MOV SP,BP ;DELETE LOCAL STORAGE POP BP ;RESTORE PREVIOUS FRAME RET ;BUILD DUMMY MESSAGE HEADER BLDHDR: PUSH BP ;SAVE CALLER'S FRAME MOV BP,SP ;ESTABLISH LOCAL FRAME PUSH CX PUSH DX PUSH DI MOV DI,DS:MSGCKPT+MDIMAX ;MAXIMUM MSGS DEC DI SHL DI,1 ;MAXIMUM INDEX CMP DS:MSGCKPT+MILAST,DI ;LAST INDEX JL BLDH03 ;NO PROBLEM MOV AX,36 ;TOO MANY ... BLDH00: CALL WMSGNO ;TELL USER MOV AX,397 ;MESSAGE LOST CALL ILINEB ;GET BUFFER CALL MOVMSG ;GET MSG IN BUFFER CALL LOGDSK ;LOG TO DISK STC ;SHOW PROBLEM JMP BLDH90 ;EXIT BLDH03: CALL CKFSPC ;CHECK FILE SPACE CMP AX,0 ;OUT OF SPACE? JNZ BLDH05 ;NO PROBLEM MOV AX,37 ;NO SPACE JMP BLDH00 ;TELL USER BLDH05: MOV SI,WORD PTR [BX+USRMB] ;BUFFER ADDRESS OR SI,SI ;EXIST? JZ BLDH10 ;NO CALL FREBUF ;FREE EXISTING BUFFER BLDH10: MOV AX,MSGSIZ ;BUFFER SIZE CALL GETBUF ;GET BUFFER MOV WORD PTR [BX+USRMB],SI ;SAVE BUFFER ADDRESS MOV DI,SI ;CURRENT POINTER PUSH ES PUSH DS POP ES MOV AL,0E1H ;LIVE MESSAGE STOSB ;PUT IN HEADER XOR AX,AX ;NULL STOSW ;0 MSG BLOCKS STOSW ;PROTECTION/STATUS STOSW ;MESSAGE NUMBER MOV AL,' ' MOV CX,95 REP STOSB ;BLANK STRING AREAS XOR AX,AX MOV CX,26 REP STOSB ;ZERO POINTER FIELDS POP ES MOV WORD PTR [SI-2],MFNAME ;FROM NAME MOV DI,WORD PTR [BX+USR3N] ;USER NAME CALL MOVSTR ;PUT IN HEADER MOV WORD PTR [SI-2],MTSTMP ;TIME STAMP CALL DOSTIM ;GET TIME MOV WORD PTR [SI+MHTIM],CX ;HOUR AND MINUTE MOV WORD PTR [SI+MHTIM+2],DX ;SECONDS CALL TIMHM ;HOURS & MINUTES MOV AL,':' ;DELIMITER CALL APPBYT ;PLACE IN STRING MOV AL,DH ;SECONDS CBW MOV CX,8002H ;FORCE LEADING ZEROS CALL BINASC ;PUT IN STRING CALL DOSDAT ;GET DATE MOV WORD PTR [SI+MHDAT],CX ;YEAR MOV WORD PTR [SI+MHDAT+2],DX ;MONTH & DAY CALL DATASC ;DATE STAMP CLC ;GOOD RETURN BLDH90: POP DI POP DX POP CX MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME RET ;PACK MESSAGE INDEX ARRAYS IF REQUIRED PKINX: CMP MSGUCNT,0 ;IN USE? JNZ PKINX1 ;YES - EXIT CMP KILLCNT,0 ;ANYTHING TO PACK? JNZ PKINX2 ;YES - GO DO IT CMP ADDCNT,0 ;ANYTHING ADDED? JZ PKINX1 ;NO - EXIT JMP PKINX7 ;SAVE INDEX PKINX1: RET PKINX2: PUSH AX PUSH SI PUSH DI XOR SI,SI MOV DI,DS:MSGCKPT+MIFRST ;1ST ACTIVE ENTRY PUSH BX PKINX3: CMP DI,DS:MSGCKPT+MILAST ;END OF ARRAY? JG PKINX6 ;YES - DONE MOV BX,MSGINX1 ;NUMBER INDEX CMP WORD PTR [BX+DI],0 ;DELETED ENTRY? JZ PKINX5 ;YES - SKIP CMP DI,SI ;ANY ACTION YET? JZ PKINX4 ;NO MOV AX,[BX+DI] ;MSG NUMBER MOV [BX+SI],AX ;MOVE DOWN MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;BLOCK NUMBER MOV [BX+SI],AX ;MOVE DOWN PKINX4: ADD SI,2 PKINX5: ADD DI,2 JMP PKINX3 ;CHECK NEXT ENTRY PKINX6: POP BX SUB SI,2 ;BACK UP TO LAST ENTRY MOV DS:MSGCKPT+MILAST,SI ;MARK END OF ARRAY MOV DS:MSGCKPT+MIFRST,0 ;MARK START OF ARRAY MOV KILLCNT,0 ;CLEAR KILL COUNT POP DI POP SI POP AX PKINX7: CALL SAVINX ;STORE NEW INDEX ARRAYS MOV ADDCNT,0 ;CLEAR ADD COUNT RET ;BUILD AND EDIT MESSAGE ; BP-2 CURRENT LINE ADDRESS ; BP-4 LINE INDEX ARRAY ; BP-6 # OF LINES ; BP-8 PAGE MARGIN ; BP-10 CURRENT LINE # ; BP-12 WORK REGISTER ; BP-14 PARTIAL LINE ADDRESS ; BP-16 NEXT STACKED CMD ADDR ; BP-18 'TO' STRING ; BP-20 'RE' STRING ; BP-22 FLAGS ; 1 ANSI STRING IN INPUT LINE BLDMSG: PUSH BP ;SAVE CALLER'S FRAME MOV BP,SP ;ESTABLISH LOCAL FRAME SUB SP,22 ;ALLOCATE LOCAL SPACE MOV WORD PTR [BP-6],0 ;SHOW NO LINES YET MOV WORD PTR [BP-10],0 ;START WITH 1ST LINE MOV WORD PTR [BP-14],0 ;NO PARTIAL LINE MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+UEMARG] ;USER MARGIN CMP AX,80 ;MAXIMUM VALUE JNA BLDM05 ;OK MOV AX,80 ;DEFAULT BLDM05: MOV [BP-8],AX ;CREATE 'TO' AND 'RE' STRINGS MOV AX,25 ;LENGTH CALL GETBUF ;GET BUFFER MOV DI,[BX+USRMB] ;MESSAGE HEADER ADD DI,MTNAME ;'TO' NAME MOV CX,MTSTMP-MTNAME ;LENGTH CALL MOVSTL ;MOVE TO BUFFER CALL STRIP ;STRIP TRAILING BLANKS MOV [BP-18],SI ;'TO' NAME STRING MOV AX,25 ;LENGTH CALL GETBUF ;GET BUFFER MOV DI,[BX+USRMB] ;MESSAGE HEADER ADD DI,MFSUBJ ;SUBJECT MOV CX,MFBPTR-MFSUBJ ;LENGTH CALL MOVSTL ;MOVE TO BUFFER CALL STRIP ;STRIP TRAILING BLANKS MOV [BP-20],SI ;'RE' STRING MOV AX,WORD PTR [BX+USRIN] ;1ST INPUT BUFFER MOV [BP-16],AX MOV AX,256 ;LINE INDEX SIZE CALL GETBUF ;GET INDEX MOV [BP-4],SI ;SAVE ADDRESS MOV DI,SI MOV CX,128 ;SIZE IN WORDS XOR AX,AX PUSH ES PUSH DS POP ES REP STOSW ;CLEAR TO ZEROS POP ES CALL TXPRT ;EXPERT? JNZ BLDM20 ;YES MOV AX,44 ;TO ENTER MSG ... CALL WMSGNO BLDM20: CALL DRWMGN ;DRAW RULER BLDM30: CALL ILINEB ;INIT LINE BUFFER MOV AX,[BP-10] ;CURRENT LINE INC AX ;BASE 1 MOV CX,3 ;FIELD WIDTH CALL BINASC ;PUT IN BUFFER MOV AL,':' ;DELIMITER CALL APPBYT ;ADD TO STRING INC WORD PTR [SI-2] ;LEAVE ONE SPACE MOV AX,[BP-14] ;PARTIAL LINE MOV [BP-2],AX ;SAVE AS CURRENT MOV WORD PTR [BP-14],0 ;CLEAR PARTIAL LINE FLAG OR AX,AX ;EXIST? JZ BLDM32 ;NO MOV DI,AX ;PARTIAL STRING CALL MOVSTR ;MOVE TO BUFFER BLDM32: CALL WRLIN ;DISPLAY LINE NUMBER CALL INLIN ;GET MESSAGE LINE JNC BLDM34 ;GO STORE LINE MOV DI,[BP-2] ;EMPTY LINE ADDRESS CALL FREBUF ;FREE IT JMP BLDM50 ;SUBFUNCTION PROMPT BLDM34: MOV DI,[BP-10] ;CURRENT LINE NUMBER SHL DI,1 ;FORM INDEX ADD DI,[BP-4] ;START OF ARRAY MOV SI,[BP-6] ;END OF ARRAY SHL SI,1 ;FORM INDEX ADD SI,[BP-4] ;START OF ARRAY BLDM36: CMP SI,DI ;DONE? JZ BLDM40 ;YES MOV AX,WORD PTR [SI-2] ;PREVIOUS ENTRY MOV WORD PTR [SI],AX ;MOVE IT UP SUB SI,2 ;WORK DOWN JMP BLDM36 ;LOOP 'TIL DONE BLDM40: MOV AX,[BP-2] ;LINE ADDRESS MOV WORD PTR [DI],AX ;PUT IN ARRAY INC WORD PTR [BP-6] ;NUMBER OF LINES INC WORD PTR [BP-10] ;NEXT LINE NUMBER BLDM41: CMP WORD PTR [BP-6],125 ;ALMOST FULL? JNZ BLDM42 ;NO PROBLEM MOV AX,45 ;TWO LINES ... CALL WMSGNO BLDM42: CMP WORD PTR [BP-6],126 ;EVEN FULLER? JNZ BLDM44 ;NO PROBLEM MOV AX,46 ;LAST LINE ... CALL WMSGNO BLDM44: CMP WORD PTR [BP-6],127 ;FULL? JNZ BLDM46 ;NO PROBLEM MOV AX,47 ;MESSAGE FULL CALL WMSGNO JMP SHORT BLDM50 BLDM46: JMP BLDM30 ;NEXT LINE BLDM50: MOV AX,48 ;SHORT SUBFUNCTION PROMPT CALL TXPRT ;EXPERT? JNZ BLDM52 ;YES BLDM51: MOV AX,49 ;LONG SUBFUNCTION PROMPT BLDM52: CALL QMSGNO JNC BLDM53 ;GOOD READ JMP BLDM90 ;LOST CARRIER BLDM53: CALL DQCMD CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ BLDM50 ;REPEAT PROMPT LODSB ;GET CMD CHAR MOV DI,OFFSET CTBL5 ;MSG SUBFUNCTION CMD STR MOV CX,(JTBL5-CTBL5) ;STRING LENGTH REPNZ SCASB ;CHECK FOR MATCH JNZ BLDM50 ;NO MATCH SUB DI,OFFSET CTBL5+1 ;OFFSET IN STRING SHL DI,1 ;FOR TABLE WIDTH JMP JTBL5[DI] ;GO TO COMMAND ;ABORT MSG MSFA00: MOV AX,50 ;ABORT MSG? CALL QMSGNO JC MSFA10 ;LOST CARRIER CALL DQCMD CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE CMP BYTE PTR [SI],'Y' ;YES? JZ MSFA10 ;YES JMP BLDM50 ;REPEAT PROMPT MSFA10: MOV AX,51 ;ABORTED CALL WMSGNO STC ;SHOW MESSAGE ABORTED JMP BLDM90 ;FREE ALL STORAGE MSFC00: CALL DRWMGN ;DRAW MARGIN RULER MOV AX,[BP-6] ;LAST LINE MOV [BP-10],AX ;SET AS CURRENT JMP BLDM41 ;RESUME INPUT MSFD00: CALL ILINEB ;GET LINE BUFFER MOV AX,178 ;DELETE CALL MOVMSG ;PUT IN BUFFER CALL QLINE ;GET LINE NUMBER JC MSFD90 ;INVALID - EXIT CMP AX,-2 ;HEADER? JNB MSFD90 ;CAN NOT DELETE HEADER LINE CALL LISTLN ;DISPLAY LINE MOV DI,AX ;LINE NUMBER MOV AX,52 ;DELETE THIS LINE? CALL QYESNO ;CHECK FOR CONFIRMATION MOV AX,DI ;LINE NUMBER JC MSFD05 ;DEFAULT TO NO JZ MSFD10 ;OK TO DELETE MSFD05: CALL ILINEB ;FORMAT BUFFER PUSH AX MOV AX,175 ;LINE # CALL MOVMSG POP AX CALL BINASP ;PUT LINE NUMBER IN STR INC WORD PTR [SI-2] ;LEAVE SPACE MOV AX,176 ;NOT CALL MOVMSG MOV AX,177 ;DELETED CALL MOVMSG MOV SI,WORD PTR [BX+USRLB] ;LINE BUFFER CALL WRMSG JMP BLDM50 ;BACK TO PROMPT MSFD10: DEC DI ;BASE 0 SHL DI,1 ;FOR INDEX ADD DI,[BP-4] ;START OF INDEX MOV SI,DI ADD SI,2 ;FIRST TO MOVE MOV CX,[BP-6] ;NUMBER OF LINES SUB CX,AX ;NUMBER TO MOVE DEC WORD PTR [BP-6] ;NEW NUMBER OF LINES PUSH SI MOV SI,WORD PTR [DI] ;ADDRESS TO FREE CALL FREBUF ;FREE IT POP SI PUSH ES PUSH DS POP ES REP MOVSW ;MOVE LINES DOWN POP ES PUSH AX CALL ILINEB ;FORMAT BUFFER MOV AX,175 ;LINE # CALL MOVMSG POP AX CALL BINASP ;INSERT LINE # INC WORD PTR [SI-2] ;LEAVE ONE SPACE MOV AX,177 ;DELETED CALL MOVMSG CALL WRMSG MSFD90: JMP BLDM50 MSFE00: CALL ILINEB ;INIT LINE BUFFER CALL QLINE ;GET LINE NUMBER JNC MSFE10 ;VALID MSFE05: JMP BLDM50 ;SUBFUNCTION PROMPT MSFE10: CALL LISTLN ;DISPLAY LINE MOV AX,53 ;EDIT INSTRUCTIONS CALL QMSGNO ;GET CHANGE STRINGS JC MSFE05 ;LOST CARRIER CALL DQCMD ;GET OLD STRING MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ MSFE05 ;NO STRING MOV DI,[BP-2] ;EXISTING LINE MOV AX,WORD PTR [DI-2] ;TARGET LENGTH CALL INSTRG ;CHECK FOR MATCH JNC MSFE20 ;FOUND CALL ILINEB ;FORMAT BUFFER MOV AX,180 ;STRING < CALL MOVMSG MOV DI,WORD PTR [BX+USRCMD] ;OLD STRING CMP WORD PTR [DI-2],45 ;MAX TO PRINT JLE MSFE15 ;NO PROBLEM MOV WORD PTR [DI-2],45 ;TRUNCATE STRING MSFE15: CALL MOVSTR MOV AX,181 ;> NOT FOUND CALL MOVMSG MOV AX,[BP-10] ;LINE NUMBER CALL BINASP ;PUT IN BUFFER CALL WRMSG CALL DQCMD ;PURGE REPLACEMENT STRING JMP MSFE10 ;TRY AGAIN MSFE20: ADD DI,AX ;POSITION IN STRING MOV [BP-12],DI ;SAVE MOV DX,WORD PTR [SI-2] ;LENGTH TO REPLACE CALL DQCMD ;GET REPLACEMENT STRING JC MSFE35 ;NO REPLACEMENT STRING MOV CX,WORD PTR [SI-2] ;REPLACEMENT LENGTH CMP CX,DX ;SAME? JNZ MSFE30 ;NO PUSH ES PUSH DS POP ES REP MOVSB ;OVERLAY STRING POP ES JMP MSFE10 ;EDIT PROMPT MSFE30: JA MSFE40 ;MUST EXPAND STRING SUB DX,CX ;CHARS TO DELETE JCXZ MSFE32 ;NULL SECOND STRING PUSH ES PUSH DS POP ES REP MOVSB ;OVERLAY STRING POP ES MSFE32: MOV SI,DI ;END OF OVERLAY ADD SI,DX ;CHARS TO DELETE MOV [BP-12],DI ;CURRENT POSITION MOV DI,[BP-2] ;ORIGINAL STRING MOV CX,DI ;START OF TEXT ADD CX,WORD PTR [DI-2] ;POINT PAST END SUB CX,SI ;LESS ALREADY MOVED SUB WORD PTR [DI-2],DX ;ADJUST LENGTH MOV DI,[BP-12] ;CURRENT POSITION JCXZ MSFE35 ;END OF STRING PUSH ES PUSH DS POP ES REP MOVSB ;SHIFT DOWN STRING POP ES MSFE35: JMP MSFE10 ;EDIT PROMPT MSFE40: PUSH AX ;OFFSET MOV AX,CX ;NEW STR LENGTH SUB AX,DX ;OLD STR LENGTH MOV DI,[BP-2] ;CURRENT STR ADD AX,WORD PTR [DI-2] ;CURRENT STR LENGTH CALL GETBUF ;GET NEW BUFFER MOV WORD PTR [SI-2],AX ;SET LENGTH XCHG SI,DI POP CX ;LENGTH OF 1ST PART PUSH DI ;SAVE NEW STRING ADDR JCXZ MSFE42 ;NO 1ST PART PUSH ES PUSH DS POP ES REP MOVSB ;MOVE 1ST PART POP ES MSFE42: ADD SI,DX ;SKIP REPLACED CHARS MOV [BP-12],SI ;SAVE POSITION MOV SI,WORD PTR [BX+USRCMD] ;REPLACEMENT STRING MOV CX,WORD PTR [SI-2] ;STRING LENGTH PUSH ES PUSH DS POP ES REP MOVSB ;COPY REPLACEMENT STRING POP ES MOV SI,[BP-2] ;CURRENT STRING MOV CX,WORD PTR [SI-2] ;ORIGINAL LENGTH ADD CX,SI ;POINT TO END MOV SI,[BP-12] ;CURRENT POSITION SUB CX,SI ;REMAINING LENGTH JCXZ MSFE44 ;END OF STRING PUSH ES PUSH DS POP ES REP MOVSB ;COPY 2ND PART POP ES MSFE44: MOV SI,[BP-2] ;ORIGINAL STRING CALL FREBUF ;FREE IT POP SI ;NEW STRING MOV [BP-2],SI ;SAVE MOV DI,[BP-10] ;CURRENT LINE NUMBER OR DI,DI ;POSITIVE? JS MSFE50 ;NO DEC DI ;ZERO BASE SHL DI,1 ;MAKE INDEX ADD DI,[BP-4] ;ORIGIN MOV AX,[BP-2] ;CURRENT LINE MOV WORD PTR [DI],AX ;PUT IN INDEX JMP MSFE10 ;REPEAT PROMPT MSFE50: CMP WORD PTR [BP-10],-1 ;SUBJECT? JNZ MSFE52 ;NO MOV [BP-20],SI ;NEW SUBJECT STRING JMP MSFE10 ;EDIT PROMPT MSFE52: MOV [BP-18],SI ;NEW 'TO' STRING JMP MSFE10 ;EDIT PROMPT MSFH00: MOV AL,4 ;SUBFUNCTION HELP FILE CALL SENDHF ;DISPLAY IT JMP BLDM50 ;REPEAT PROMPT MSFI00: CALL ILINEB ;FORMAT BUFFER MOV AX,182 ;BEFORE CALL MOVMSG CALL QLINE ;GET LINE NUMBER JC MSFI10 ;INVALID CMP AX,-2 ;HEADER? JB MSFI20 ;NO MSFI10: JMP BLDM50 ;SUBFUNCTION PROMPT MSFI20: DEC AX ;ZERO BASE MOV [BP-10],AX ;SET CURRENT LINE # JMP BLDM41 ;GO INSERT MSFL00: CALL ILINEB ;INIT LINE BUFFER MOV AX,158 ;TO CALL MOVMSG ;MOVE TO BUFFER CALL STRIP ;STRIP TRAILING BLANKS INC WORD PTR [SI-2] ;ONE SPACE MOV DI,[BP-18] ;TO NAME CALL MOVSTR INC WORD PTR [SI-2] ;LEAVE SPACE MOV AX,159 ;RE CALL MOVMSG CALL STRIP ;STRIP TRAILING BLANKS INC WORD PTR [SI-2] ;ONE SPACE MOV DI,[BP-20] ;SUBJECT CALL MOVSTR CALL WRMSG CALL DRWMGN ;DRAW MARGIN RULE MOV CX,[BP-6] ;LINES TO LIST JCXZ MSFL20 ;EMPTY MESSAGE MOV WORD PTR [BP-10],1 ;1ST LINE MSFL10: CALL LISTLN ;LIST LINE JC MSFL20 ;NO MORE INC WORD PTR [BP-10] ;NEXT LINE LOOP MSFL10 ;GO HANDLE MSFL20: JMP BLDM50 ;ISSUE PROMPT MSFM00: MOV AX,WORD PTR [BX+USRST] ;USER RECORD PUSH AX ;PASS AS PARM CALL SETMGN ;SET MARGIN JC MSFM10 ;NO CHANGE MOV [BP-8],AX ;NEW MARGIN MSFM10: JMP BLDM50 ;ISSUE PROMPT MSFU00: MOV SI,WORD PTR [BX+USRMB] ;HEADER MOV WORD PTR [SI+MFBPTR],0 ;UNCHAIN MSFN00: MOV AX,59 ;NEW SUBJECT CALL QMSGNO JC MSFU90 ;LOST CARRIER CALL DQTIOA ;GET NEW SUBJECT MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ MSFU90 ;ABORT COMMAND MOV DI,[BP-20] ;OLD SUBJECT STRING MOV [BP-20],SI ;NEW SUBJECT STRING XCHG SI,DI ;FOR FREBUF MSFU90: CALL FREBUF ;FREE OLD STRING JMP BLDM50 ;SUBFUNCTION PROMPT ;--------------------------------------------------------------------- ;SAVE NEW MESSAGE ;--------------------------------------------------------------------- MSFS00: CMP WORD PTR [BP-6],0 ;ANY LINES IN MSG? JNZ MSFS05 ;OF COURSE THERE ARE JMP MSFA00 ;TREAT AS ABORT MSFS05: MOV SI,[BP-18] ;'TO' STRING MOV DI,[BX+USRMB] ;HEADER ADD DI,MTNAME ;'TO' FIELD MOV CX,MTSTMP-MTNAME ;LENGTH CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE ;MAKE UPPER CASE CALL PADB ;PAD TO LENGTH MOV [BP-18],SI ;PADB CAN ALTER LENGTH PUSH ES PUSH DS POP ES REP MOVSB ;MOVE TO HEADER POP ES MOV SI,[BP-20] ;'RE' STRING MOV DI,[BX+USRMB] ;HEADER ADD DI,MFSUBJ ;'RE' FIELD MOV CX,MFBPTR-MFSUBJ ;LENGTH CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE ;MAKE UPPER CASE CALL PADB ;PAD TO LENGTH MOV [BP-20],SI ;PADB CAN ALTER LENGTH push es push ds pop es REP MOVSB ;MOVE TO HEADER pop es INC DS:MSGCKPT+MLASTMN ;NEW MESSAGE NUMBER ADD DS:MSGCKPT+MILAST,2 ;LAST INDEX POINTER MOV AX,DS:MSGCKPT+MLASTMN ;HIGH MESSAGE NUMBER MOV DI,DS:MSGCKPT+MILAST ;INDEX TO NEW MESSAGE MOV [BP-12],DI ;MUST RETURN TO CALLER MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER MOV WORD PTR [DI+MMNUMB],AX ;PUT IN HEADER PUSH AX CALL ILINEB ;FORMAT BUFFER MOV AX,185 ;STORING MSG CALL MOVMSG POP AX CALL BINASP ;ADD MSG NUMBER CALL WRMSG MOV CX,[BP-6] ;NUMBER OF LINES MOV DX,CX ;ONE BYTE PER LINE MOV DI,[BP-4] ;LINE INDEX MSFS10: MOV SI,WORD PTR [DI] ;LINE ADDRESS ADD DX,WORD PTR [SI-2] ;LINE LENGTH ADD DI,2 ;NEXT LINE POINTER LOOP MSFS10 ;COUNT THEM ALL ADD DX,127 ;ROUND TO RECORD SIZE MOV CL,7 SHR DX,CL ;CONVERT TO BLOCKS INC DX ;COUNT HEADER MOV DI,WORD PTR [BX+USRMB] ;HEADER MOV WORD PTR [DI+MRSIZE],DX ;PUT IN HEADER ;SEEK TO END OF FILE MOV AX,4202H ;SEEK EOF XOR CX,CX ;CLEAR OFFSET MOV DX,CX ;ALSO MSW PUSH BX MOV BX,MSSGH ;FILE HANDLE INT 21H ;DOS REQUEST POP BX JNC MSFS20 ;SEEK OK ERR 2 MSFS20: MOV CX,MSGSIZ ;BLOCK SIZE DIV CX ;GET BLOCK NUMBER MOV WORD PTR [BX+USRMP],AX ;BLOCK POINTER MOV DI,[BP-12] ;INDEX TO LAST MSG PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV [BX+DI],AX ;BLOCK NUMBER POP BX MOV AX,DS:MSGCKPT+MLASTMN ;NEW MESSAGE NUMBER PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV [BX+DI],AX ;UPDATE INDEX POP BX INC DS:MSGCKPT+MIACTM ;UPDATE COUNT INC ADDCNT ;SHOW MSG ADDED PUSH AX ;MESSAGE NUMBER MOV DI,WORD PTR [BX+USRMB] ;HEADER ADDRESS MOV AX,WORD PTR [DI+MFBPTR] ;BACK POINTER PUSH AX ;BACK POINTER MOV CX,[BP-6] ;NUMBER OF LINES XOR DX,DX ;SHOW BUFFER FULL MOV SI,WORD PTR [BX+USRMB] ;START OF BUFFER CALL ATOINX ;ADD NEW MESSAGE TO INDEX MSFS30: MOV SI,[BP-6] ;NUMBER OF LINES SUB SI,CX ;CURRENT LINE SHL SI,1 ;INDEX ADD SI,[BP-4] ;START OF TABLE MOV SI,WORD PTR [SI] ;STRING ADDRESS PUSH CX MOV CX,WORD PTR [SI-2] ;STRING LENGTH MSFS40: OR DX,DX ;ANY ROOM IN BUFFER? JZ MSFS45 ;NO CMP CX,DX ;ROOM IN BUFFER? JBE MSFS50 ;NO PROBLEM SUB CX,DX ;EXCESS PUSH CX MOV CX,DX ;LENGTH TO MOVE push es push ds pop es REP MOVSB ;MOVE STRING pop es POP CX ;REMAINING LENGTH MSFS45: CALL MSFSWB ;WRITE BUFFER MSFS50: SUB DX,CX ;REMAINING SPACE IN BUFFER push es push ds pop es REP MOVSB ;MOVE REST OF STRING pop es OR DX,DX ;BUFFER EMPTY? JNZ MSFS52 ;NO PROBLEM CALL MSFSWB ;WRITE BUFFER MSFS52: MOV AL,227 ;DELIMITER MOV [DI],AL ;MOVE TO BUFFER INC DI ;NEXT BUFFER POS DEC DX ;REMAINING SPACE POP CX LOOP MSFS30 ;GET NEXT LINE MOV CX,DX ;REMAINING SPACE JCXZ MSFS55 ;NO SPACE LEFT MOV AL,' ' push es push ds pop es REP STOSB ;BLANK REST OF RECORD pop es MSFS55: CALL MSFSWB ;WRITE BUFFER ;SET FORWARD POINTER IN PREVIOUS RECORD POP AX ;BACK POINTER IN NEW RECORD POP DX ;MESSAGE # OR AX,AX ;CHAIN? JZ MSFS70 ;NO MSFS60: CALL FINDMN ;FIND PREVIOUS RECORD JC MSFS65 ;REPLACE INVALID CHAIN MOV WORD PTR [BX+USRMP],AX ;POINT TO RECORD CALL READM ;READ IT MOV AX,WORD PTR [SI+MFPTR1] ;FORWARD POINTER CMP AX,WORD PTR [SI+MMNUMB] ;VALID? JA MSFS60 ;YES - GO FOLLOW CHAIN MSFS65: MOV WORD PTR [SI+MFPTR1],DX ;NEW FORWARD POINTER CALL WRITM ;UPDATE RECORD MSFS70: CALL CKPTM ;CHECKPOINT RECORD MOV DI,WORD PTR [BX+USRST] ;USER RECORD INC WORD PTR [DI+UEMSGE] ;MSGS ENTERED MOV AX,DS:MSGCKPT+MLASTMN ;LAST MSG # DEC AX ;PREVIOUS NUMBER CMP AX,WORD PTR [DI+UEHMSG] ;READ ALL BUT THIS? JNZ BLDM80 ;NO INC WORD PTR [DI+UEHMSG] ;SHOW AS HAVING READ BLDM80: CLC ;SHOW GOOD RETURN BLDM90: PUSHF ;SAVE CARRY STATUS MOV SI,[BP-18] ;'TO' STRING CALL FREBUF ;FREE IT MOV SI,[BP-20] ;'RE' STRING CALL FREBUF ;FREE IT MOV CX,[BP-6] ;NUMBER OF LINES MOV DI,[BP-4] ;LINE INDEX JCXZ BLDM94 ;NO LINES TO FREE BLDM92: MOV SI,WORD PTR [DI] ;LINE ADDRESS CALL FREBUF ;FREE IT ADD DI,2 ;NEXT LINE LOOP BLDM92 ;GET NEXT LINE ADDRESS BLDM94: MOV SI,[BP-4] ;LINE INDEX CALL FREBUF ;FREE IT MOV DI,[BP-12] ;INDEX TO NEW MESSAGE POPF ;RESTORE CARRY STATUS MOV SP,BP ;FREE LOCAL VARIABLES POP BP ;RESTORE CALLER'S FRAME RET MSFSWB: CALL WRITM ;WRITE MSG BLOCK INC WORD PTR [BX+USRMP] ;POINT TO NEXT BLOCK MOV DI,WORD PTR [BX+USRMB] ;START OF BUFFER MOV DX,MSGSIZ ;SHOW BUFFER EMPTY RET ;TCLOSE FILE FEOF: PUSH BX MOV BX,AX ;FILE HANDLE MOV AH,45H ;DUP REQUEST INT 21H ;DOS FUNCTION CALL POP BX JNC FEOF10 ;NO PROBLEM ERR 0AH ;FEOF FAILURE FEOF10: CALL YIELD ;LET OTHER TASKS RUN PUSH BX MOV BX,AX ;NEW HANDLE MOV AH,3EH ;CLOSE INT 21H ;DOS REQUEST POP BX JNC FEOF20 ;NO PROBLEM ERR 0AH ;FEOF FAILURE FEOF20: CALL YIELD ;BE A GOOD CITIZEN RET ;LIST ONE LINE OF MESSAGE LISTLN: PUSH AX PUSH CX PUSH SI PUSH DI CALL ILINEB ;GET BUFFER MOV AX,WORD PTR [BP-10] ;LINE NUMBER OR AX,AX ;POSITIVE? JNS LIST20 ;NO PROBLEM CMP WORD PTR [BP-10],-1 ;SUBJECT? JNZ LIST10 ;NO MOV DI,[BP-20] ;POINT TO SUBJECT MOV [BP-2],DI ;CURRENT LINE MOV AX,159 ;'RE' JMP SHORT LIST15 LIST10: MOV DI,[BP-18] ;TO NAME MOV [BP-2],DI ;CURRENT LINE MOV AX,168 ;'TO' LIST15: CALL MOVMSG ;MOVE LINE NAME TO BUFFER JMP SHORT LIST30 ;GO PROCESS LIST20: MOV CX,2 CALL BINASC ;PUT LINE NUMBER IN BUFFER MOV AL,':' ;DELIMITER CALL APPBYT ;ADD TO BUFFER INC WORD PTR [SI-2] ;LEAVE ONE SPACE MOV DI,[BP-10] ;LINE NUMBER DEC DI ;0 BASE SHL DI,1 ;TABLE WIDTH ADD DI,[BP-4] ;LINE INDEX MOV DI,WORD PTR [DI] ;LINE ADDRESS MOV [BP-2],DI ;CURRENT LINE LIST30: MOV DI,[BP-2] ;CURRENT LINE CALL MOVSTR ;MOVE TO BUFFER CALL WRMSG POP DI POP SI POP CX POP AX RET ;QUERY FOR LINE NUMBER QLINE: MOV AX,175 ;LINE # CALL MOVMSG MOV DI,WORD PTR [BX+USRIN] ;1ST INPUT BUFFER OR DI,DI ;EXIST? JZ QLIN10 ;NO CMP DI,[BP-16] ;PRIOR USERS BUFFER? JNZ QLIN10 ;NO PROBLEM CALL QVAL05 ;FORCE USER RESPONSE JMP QLIN15 ;CHECK RESPONSE QLIN10: CALL QVALUE ;GET LINE NUMBER QLIN15: JC QLIN20 ;NOT VALID CMP AX,-2 ;HEADER? JNB QLIN18 ;YES - OK FOR EDIT CMP AX,0 ;VALID? JZ QLIN20 ;NO CMP AX,[BP-6] ;MAX LINE NUMBER JA QLIN20 ;TOO HIGH QLIN18: MOV [BP-10],AX ;SET LINE NUMBER CLC ;GOOD RETURN RET QLIN20: CALL ILINEB ;FORMAT BUFFER MOV AX,179 ;NO SUCH LINE CALL MOVMSG MOV DI,WORD PTR [BX+USR1N] ;1ST NAME CALL MOVSTR MOV SI,WORD PTR [BX+USRLB] ;START OF TEXT CALL WRMSG STC RET QVALUE: PUSH SI CALL DQCMD ;AVAILABLE INPUT? JNC QVAL10 ;YES - SKIP MSG POP SI QVAL05: CALL QUERY ;GET RESPONSE JC QVAL30 ;LOST CARRIER JMP QVALUE ;GET RESULTS QVAL10: POP CX ;DISCARD BUFFER ADDRESS MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ QVAL30 ;NULL RESPONSE CALL ASCBIN ;GET VALUE RET QVAL30: STC ;SHOW NULL RESPONSE RET QVALNO: CALL DQCMD ;AVAILABLE INPUT? JNC QVNO10 ;YES - SKIP MSG QVNO05: CALL QMSGNO ;GET RESPONSE JC QVNO30 ;LOST CARRIER JMP QVALNO ;GET RESULTS QVNO10: MOV CX,WORD PTR [SI-2] ;LENGTH JCXZ QVNO30 ;NULL RESPONSE CALL ASCBIN ;GET VALUE RET QVNO30: STC ;SHOW NULL RESPONSE RET ;QUERY FOR YES RESPONSE TO MSG ;RETURN Z IF YES OR C IF NULL RESPONSE QYESNO: PUSH AX PUSH CX PUSH SI CALL QMSGNO JMP SHORT QYES00 QYES: PUSH AX PUSH CX PUSH SI CALL QUERY QYES00: JC QYESX ;LOST CARRIER CALL DQCMD MOV CX,WORD PTR [SI-2] ;LENGTH OF RESPONSE OR CX,CX ;ANYTHING? STC ;ASSUME NULL JZ QYESX ;RIGHT ON! CALL LALIGN ;STRIP LEADING BLANKS CALL XLATE CMP BYTE PTR [SI],'Y' ;YES? CLC ;SHOW ACTUAL INPUT QYESX: POP SI POP CX POP AX RET ;INPUT ONE LINE OF MESSAGE INLIN: MOV DI,[BP-2] ;CURRENT LINE ADDRESS OR DI,DI ;EXIST? JZ INLI10 ;NO MOV CX,WORD PTR [DI-2] ;LENGTH ADD DI,CX ;POSITION JMP INLI20 ;GO READ INLI10: MOV AX,[BP-8] ;LINE LENGTH CALL GETBUF ;GET BUFFER MOV [BP-2],SI ;SAVE AS CURRENT LINE MOV DI,SI ;CURRENT POSITION XOR CX,CX ;CLEAR COUNT MOV [BP-22],CX ;NO ANSI STRING INLI20: CALL CONR ;NEXT CHAR JC INLI40 ;LOST CARRIER CMP AL,10 ;LF JZ INLI20 ;IGNORE CMP AL,8 ;BACK SPACE JZ INLI22 ;YES CMP AL,1DH ;PC-TALK LEFT ARROW JZ INLI22 ;TREAT AS BACK-SPACE CMP AL,127 ;BACK SPACE JNZ INLI24 ;NO INLI22: OR CX,CX ;ALREADY AT START? JZ INLI20 ;YES - IGNORE DEC CX ;BACK UP COUNT DEC DI ;BACK UP BUFFER MOV AL,8 ;DON'T ECHO DELETE CHAR CALL CONW ;ECHO BACKSPACE MOV AL,' ' CALL CONW ;DELETE PREVIOUS CHAR MOV AL,8 CALL CONW ;COMPLETE BACKSPACE SEQ. JMP INLI20 ;DON'T STORE IN BUFFER INLI24: CMP AL,9 ;TAB? JNZ INLI30 ;NO PROBLEM MOV AL,' ' ;TREAT AS BLANK INLI30: CALL CONW ;ECHO CHAR CMP AL,27 ;ESC CHAR? JNZ INLI35 ;NO OR WORD PTR [BP-22],1 ;SHOW ANSI INLI35: CMP AL,13 ;END OF LINE? JNZ INLI50 ;NO CALL WRLF ;LINE FEED IF NEEDED MOV WORD PTR [BX+CBLINO],0 ;CLEAR LINE COUNTER OR CX,CX ;EMPTY? JNZ INLI45 ;NOT EMPTY INLI40: STC ;SHOW EMPTY LINE JMP INLI48 ;RETURN INLI45: CLC ;SHOW NOT EMPTY INLI48: MOV SI,[BP-2] ;START OF LINE MOV WORD PTR [SI-2],CX ;LENGTH RET INLI50: MOV [DI],AL ;PUT IN BUFFER INC DI ;NEXT BUFFER POS INC CX ;COUNT CHAR ; TEST WORD PTR [BP-22],1 ;SUPPRESS LENGTH CHECKING? ; JNZ INLI55 ;YES MOV DX,[BP-8] ;MARGIN SUB DX,3 CMP CX,DX ;NEAR MARGIN? JLE INLI52 ;NO CMP AL,' ' ;END OF WORD? JNZ INLI52 ;NO MOV AL,13 ;FORCE END OF LINE JMP INLI30 ;GO HANDLE INLI52: CMP CX,[BP-8] ;LINE FULL? JB INLI20 ;NO - GET NEXT CHAR XOR DX,DX ;CLEAR BACKSPACE COUNT INLI54: DEC DI ;BACK UP IN BUFFER CMP BYTE PTR [DI],' ' ;SPACE? JZ INLI60 ;YES INC DX ;COUNT CHARS SCANNED LOOP INLI54 ;TRY AGAIN MOV CX,DX ;RESTORE COUNT MOV AL,13 ;FORCE END OF LINE JMP INLI30 ;GO HANDLE INLI55: PUSH CX ;TRUE COUNT ADD CX,8 ;INCLUDE HEADER CMP CX,WORD PTR [SI-6] ;BUFFER SIZE POP CX JNB INLI57 ;OUT OF SPACE JMP INLI20 ;GET NEXT CHAR INLI57: PUSH CX SHL CX,1 ;DOUBLE SIZE CALL PADB ;EXPAND BUFFER MOV [BP-2],SI ;NEW LINE ADDRESS POP CX ;CURRENT COUNT JMP INLI20 ;GET NEXT CHAR INLI60: MOV AX,[BP-8] ;LINE SIZE CALL GETBUF ;GET NEW BUFFER MOV WORD PTR [SI-2],DX ;SIZE DEC CX INC DI ;REMOVE SPACE PUSH SI ;SAVE START OF STRING PUSH CX ;SAVE OLD COUNT MOV CX,DX ;COUNT TO MOVE XCHG SI,DI ;FOR MOVSB push es push ds pop es REP MOVSB ;MOVE STRING pop es MOV CX,DX ;# OF BACKSPACES INLI65: MOV AL,8 ;BACKSPACE CALL CONW MOV AL,' ' CALL CONW ;CLEAR PREVIOUS CHARACTER MOV AL,8 CALL CONW ;COMPLETE BACKSPACE SEQ. LOOP INLI65 POP CX POP SI MOV [BP-14],SI ;SAVE PARTIAL LINE MOV AL,13 ;END OF LINE JMP INLI30 ;GO HANDLE ;DRAW MARGIN RULER DRWMGN: MOV AX,[BP-8] ;MARGIN ADD AX,4 ;ALLOW FOR MSG #S CALL GETBUF ;GET BUFFER CALL BLANKF ;INIT TO BLANKS LEA DI,[SI+5] ;LEAVE 5 SPACES MOV BYTE PTR [DI],'[' INC DI MOV AL,'-' MOV CX,[BP-8] ;MARGIN SUB CX,2 ;ALLOW FOR [] push es push ds pop es REP STOSB pop es MOV BYTE PTR [DI],']' INC DI ;INCLUDE ']' SUB DI,SI ;LENGTH MOV WORD PTR [SI-2],DI ;SET LENGTH CALL WRMSG CALL FREBUF ;RELEASE BUFFER RET ;--------------------------------------------------------------------- ;KILL A MESSAGE ;ENTERED WITH MESSAGE RANGE IN AX:DX ; BP+10 FLAGS ; 80H DELETE RANGE ; 40H DELETE PRIVATE MSGS ; 20H DELETE UNREAD MSGS ; 10H DELETE FLASH MSGS ; BP+8 SECTION MASK ; BP+6 UPPER BOUND ; BP+4 LOWER BOUND ; BP+2 RETURN ADDRESS ; BP-2 FORWARD POINTER ; BP-4 BACKWARD POINTER ;--------------------------------------------------------------------- KILL00: FRAME 2 MOV AX,[BP+4] ;STARTING MESSAGE # KILL02: CALL FINDMN ;FIND MESSAGE BLOCK JNC KILL10 ;FOUND TEST WORD PTR [BP+10],80H ;RANGE? JZ KILL08 ;NO - INVALID KILL04: INC WORD PTR [BP+4] ;NEXT MESSAGE TEST WORD PTR [BP+10],80H ;RANGE? JNZ KILL06 ;YES JMP KILL90 ;EXIT KILL06: MOV AX,[BP+4] ;NEW MESSAGE NUMBER CMP AX,[BP+6] ;END OF RANGE? JBE KILL02 ;GO KILL IT JMP KILL90 ;EXIT KILL08: CALL NOMSGN ;NO SUCH MSG JMP KILL90 ;EXIT KILL10: MOV WORD PTR [BX+USRMP],AX ;BLOCK NUMBER CALL READM ;READ HEADER MOV AX,WORD PTR [SI+MFBPTR] ;BACK POINTER MOV [BP-4],AX MOV AX,WORD PTR [SI+MFPTR1] ;FORWARD POINTER MOV [BP-2],AX TEST BYTE PTR [SI+MRSTAT],8 ;MESSAGE READ? JNZ KILL11 ;YES - CAN DELETE TEST WORD PTR [BP+10],20H ;DELETE UNREAD MAIL? JZ KILL13 ;NO - DON'T DELETE KILL11: MOV AX,[SI+MFSECT] ;SECTION NUMBER OR AX,AX ;PRIVATE MSG? JNZ KIL11A ;NO TEST WORD PTR [BP+10],40H ;DELETE PRIVATE MSGS? JNZ KIL11B ;YES KIL11A: AND AX,[BP+8] ;DELETE THIS SECTION? JZ KILL13 ;NO KIL11B: CALL TSIGOP ;PRIVILEGED USER? JNZ KILL15 ;YES TEST WORD PTR DS:MSGCKPT+MSOPTS,2000H ;SYSOP KILL PUBLIC? JNZ KILL13 ;YES - DON'T DELETE KILL12: CALL KOWN ;OWNER? JNC KILL15 ;YES KILL13: TEST WORD PTR [BP+10],80H ;RANGE CMD? JNZ KILL14 ;YES - NO MESSAGE MOV AX,56 ;ONLY OWNERS CALL WMSGNO KILL14: JMP KILL04 ;CHECK RANGE KILL15: TEST BYTE PTR [SI+MPFLAG],1 ;FLASH MSG? JZ KILL19 ;NO TEST WORD PTR [BP+10],10H ;DELETE FLASH MSGS? JZ KILL13 ;NO MOV AX,[BP+4] ;MESSAGE NUMBER CMP AX,DS:MSGCKPT+MFLASH ;1ST FLASH? JNZ KILL17 ;NO MOV AX,[BP-2] ;FORWARD POINTER MOV DS:MSGCKPT+MFLASH,AX ;NEW 1ST FLASH KILL17: MOV AX,[BP+4] ;MESSAGE NUMBER CMP AX,DS:MSGCKPT+MLASTF ;LAST FLASH MSG? JNZ KILL19 ;NO MOV AX,[BP-4] ;BACKWARD POINTER MOV DS:MSGCKPT+MLASTF,AX ;NEW LAST FLASH KILL19: MOV BYTE PTR [SI+MDFLAG],0E2H ;MARK MSG KILLED CALL WRITM ;RE-WRITE MESSAGE CALL DTOINX ;DELETE FROM TO INDEX MOV AX,[BP+4] ;MESSAGE NUMBER CALL FINDMN ;FIND IN INDEX PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV WORD PTR [BX+DI],0 ;DELETE FROM INDEX POP BX CMP DI,DS:MSGCKPT+MILAST ;LAST RECORD? JNZ KILL23 ;NO KILL20: OR DI,DI ;EMPTY? JZ KILL21 ;YES SUB DI,2 ;POINT TO PREVIOUS MOV DS:MSGCKPT+MILAST,DI ;UPDATE PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV AX,[BX+DI] ;NEW LAST MSG # POP BX OR DI,DI ;EMPTY ARRAY? JNZ KILL22 ;NO PROBLEM KILL21: MOV DS:MSGCKPT+MIFRST,DI ;SHOW EMPTY JMP SHORT KILL25 KILL22: OR AX,AX ;EXIST? JZ KILL20 ;NO KILL23: CMP DI,DS:MSGCKPT+MIFRST ;FIRST RECORD? JNZ KILL25 ;NO KILL24: ADD DI,2 ;NEXT MOV DS:MSGCKPT+MIFRST,DI ;SET NEW INDEX OR AX,AX ;MSG EXIST? JZ KILL24 ;NO - SKIP IT KILL25: MOV DI,WORD PTR [BX+USRST] ;USER RECORD INC WORD PTR [DI+UEMSGK] ;COUNT KILL DEC DS:MSGCKPT+MIACTM ;REDUCE ACTIVE COUNT INC KILLCNT ;SHOW RECORDS DELETED MOV AX,[BP-2] ;FORWARD POINTER CALL FINDMN ;LOCATE BLOCK JC KILL30 ;DOES NOT EXIST MOV WORD PTR [BX+USRMP],AX ;NEXT IN CHAIN CALL READM ;READ IT MOV AX,WORD PTR [SI+MFBPTR] ;BACK POINTER CMP AX,[BP+4] ;MESSAGE NUMBER JNZ KILL30 ;NO CHAIN TO CLOSE MOV AX,[BP-4] ;BACK POINTER MOV WORD PTR [SI+MFBPTR],AX ;CLOSE BACK CHAIN CALL WRITM ;UPDATE RECORD KILL30: MOV AX,[BP-4] ;BACK POINTER KILL32: MOV [BP-4],AX ;NEW BACK POINTER CALL FINDMN ;LOCATE IT JC KILL40 ;DOES NOT EXIST MOV WORD PTR [BX+USRMP],AX ;PREVIOUS IN CHAIN CALL READM ;READ IT MOV AX,WORD PTR [SI+MFPTR1] ;FORWARD POINTER CMP AX,[BP+4] ;POINT TO US? JZ KILL35 ;YES - ADJUST CHAIN CMP AX,[BP-4] ;PREVIOUS POINTER JA KILL32 ;TRY NEXT MESSAGE JMP SHORT KILL40 ;INVALID CHAIN POINTER KILL35: MOV AX,[BP-2] ;FORWARD PTR MOV WORD PTR [SI+MFPTR1],AX ;CLOSE CHAIN CALL WRITM ;UPDATE RECORD KILL40: CALL ILINEB ;FORMAT BUFFER MOV AX,155 ;MSG # CALL MOVMSG MOV AX,[BP+4] ;MSG # CALL BINASP ;PUT IN STRING INC WORD PTR [SI-2] ;LEAVE ONE SPACE MOV AX,183 ;KILLED CALL MOVMSG CALL WRMSG JC KILL90 ;NO MORE JMP KILL04 ;CHECK RANGE KILL90: EXITF 4 ;-------------------------------------------------------- ;BUILD MESSAGE INDEX ARRAYS ;-------------------------------------------------------- BUILDM: MOV WORD PTR [BX+USRMP],0 ;START OF FILE MOV SI,OFFSET DS:MSGCKPT ;CHECKPOINTED VARIABLES MOV WORD PTR [BX+USRMB],SI ;POINT TO BUFFER CALL READM ;READ 1ST RECORD MOV WORD PTR [BX+USRMB],0 ;SHOW NO BUFFER ;ALLOCATE INDEX ARRAYS CMP DS:MSGCKPT+MVERS,2 ;NEW FORMAT? JNB BUILD0 ;YES MOV DS:MSGCKPT+MDIMAX,MSGMAX ;SET DEFAULT VALUE BUILD0: MOV AX,DS:MSGCKPT+MDIMAX ;MAXIMUM MESSAGES SHL AX,1 ;2 BYTES PER ENTRY CALL GETSBF ;GET BUFFER MOV MSGINX1,SI ;NUMBER INDEX CALL GETSBF ;GET BUFFER MOV MSGINX2,SI ;BLOCK INDEX ;LOAD MESSAGE INDICES IF PRESENT CMP DS:MSGCKPT+MVERS,0 ;OLD FORMAT FILE? JZ BUILD1 ;YES JMP LOAD00 ;GO LOAD BUILD1: MOV DS:MSGCKPT+MILAST,-2 ;LAST INDEX POINTER BUIL00: INC WORD PTR [BX+USRMP] ;NEXT MESSAGE BLOCK BUIL01: CALL READM ;READ MESSAGE HEADER JNZ BUIL05 ;END OF FILE MOV CX,WORD PTR [SI+MRSIZE] ;RECORD SIZE MOV AL,BYTE PTR [SI+MDFLAG] ;DELETION STATUS AND AL,83H ;ISOLATE DEFINED BITS CMP AL,82H ;DEAD? JZ BUIL04 ;YES - SKIP RECORD CMP AL,81H ;LIVE? JZ BUIL02 ;YES - PUT IN INDEX CMP DEBUGF,0 ;TESTING? JZ BUIL00 ;NO - SEARCH FOR VALID HEADER ERR 301H ;BAD RECORD IN MSG FILE BUIL02: ADD DS:MSGCKPT+MILAST,2 ;COUNT RECORD MOV DI,DS:MSGCKPT+MILAST CMP DI,MSGMAX*2 ;END OF ARRAY? JNZ BUIL03 ;NO PROBLEM ERR 302H ;TOO MANY MSGS IN FILE BUIL03: MOV AX,WORD PTR [SI+MMNUMB] ;MSG NUMBER PUSH BX MOV BX,MSGINX1 ;NUMBER INDEX MOV [BX+DI],AX ;SAVE MSG NUMBER MOV AX,WORD PTR [BX+USRMP] ;MESSAGE BLOCK NUMBER MOV BX,MSGINX2 ;BLOCK INDEX MOV [BX+DI],AX ;SAVE RECORD NUMBER POP BX BUIL04: ADD WORD PTR [BX+USRMP],CX ;NEXT MSG HEADER JMP BUIL01 ;GO READ NEXT HEADER BUIL05: MOV DI,DS:MSGCKPT+MILAST ;LAST INDEX ENTRY MOV AX,DI ;DS:MSGCKPT+MILAST SAR AX,1 ;DIVIDE BY TWO INC AX ;OFFSET -> COUNT MOV DS:MSGCKPT+MIACTM,AX ;STORE XOR DI,DI ;1ST INDEX ENTRY MOV DS:MSGCKPT+MIFRST,DI RET LOAD00: PUSH CX PUSH DX MOV CX,DS:MSGCKPT+MDIMAX ;MAXIMUM MESSAGES SHL CX,1 ;2 BYTES PER ENTRY MOV DX,MSGINX1 ;NUMBER INDEX PUSH BX MOV BX,MSSGH ;MESSAGE FILE HANDLE MOV AH,3FH ;READ FILE INT 21H ;DOS REQUEST MOV DX,MSGINX2 ;BLOCK INDEX MOV AH,3FH ;READ FILE INT 21H ;DOS REQUEST POP BX CMP AX,CX ;READ OK? POP DX POP CX RET SAVINX: CMP DS:MSGCKPT+MVERS,0 ;OLD FORMAT? JNZ SAVIN0 ;NO PROBLEM RET ;EXIT SAVIN0: PUSH CX PUSH DX PUSH SI MOV SI,OFFSET MSGUSR ;MESSAGE FILE LOCK CALL LOCKWT ;ACQUIRE FILE LOCK MOV WORD PTR [BX+USRMP],1 ;INDEX ARRAY BLOCK CALL SEEKM ;POINT TO RECORD MOV CX,DS:MSGCKPT+MDIMAX ;MAXIMUM ENTRIES SHL CX,1 ;2 BYTES PER ENTRY MOV DX,MSGINX1 ;INDEX STARTING ADDRESS PUSH BX MOV BX,MSSGH ;MESSAGE FILE HANDLE MOV AH,40H ;WRITE TO FILE INT 21H ;DOS REQUEST MOV DX,MSGINX2 ;BLOCK ENTRY MOV AH,40H ;WRITE TO FILE INT 21H ;DOS REQUEST POP BX CALL UNLOCK ;UNLOCK MESSAGE FILE POP SI POP DX POP CX CALL CKPTM ;NOW CHECKPOINT POINTERS RET READM: PUSH CX PUSH DX CMP WORD PTR [BX+USRMB],0 ;BUFFER AVAILABLE? JNZ READ10 ;NO PROBLEM MOV AX,MSGSIZ ;BUFFER SIZE CALL GETBUF ;GET BUFFER MOV WORD PTR [BX+USRMB],SI ;SAVE BUFFER ADDRESS READ10: MOV SI,OFFSET MSGUSR ;MSG FILE LOCK WORD CALL LOCKWT ;ACQUIRE LOCK CALL SEEKM ;POINT TO RECORD MOV CX,MSGSIZ ;BYTES TO READ MOV DX,WORD PTR [BX+USRMB] ;BUFFER ADDRESS PUSH BX MOV BX,MSSGH ;FILE HANDLE MOV AH,3FH ;READ FILE INT 21H ;DOS CALL POP BX CALL UNLOCK ;RELEASE FILE LOCK CALL YIELD CMP AX,CX ;TEST END OF FILE POP DX POP CX MOV SI,WORD PTR [BX+USRMB] ;RETURN BUFFER POINTER RET CKPTM: CMP MSSGH,0 ;FILE AVAILABLE? JZ CKPTMX ;NO - SKIP CHECKPOINT MOV SI,WORD PTR [BX+USRMB] ;MESSAGE FILE BUFFER CALL FREBUF ;FREE IT MOV WORD PTR [BX+USRMB],OFFSET DS:MSGCKPT MOV WORD PTR [BX+USRMP],0 ;FIRST RECORD CALL WRITM ;WRITE RECORD MOV WORD PTR [BX+USRMB],0 ;SHOW NO BUFFER MOV AX,MSSGH ;MESSAGE FILE HANDLE CALL FEOF ;FORCE END OF FILE CKPTMX: RET WRITM: PUSH SI MOV SI,OFFSET MSGUSR ;MSG FILE LOCK WORD CALL LOCKWT ;ACQUIRE FILE LOCK CALL SEEKM ;POINT TO RECORD PUSH CX PUSH DX MOV CX,MSGSIZ ;BYTES TO WRITE MOV DX,WORD PTR [BX+USRMB] ;BUFFER ADDRESS PUSH BX MOV BX,MSSGH ;FILE HANDLE MOV AH,40H ;WRITE TO FILE INT 21H ;DOS CALL POP BX CALL UNLOCK ;FREE FILE LOCK CALL YIELD ;TAKE A BREAK CMP AX,CX ;ANY PROBLEMS? JZ WRITMX ;NO CMP AX,0 ;OUT OF SPACE? JZ WRITMX ;YES - DON'T CRASH ERR 2 WRITMX: POP DX POP CX POP SI RET SEEKM: PUSH CX MOV DX,MSGSIZ ;MESSAGE SIZE MOV AX,WORD PTR [BX+USRMP] ;BLOCK POINTER MUL DX ;BYTE OFFSET MOV CX,DX ;MSW MOV DX,AX ;LSW PUSH BX MOV BX,MSSGH ;FILE HANDLE MOV AX,4200H ;SEEK FILE INT 21H ;DOS CALL POP BX POP CX RET ;SET BIT IN MSG READ ARRAY SETRDB: PUSH AX PUSH DI CALL LOCRDB ;FIND BIT TO SET JZ SETRDX ;ARRAY DOES NOT EXIST OR BYTE PTR [DI],AL ;SET BIT ON SETRDX: POP DI POP AX RET ;TEST BIT IN MSG READ ARRAY TSTRDB: PUSH AX PUSH DI CALL LOCRDB ;FIND BIT TO TEST JZ SETRDX ;ARRAY DOES NOT EXIST TEST BYTE PTR [DI],AL ;CHECK IT JMP SETRDX ;EXIT ;CLEAR BIT IN MSG READ ARRAY CLRRDB: PUSH AX PUSH DI CALL LOCRDB ;FIND BIT TO CLEAR JZ SETRDX ;ARRAY DOES NOT EXIST XOR AL,0FFH ;FLIP BITS AND BYTE PTR [DI],AL ;TURN BIT OFF JMP SETRDX ;EXIT ;LOCATE BIT IN MSG READ ARRAY LOCRDB: CMP WORD PTR [BP-10],0 ;ARRAY EXIST? JZ LOCRDX ;NO PUSH CX PUSH DX SHR DI,1 ;CORRECT FOR TABLE WIDTH MOV AX,DI ;FOR DIVIDE XOR DX,DX ;MSW DIVIDEND MOV CX,8 ;DIVISOR DIV CX MOV CL,DL ;REMAINDER MOV DI,AX ;QUOTIENT INTO INDEX REGISTER MOV AL,80H ;1ST BIT IN BYTE SHR AL,CL ;MOVE TO PROPER PLACE POP DX POP CX ADD DI,[BP-10] ;BIT ARRAY OFFSET LOCRDX: RET ;CHECK OWNERSHIP ROWN: CALL INGRP ;CHECK GROUP OWNERSHIP JNC ROWNX ;OK KOWN: CALL INFROM ;AUTHOR? JNC ROWNX ;YES CALL INTOST ;RECIPIENT? ROWNX: RET ;CHECK IF GROUPID = ADDRESSEE INGRP: PUSH CX PUSH SI PUSH DI MOV DI,WORD PTR [BX+USRST] ;LOGON TABLE ENTRY ADD DI,UEGID ;GROUP ID MOV SI,WORD PTR [BX+USRMB] ;MESSAGE HEADER ADD SI,MTNAME ;ADDRESSEE MOV CX,8 ;GID LENGTH push es push ds pop es REPZ CMPSB ;CHECK MATCH pop es JZ INGRPX ;MATCH OK STC INGRPX: POP DI POP SI POP CX RET ;CHECK IF NAME = FROM INFROM: PUSH SI PUSH DI PUSH CX MOV SI,WORD PTR [BX+USR3N] ;USER NAME MOV CX,31 ;LENGTH INCLUDING BLANKS MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER ADD DI,MFNAME ;'FROM' NAME push es push ds pop es REPZ CMPSB ;CHECK MATCH pop es JZ INFROX ;MATCH OK STC INFROX: POP CX POP DI POP SI RET ;CHECK IF NAME IN TO STRING INTOST: PUSH SI PUSH DI PUSH AX PUSH CX PUSH DX MOV SI,WORD PTR [BX+USR3N] ;USER NAME ;SEE IF SPECIAL TAG FOR THIS NAME MOV AL,'(' ;NOT VALID IN NAME MOV DI,SI XOR DX,DX ;CLEAR LENGTH MOV CX,WORD PTR [SI-2] ;SOURCE DATA LENGTH INTO10: CMP BYTE PTR [DI],AL ;FIND ONE? JZ INTO20 ;YES - DONE INC DI INC DX LOOP INTO10 ;CHECK NEXT INTO20: MOV CX,DX ;LENGTH FOR INSTRG MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER ADD DI,MTNAME ;'TO' NAME MOV AX,23 ;LENGTH OF 'TO' STRING CALL INSTRG ;IN STRING? POP DX POP CX POP AX POP DI POP SI RET ;CHECK IF MSG IS TO 'ALL' CKALL: PUSH SI PUSH DI PUSH CX PUSH AX MOV SI,WORD PTR [BX+USRMB] ;MESSAGE BUFFER MOV DI,WORD PTR [BX+USRST] ;USER RECORD TEST WORD PTR [DI+UEOPTS],32 ;SEE 'ALL' MSGS? JNZ CKALL8 ;NO MOV AX,WORD PTR [SI+MMNUMB] ;MESSAGE NUMBER CMP AX,WORD PTR [DI+UEHMSG] ;NEW MSG? JBE CKALL8 ;NO ADD SI,MTNAME ;TO NAME MOV AX,174 ;ALL MSG CALL GETMSG ;GET IN BUFFER CALL CMPSTR ;COMPARE STRINGS PUSHF MOV SI,DI CALL FREBUF ;FREE STRING POPF JNZ CKALL8 ;NO MATCH CLC ;SHOW MATCH FOUND CKALLX: POP AX POP CX POP DI POP SI RET CKALL8: STC ;SHOW NO MATCH JMP CKALLX ;EXIT ;--------------------------------------------------------- ;CHECK IF STRING [SI] IN STRING [DI] ; AX = LENGTH OF TARGET STRING ; CX = LENGTH OF SOURCE STRING ; SI = START OF SOURCE STRING ; DI = START OF TARGET STRING ; RETURNS AX = OFFSET OF SOURCE IN TARGET IF CARRY = 0 ; LOCAL STORAGE ; [BP-2] ORIGINAL TARGET STRING ; [BP-4] CURRENT TARGET LOCATION ; [BP-6] LENGTH OF SOURCE STRING ; [BP-8] ADDRESS OF SOURCE STRING ;-------------------------------------------------------- INSTRG: PUSH BP ;SAVE CALLER'S FRAME MOV BP,SP ;SET LOCAL FRAME SUB SP,8 ;CREATE LOCAL STORAGE MOV [BP-2],DI ;START OF TARGET STRING MOV [BP-6],CX ;SOURCE LENGTH MOV [BP-8],SI ;SOURCE ADDRESS INSTR1: CMP AX,CX ;ENOUGH LEFT FOR MATCH? JB INSTR9 ;NO MOV [BP-4],DI ;CURRENT TARGET POSITION push es push ds pop es REPZ CMPSB ;CHECK MATCH pop es JNZ INSTR2 ;NO MATCH MOV AX,[BP-4] ;MATCHED STRING SUB AX,[BP-2] ;ORIGINAL STRING CLC ;SHOW GOOD MATCH JMP INSTRX ;EXIT INSTR2: MOV CX,[BP-6] ;RESTORE LENGTH MOV SI,[BP-8] ;RESTORE SOURCE STRING MOV DI,[BP-4] ;TARGET POSITION INC DI ;NEXT CHAR DEC AX ;TARGET LENGTH JMP INSTR1 ;TRY AGAIN INSTR9: STC ;SHOW NO MATCH INSTRX: MOV SI,[BP-8] ;RESTORE SOURCE ADDRESS MOV DI,[BP-2] ;RESTORE TARGET ADDRESS MOV CX,[BP-6] ;RESTORE SOURCE LENGTH MOV SP,BP ;DELETE LOCAL FRAME POP BP ;RESTORE CALLER'S FRAME RET EXIST: PUSH AX PUSH DI CALL FINDMN ;SEARCH FOR NUMBER POP DI POP AX RET FINDMN: OR AX,AX ;ANY NUMBER SUPPLIED? JZ FINDM1 ;NO MOV DI,MSGINX1 ;POINT TO MSG # INDEX MOV CX,DS:MSGCKPT+MILAST ;LAST ARRAY ENTRY ADD CX,2 ;POINT PAST END JZ FINDM1 ;LIST IS EMPTY SHR CX,1 ;ENTRY COUNT PUSH ES PUSH DS POP ES REPNZ SCASW ;LOOK FOR MATCH POP ES JNZ FINDM1 ;NO MATCH SUB DI,2 ;MATCHING ENTRY SUB DI,MSGINX1 ;OFFSET IN TABLE PUSH BX MOV BX,MSGINX2 ;BLOCK INDEX MOV AX,[BX+DI] ;GET MSG BLOCK NUMBER POP BX CLC ;SHOW FOUND MATCH RET FINDM1: STC ;SHOW NO MATCH RET ;DETERMINE IF USER HAS MORE THAN ONE AUTHORIZED MESSAGE SECTION ;RETURNS ONLY VALID SECTION NUMBER IF CARRY NOT SET VALSEC: PUSH DI PUSH CX PUSH DX MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+UESECT] ;SECTION FLAGS MOV CX,16 ;NUMBER OF BITS XOR DX,DX ;COUNTER VALS10: RCR AX,1 ;SHIFT OUT ONE BIT JNC VALS20 ;NO BIT FOUND INC DX ;COUNT BIT VALS20: LOOP VALS10 ;NEXT BIT MOV AX,WORD PTR [DI+UESECT] ;RESTORE SECTION FLAGS CMP DX,1 ;EXACTLY ONE SECTION? JZ VALS30 ;YES - EXIT STC ;SHOW MULTIPLE SECTIONS VALS30: POP DX POP CX POP DI RET MSGSYST ENDP ;CONVERT SECTION BIT IN AX TO BIT NUMBER NUMSEC: PUSH CX MOV CX,16 ;MAX BITS CLC NUMS10: RCR AX,1 ;SHIFT OUT ONE BIT JC NUMS20 ;FOUND BIT LOOP NUMS10 ;CHECK NEXT BIT JMP SHORT NUMS30 ;RETURN ZERO NUMS20: MOV AX,17 SUB AX,CX ;BIT NUMBER NUMS30: POP CX RET ;VALIDATE MESSAGE 'TO' NAME VALNAM: PUSH CX PUSH DX PUSH SI MOV SI,DI ;WORK POINTER CALL STRIP ;KILL TRAILING BLANKS MOV CX,WORD PTR [SI-2] ;LENGTH MOV DX,1 ;WORD COUNT VALN10: CMP BYTE PTR [SI],' ' ;DELIMITER? JNZ VALN20 ;NO INC DX ;COUNT WORD VALN20: INC SI ;NEXT CHAR LOOP VALN10 ;KEEP IT MOVING CMP DX,1 ;ONLY ONE WORD? JZ VALN90 ;YES - ALLOW IT MOV SI,DI ;RESTORE POINTER MOV CX,UELNK-UENAM ;LENGTH OF LOGIN NAME CALL PADB ;PAD WITH BLANKS MOV DI,SI ;PADB CAN SWAP STRINGS CALL STRIP ;RESET COUNT CALL RDUSER ;CHECK FOR USER NAME JC VALN90 ;NOT FOUND CALL FREUSR ;RELEASE USER RECORD CLC ;NAME FOUND VALN90: POP SI POP DX POP CX RET CSEG ENDS END