This commit is contained in:
mysticbbs 2013-03-04 10:53:06 -05:00
parent 4ce4e25802
commit 8c335f488e
14 changed files with 1078 additions and 85 deletions

View File

@ -287,7 +287,7 @@ Begin
Box.Open (5, 5, 76, 21);
VerticalLine (26, 7, 19);
VerticalLine (58, 7, 14);
VerticalLine (58, 7, 15);
Form.AddBol ('L', ' List Compression', 8, 7, 28, 7, 18, 3, @Config.FCompress, Topic + '');
Form.AddTog ('I', ' List Columns', 12, 8, 28, 8, 14, 1, 1, 2, '1 2', @Config.FColumns, Topic + '');
@ -308,9 +308,10 @@ Begin
Form.AddStr ('N', ' DL Unvalidated', 42, 9, 60, 9, 16, 15, mysMaxAcsSize, @Config.AcsDLUnvalid, Topic + 'ACS to download unvalidated files');
Form.AddStr ('F', ' See Failed', 46, 10, 60, 10, 12, 15, mysMaxAcsSize, @Config.AcsSeeFailed, Topic + 'ACS to see failed files');
Form.AddStr (#0, ' DL Failed', 47, 11, 60, 11, 11, 15, mysMaxAcsSize, @Config.AcsDLFailed, Topic + 'ACS to download failed files');
Form.AddLong ('C', ' Min Upload Space', 40, 12, 60, 12, 18, 9, 0, 999999999, @Config.FreeUL, Topic + 'Min space to allow uploads (kb)');
Form.AddLong ('-', ' Min CD-ROM Space', 40, 13, 60, 13, 18, 9, 0, 999999999, @Config.FreeCDROM, Topic + 'Min space for CD-ROM copy (kb)');
Form.AddChar (#0, ' Default Protocol', 40, 14, 60, 14, 18, 32, 96, @Config.FProtocol, Topic + 'Default Protocol hotkey');
Form.AddStr (#0, ' See Offline', 45, 12, 60, 12, 13, 15, mysMaxAcsSize, @Config.AcsSeeOffline, Topic + 'ACS to see offline files');
Form.AddLong ('C', ' Min Upload Space', 40, 13, 60, 13, 18, 9, 0, 999999999, @Config.FreeUL, Topic + 'Min space to allow uploads (kb)');
Form.AddLong ('-', ' Min CD-ROM Space', 40, 14, 60, 14, 18, 9, 0, 999999999, @Config.FreeCDROM, Topic + 'Min space for CD-ROM copy (kb)');
Form.AddChar (#0, ' Default Protocol', 40, 15, 60, 15, 18, 32, 96, @Config.FProtocol, Topic + 'Default Protocol hotkey');
Form.Execute;

View File

@ -2,9 +2,839 @@ Unit bbs_Edit_Ansi;
{$I M_OPS.PAS}
// online ansi editor WIP
Interface
// Future online pipe/ansi editor and new full screen editor.
// Will be the most badass editor to ever exist.
Uses
bbs_MsgBase_ANSI;
Const
MaxLines = 1000;
Type
TEditorANSI = Class
Owner : Pointer;
ANSI : TMsgBaseANSI;
WinY1 : Byte;
WinY2 : Byte;
WinX1 : Byte;
WinX2 : Byte;
WinSize : Byte;
RowSize : Byte;
CurX : Byte;
CurY : SmallInt;
CurAttr : Byte;
CurLength : Byte;
TopLine : LongInt;
CurLine : LongInt;
InsertMode : Boolean;
DrawMode : Boolean;
GlyphMode : Boolean;
WrapMode : Boolean;
ClearEOL : Boolean;
LastLine : LongInt;
Constructor Create (Var O: Pointer);
Destructor Destroy; Override;
Function IsAnsiLine (Line: LongInt) : Boolean;
Function IsBlankLine (Var Line; LineSize: Byte) : Boolean;
Function GetLineLength (Var Line; LineSize: Byte) : Byte;
Function GetWrapPos (Var Line; LineSize, WrapPos: Byte) : Byte;
Procedure TrimLine (Var Line; LineSize: Byte);
Procedure DeleteLine (Line: LongInt);
Procedure InsertLine (Line: LongInt);
Procedure FindLastLine;
Procedure Reformat;
Procedure LocateCursor;
Procedure ReDrawTemplate;
Procedure DrawPage (StartY, EndY: Byte; ExitEOF: Boolean);
Procedure ScrollUp;
Procedure ScrollDown;
Function LineUp : Boolean;
Function LineDown (Reset: Boolean) : Boolean;
Procedure PageUp;
Procedure PageDown;
Procedure DrawLine (Line: LongInt; XP, YP: Byte);
Procedure DoEnter;
Procedure DoBackSpace;
Procedure DoDelete;
Procedure DoChar (Ch: Char);
Function Edit : Boolean;
Procedure LoadANSI;
End;
Implementation
Uses
m_Strings,
bbs_Core,
bbs_Ansi_MenuBox;
Constructor TEditorANSI.Create (Var O: Pointer);
Begin
Inherited Create;
Owner := O;
ANSI := TMsgBaseANSI.Create(NIL, False);
WinX1 := 1;
WinX2 := 79;
WinY1 := 2;
WinY2 := 23;
WinSize := WinY2 - WinY1 + 1;
RowSize := WinX2 - WinX1 + 1;
CurX := 1;
CurY := 1;
CurLine := 1;
TopLine := 1;
CurAttr := 7;
InsertMode := True;
DrawMode := False;
GlyphMode := False;
WrapMode := True;
ClearEOL := RowSize >= 79;
LastLine := 1;
End;
Destructor TEditorANSI.Destroy;
Begin
Inherited Destroy;
ANSI.Free;
End;
Procedure TEditorANSI.FindLastLine;
Var
Count : LongInt;
Begin
LastLine := MaxLines;
While (LastLine > 1) And IsBlankLine(ANSI.Data[LastLine], 80) Do
Dec(LastLine);
End;
Function TEditorANSI.IsAnsiLine (Line: LongInt) : Boolean;
Var
Count : Byte;
Begin
Result := False;
If GetLineLength(ANSI.Data[Line], 80) >= Rowsize Then Begin
Result := True;
Exit;
End;
For Count := 1 to 80 Do
If (Ord(ANSI.Data[Line][Count].Ch) < 32) or (Ord(ANSI.Data[Line][Count].Ch) > 128) Then Begin
Result := True;
Exit;
End;
End;
Function TEditorANSI.IsBlankLine (Var Line; LineSize: Byte) : Boolean;
Var
EndPos : Byte;
Data : Array[1..255] of RecAnsiBufferChar absolute Line;
Begin
EndPos := LineSize;
While (EndPos > 0) and (Data[EndPos].Ch = #0) Do
Dec (EndPos);
Result := EndPos = 0;
End;
Procedure TEditorANSI.TrimLine (Var Line; LineSize: Byte);
Var
Data : Array[1..255] of RecAnsiBufferChar absolute Line;
EndPos : Byte;
Begin
EndPos := 1;
While (EndPos <= LineSize) and (Data[1].Ch = ' ') Do Begin
Move (Data[2], Data[1], SizeOf(RecAnsiBufferChar) * (LineSize - 1));
Data[LineSize].Ch := #0;
Inc (EndPos);
End;
EndPos := LineSize;
While (EndPos > 0) and ((Data[EndPos].Ch = ' ') or (Data[EndPos].Ch = #0)) Do Begin
Data[EndPos].Ch := #0;
Dec (EndPos);
End;
End;
Procedure TEditorANSI.DeleteLine (Line: LongInt);
Var
Count : LongInt;
Begin
For Count := Line to MaxLines - 1 Do
ANSI.Data[Count] := ANSI.Data[Count + 1];
FillChar (ANSI.Data[MaxLines], SizeOf(RecAnsiBufferLine), #0);
If LastLine > 1 Then Dec(LastLine);
End;
Procedure TEditorANSI.InsertLine (Line: LongInt);
Var
Count : LongInt;
Begin
For Count := MaxLines DownTo Line + 1 Do
ANSI.Data[Count] := ANSI.Data[Count - 1];
FillChar(ANSI.Data[Line], SizeOf(RecAnsiBufferLine), #0);
If LastLine < MaxLines Then Inc(LastLine);
End;
Function TEditorANSI.GetWrapPos (Var Line; LineSize: Byte; WrapPos: Byte) : Byte;
Var
Data : Array[1..255] of RecAnsiBufferChar absolute Line;
Begin
If GetLineLength(Line, LineSize) < WrapPos Then Begin
Result := 0;
Exit;
End;
Result := LineSize;
While (Result > 0) and ((Data[Result].Ch <> ' ') or (Result > WrapPos)) Do
Dec (Result);
End;
Function TEditorANSI.GetLineLength (Var Line; LineSize: Byte) : Byte;
Var
Data : Array[1..255] of RecAnsiBufferChar absolute Line;
Begin
Result := LineSize;
While (Result > 0) and (Data[Result].Ch = #0) Do
Dec (Result);
End;
Procedure TEditorANSI.Reformat;
Var
WrapData : Array[1..255] of RecAnsiBufferChar;
TempStr : Array[1..255] of RecAnsiBufferChar;
NewLine : Array[1..255] of RecAnsiBufferChar;
Count : LongInt;
LineSize : Byte;
StartY : Byte;
StartLine : LongInt;
EndLine : LongInt;
First : Boolean = True;
Procedure Update;
Var
NewY : LongInt;
Begin
NewY := StartY + EndLine - StartLine + 1;
If NewY > WinSize Then NewY := WinSize;
If CurY > WinSize Then
ScrollDown
Else
DrawPage (StartY, NewY, True);
End;
Begin
FillChar (WrapData, SizeOf(WrapData), #0);
Count := CurLine;
StartY := CurY;
StartLine := Count;
While Count <= MaxLines Do Begin
If Count > LastLine Then LastLine := Count;
FillChar (TempStr, SizeOf(TempStr), #0);
Move (Ansi.Data[Count], TempStr, SizeOf(Ansi.Data[Count]));
If Not IsBlankLine(WrapData, 255) Then Begin
If IsBlankLine(TempStr, 255) Then Begin
If Count < LastLine Then Begin
InsertLine(Count);
EndLine := MaxLines;
End Else
EndLine := Count;
Move (WrapData, ANSI.Data[Count], SizeOf(Ansi.Data[Count]));
Update;
Exit;
End;
FillChar (NewLine, SizeOf(NewLine), #0);
LineSize := GetLineLength(WrapData, 255);
Move (WrapData, NewLine, LineSize * SizeOf(RecAnsiBufferChar));
NewLine[LineSize + 1].Ch := ' ';
NewLine[LineSize + 1].Attr := WrapData[LineSize].Attr;
Move (TempStr, NewLine[LineSize + 2], GetLineLength(TempStr, 255) * SizeOf(RecAnsiBufferChar));
Move (NewLine, TempStr, SizeOf(NewLine));
End;
FillChar (WrapData, SizeOf(WrapData), #0);
LineSize := GetWrapPos(TempStr, 255, RowSize);
If LineSize > 0 Then Begin
Move (TempStr[LineSize], WrapData, (GetLineLength(TempStr, 255) - LineSize + 1) * SizeOf(RecAnsiBufferChar));
FillChar (TempStr[LineSize], (255 - LineSize) * SizeOf(RecAnsiBufferChar), #0);
TrimLine (WrapData, 255);
If First Then Begin
If CurX > LineSize Then Begin
CurX := CurX - LineSize;
Inc (CurY);
Inc (CurLine);
End;
First := False;
End;
End;
FillChar (ANSI.Data[Count], SizeOf(ANSI.Data[Count]), #0);
Move (TempStr, ANSI.Data[Count], RowSize * SizeOf(RecAnsiBufferChar));
If LineSize = 0 Then Begin
If First Then Begin
CurX := 1;
Inc (CurLine);
Inc (CurY);
If CurLine > LastLine Then LastLine := CurLine;
EndLine := Count + 1;
End Else
EndLine := Count;
Update;
Exit;
End;
Inc (Count);
End;
// Update;
End;
Procedure TEditorANSI.ReDrawTemplate;
// temp stuff to be replaced by real template
Var
B : TAnsiMenuBox;
Begin
TBBSCore(Owner).io.AllowArrow := True;
TBBSCore(Owner).io.AnsiColor(7);
TBBSCore(Owner).io.AnsiClear;
(*
B := TAnsiMenuBox.Create;
B.FrameType := 1;
B.Open (5, 2, 75, 23);
B.Free;
WinX1 := 6;
WinX2 := 74;
WinY1 := 3;
WinY2 := 22;
*)
WinX1 := 1;
WinX2 := 79;
WinY1 := 2;
WinY2 := 23;
WinSize := WinY2 - WinY1 + 1;
RowSize := WinX2 - WinX1 + 1;
CurX := 1;
CurY := 1;
ClearEOL := RowSize >= 79;
LoadANSI;
FindLastLine;
DrawPage(1, WinSize, False);
End;
Procedure TEditorANSI.LocateCursor;
Begin
CurLength := GetLineLength(ANSI.Data[CurLine], RowSize);
If CurX < 1 Then CurX := 1;
If CurX > CurLength Then CurX := CurLength + 1;
If CurY < 1 Then CurY := 1;
While TopLine + CurY - 1 > LastLine Do
Dec (CurY);
If Not DrawMode Then Begin
If (CurX > 1) and (CurX = CurLength + 1) Then
CurAttr := ANSI.Data[CurLine][CurX - 1].Attr
Else
CurAttr := ANSI.Data[CurLine][CurX].Attr;
If CurAttr = 0 Then CurAttr := 7;
End;
With TBBSCore(Owner).io Do Begin
//AnsiGotoXY (1, 1);
//BufAddStr ('X:' + strI2S(CurX) + ' Y:' + strI2S(CurY) + ' CL:' + strI2S(CurLine) + ' TL:' + strI2S(TopLine) + ' Last:' + strI2S(LastLine) + ' Len:' + strI2S(GetLineLength(ANSI.Data[CurLine], 80)) + ' Row:' + strI2S(RowSize) + ' ');
AnsiGotoXY (WinX1 + CurX - 1, WinY1 + CurY - 1);
AnsiColor (CurAttr);
BufFlush;
End;
End;
Procedure TEditorANSI.DrawPage (StartY, EndY: Byte; ExitEOF: Boolean);
Var
CountY : LongInt;
CountX : Byte;
Begin
For CountY := StartY to EndY Do Begin
If TopLine + CountY - 1 > LastLine + 1 Then Begin
TBBSCore(Owner).io.AnsiGotoXY (WinX1, WinY1 + CountY - 1);
TBBSCore(Owner).io.AnsiColor (7);
If ClearEOL Then
TBBSCore(Owner).io.AnsiClrEOL
Else
TBBSCore(Owner).io.BufAddStr (strRep(' ', RowSize));
End Else
If TopLine + CountY - 1 = LastLine + 1 Then Begin
TBBSCore(Owner).io.AnsiGotoXY (WinX1, WinY1 + CountY - 1);
TBBSCore(Owner).io.AnsiColor (12);
TBBSCore(Owner).io.BufAddStr (strPadC('-----END-----', RowSize, ' '));
If ExitEOF Then Break;
End Else
DrawLine (TopLine + CountY - 1, 1, CountY);
End;
End;
Procedure TEditorANSI.ScrollUp;
Var
NewTop : LongInt;
Begin
NewTop := TopLine - (WinSize DIV 2) + 1;
If NewTop < 1 Then NewTop := 1;
CurY := CurLine - NewTop + 1;
TopLine := NewTop;
DrawPage(1, WinSize, False);
End;
Procedure TEditorANSI.ScrollDown;
Var
NewTop : LongInt;
Begin
NewTop := TopLine + (WinSize DIV 2) + 1;
While NewTop >= MaxLines Do
Dec (NewTop, 2);
CurY := CurLine - NewTop + 1;
TopLine := NewTop;
DrawPage(1, WinSize, False);
End;
Function TEditorANSI.LineUp : Boolean;
Begin
Result := False;
If CurLine = 1 Then Exit;
Dec (CurLine);
Dec (CurY);
If CurX > GetLineLength(ANSI.Data[CurLine], 80) Then CurX := GetLineLength(ANSI.Data[CurLine], 80) + 1;
If CurY < 1 Then Begin
ScrollUp;
Result := True;
End;
End;
Function TEditorANSI.LineDown (Reset: Boolean) : Boolean;
Begin
Result := False;
If CurLine >= MaxLines Then Exit;
Inc (CurLine);
Inc (CurY);
If Reset Then CurX := 1;
If CurX > GetLineLength(ANSI.Data[CurLine], 80) Then CurX := GetLineLength(ANSI.Data[CurLine], 80) + 1;
If CurY > WinSize Then Begin
Result := True;
ScrollDown;
End;
End;
(*
Procedure TEditorANSI.DrawLine (Line: LongInt; XP, YP: Byte);
Var
Count : Byte;
Begin
TBBSCore(Owner).io.AnsiGotoXY (WinX1 + XP - 1, WinY1 + YP - 1);
For Count := XP to RowSize Do Begin
If ANSI.Data[Line][Count].Ch = #0 Then Begin
TBBSCore(Owner).io.AnsiColor (7);
TBBSCore(Owner).io.BufAddChar (' ');
End Else Begin
TBBSCore(Owner).io.AnsiColor (ANSI.Data[Line][Count].Attr);
TBBSCore(Owner).io.BufAddChar (ANSI.Data[Line][Count].Ch);
End;
End;
End;
*)
Procedure TEditorANSI.DrawLine (Line: LongInt; XP, YP: Byte);
Var
Count : Byte;
LineLen : Byte;
Begin
TBBSCore(Owner).io.AnsiGotoXY (WinX1 + XP - 1, WinY1 + YP - 1);
LineLen := GetLineLength(ANSI.Data[Line], RowSize);
For Count := XP to LineLen Do Begin
If ANSI.Data[Line][Count].Ch = #0 Then Begin
TBBSCore(Owner).io.AnsiColor (7);
TBBSCore(Owner).io.BufAddChar (' ');
End Else Begin
TBBSCore(Owner).io.AnsiColor (ANSI.Data[Line][Count].Attr);
TBBSCore(Owner).io.BufAddChar (ANSI.Data[Line][Count].Ch);
End;
End;
If LineLen < RowSize Then
If ClearEOL Then Begin
TBBSCore(Owner).io.AnsiColor (7);
TBBSCore(Owner).io.AnsiClrEOL;
End Else Begin
TBBSCore(Owner).io.AnsiColor (7);
TBBSCore(Owner).io.BufAddStr (strRep(' ', LineLen - RowSize));
End;
End;
Procedure TEditorANSI.DoDelete;
Var
JoinLen : Byte;
JoinPos : Byte;
JoinBuf : Array[1..255] of RecAnsiBufferChar;
Begin
If CurX <= CurLength Then Begin
Move (ANSI.Data[CurLine][CurX + 1], ANSI.Data[CurLine][CurX], (CurLength - 1) * SizeOf(RecAnsiBufferChar));
ANSI.Data[CurLine][CurLength].Ch := #0;
DrawLine (CurLine, CurX, CurY);
End Else
If CurLine < LastLine Then
If (CurLength = 0) and (LastLine > 1) Then Begin
DeleteLine (CurLine);
DrawPage (CurY, WinSize, False);
End Else Begin
JoinLen := GetLineLength(ANSI.Data[CurLine + 1], RowSize);
If CurLength + JoinLen <= RowSize Then Begin
Move (ANSI.Data[CurLine + 1], ANSI.Data[CurLine][CurX], SizeOf(RecAnsiBufferChar) * JoinLen);
DeleteLine (CurLine + 1);
DrawPage (CurY, WinSize, False); //optimize
End Else Begin
JoinPos := GetWrapPos(ANSI.Data[CurLine + 1], RowSize, RowSize - CurLength);
If JoinPos > 0 Then Begin
Move (ANSI.Data[CurLine + 1], ANSI.Data[CurLine][CurX], SizeOf(RecAnsiBufferChar) * (JoinPos - 1));
FillChar (JoinBuf, SizeOf(JoinBuf), #0);
Move (ANSI.Data[CurLine + 1][JoinPos + 1], JoinBuf, (JoinLen - JoinPos + 1) * SizeOf(RecAnsiBufferChar));
Move (JoinBuf, ANSI.Data[CurLine + 1], RowSize * SizeOf(RecAnsiBufferChar));
DrawPage (CurY, CurY + 1, True);
End;
End;
End;
End;
Procedure TEditorANSI.DoBackSpace;
Var
JoinPos : Byte;
JoinBuf : Array[1..255] of RecAnsiBufferChar;
Begin
If CurX > 1 Then Begin
Dec (CurX);
Move (ANSI.Data[CurLine][CurX + 1], ANSI.Data[CurLine][CurX], SizeOf(RecAnsiBufferChar) * (80 - CurX + 1));
ANSI.Data[CurLine][80].Ch := #0;
If CurX > GetLineLength(ANSI.Data[CurLine], 80) Then
TBBSCore(Owner).io.OutBS(1, True)
Else
DrawLine (CurLine, CurX, CurY);
End Else
If CurLine > 1 Then Begin
If GetLineLength(ANSI.Data[CurLine - 1], 80) + CurLength <= RowSize Then Begin
CurX := GetLineLength(ANSI.Data[CurLine - 1], 80) + 1;
Move (ANSI.Data[CurLine], ANSI.Data[CurLine - 1][CurX], SizeOf(RecAnsiBufferChar) * CurLength);
DeleteLine (CurLine);
If Not LineUp Then DrawPage (CurY, WinSize, False); //optimize
End Else Begin
JoinPos := GetWrapPos(ANSI.Data[CurLine], RowSize, RowSize - GetLineLength(ANSI.Data[CurLine - 1], RowSize));
If JoinPos > 0 Then Begin
CurX := GetLineLength(ANSI.Data[CurLine - 1], 80) + 1;
Move (ANSI.Data[CurLine], ANSI.Data[CurLine - 1][CurX], SizeOf(RecAnsiBufferChar) * (JoinPos - 1));
FillChar (JoinBuf, SizeOf(JoinBuf), #0);
Move (ANSI.Data[CurLine][JoinPos + 1], JoinBuf, (CurLength - JoinPos + 1) * SizeOf(RecAnsiBufferChar));
Move (JoinBuf, ANSI.Data[CurLine], RowSize * SizeOf(RecAnsiBufferChar));
If Not LineUp Then DrawPage (CurY, WinSize, False);
End Else Begin
LineUp;
CurX := CurLength + 1;
End;
End;
End;
End;
Procedure TEditorANSI.DoChar (Ch: Char);
Begin
If InsertMode Then Begin
Move (ANSI.Data[CurLine][CurX], ANSI.Data[CurLine][CurX + 1], SizeOf(RecAnsiBufferChar) * (CurLength - CurX + 1));
ANSI.Data[CurLine][CurX].Ch := Ch;
ANSI.Data[CurLine][CurX].Attr := CurAttr;
If CurLength < RowSize {-1} Then Begin
If CurX <= CurLength Then
DrawLine (CurLine, CurX, CurY)
Else Begin
TBBSCore(Owner).io.AnsiColor (CurAttr);
TBBSCore(Owner).io.BufAddChar (Ch);
End;
Inc (CurX);
End Else Begin
Inc (CurX);
Reformat;
End;
End Else
If CurX <= RowSize Then Begin
ANSI.Data[CurLine][CurX].Ch := Ch;
ANSI.Data[CurLine][CurX].Attr := CurAttr;
TBBSCore(Owner).io.AnsiColor (CurAttr);
TBBSCore(Owner).io.BufAddChar (Ch);
Inc (CurX);
End;
End;
Procedure TEditorANSI.PageUp;
Var
NewTop : LongInt;
Begin
If CurLine = 1 Then Exit;
If TopLine = 1 Then Begin
CurLine := 1;
CurY := 1;
CurX := 1;
Exit;
End;
Dec (CurLine, WinSize);
If CurLine < 1 Then Begin
CurLine := 1;
NewTop := 1;
End Else Begin
NewTop := TopLine - WinSize;
If NewTop < 1 Then NewTop := 1;
End;
CurY := CurLine - NewTop + 1;
TopLine := NewTop;
DrawPage(1, WinSize, False);
End;
Procedure TEditorANSI.PageDown;
Var
NewTop : LongInt;
Begin
If CurLine = LastLine Then Exit;
If (LastLine > TopLine) And (LastLine <= TopLine + WinSize - 1) Then Begin
CurLine := LastLine;
CurY := CurLine - TopLine + 1;
CurX := 1;
Exit;
End;
Inc (CurLine, WinSize);
If CurLine > LastLine Then CurLine := LastLine;
NewTop := TopLine + WinSize;
While NewTop >= LastLine - (WinSize DIV 2) Do
Dec (NewTop);
If NewTop < 1 Then NewTop := 1;
CurY := CurLine - NewTop + 1;
TopLine := NewTop;
DrawPage(1, WinSize, False);
End;
Procedure TEditorANSI.LoadANSI;
Var
F : File;
B : Array[1..1024] of Char;
BR : LongInt;
A : LongInt;
C : LongINt;
Begin
Assign (F, '\code\mystic1\text\gj-glue1.ans');
Reset (F, 1);
While Not Eof(F) Do Begin
BlockRead (F, B, SizeOf(B), BR);
If BR = 0 Then Break;
ANSI.ProcessBuf(B, BR);
End;
Close(F);
For A := 1 to ANSI.Lines Do
For C := RowSize + 1 to 80 Do Begin
ANSI.Data[A][C].Ch := #0;
ANSI.Data[A][C].Attr := 0;
End;
End;
Procedure TEditorANSI.DoEnter;
Var
TempLine : RecAnsiBufferLine;
Begin
If InsertMode and IsBlankLine(ANSI.Data[MaxLines], 80) Then Begin
If CurX > CurLength Then Begin
InsertLine (CurLine + 1);
If Not LineDown(True) Then DrawPage(CurY, WinSize, True);
End Else Begin
TempLine := ANSI.Data[CurLine];
InsertLine (CurLine + 1);
FillChar (ANSI.Data[CurLine][CurX], SizeOf(RecAnsiBufferChar) * (80 - CurX + 1), #0);
Move (TempLine[CurX], ANSI.Data[CurLine + 1][1], SizeOf(RecAnsiBufferChar) * (80 - CurX + 1));
If Not LineDown(True) Then
DrawPage (CurY - 1, WinSize, True);
End;
End Else
LineDown(True);
End;
Function TEditorANSI.Edit : Boolean;
Var
Ch : Char;
Attr : Byte;
Begin
Result := False;
ReDrawTemplate;
While Not TBBSCore(Owner).ShutDown Do Begin
LocateCursor;
Ch := TBBSCore(Owner).io.GetKey;
If Session.io.IsArrow Then Begin
Case Ch of
#71 : CurX := 1;
#79 : CurX := CurLength + 1;
#72 : LineUp;
#80 : If CurLine < LastLine Then LineDown(False);
#75 : If CurX > 1 Then Dec(CurX);
#77 : If CurX <= RowSize Then Inc(CurX);
#73 : PageUp;
#81 : PageDown;
#83 : DoDelete;
End;
End Else
Case Ch of
^V : InsertMode := Not InsertMode; //update on screen
^Y : Begin
DeleteLine (CurLine);
If CurLine > LastLine Then
InsertLine (CurLine);
DrawPage (CurY, WinSize, False);
End;
^Z : Break;
#08 : DoBackSpace;
#13 : DoEnter;
#32..
#254 : If (CurLength >= RowSize) and (GetWrapPos(ANSI.Data[CurLine], RowSize, RowSize) = 0) Then Begin
If CurX = CurLength + 1 Then Begin
LineDown(True);
End;
End Else
DoChar(Ch);
End;
End;
End;
End.

View File

@ -90,6 +90,7 @@ Type
Function ExportFileList (NewFiles: Boolean; Qwk: Boolean) : Boolean;
Function ArchiveView (FName : String) : Boolean;
Procedure FileGroupChange (Ops: String; FirstBase, Intro : Boolean);
Procedure XferDisconnect;
Procedure UploadFile;
Procedure DownloadBatch;
Procedure NewFileScan (Mode: Char);
@ -1160,12 +1161,14 @@ Var
If Session.User.Access(FBase.ListACS) Then Begin
Inc (Total);
Session.io.PromptInfo[1] := strI2S(Total);
Session.io.PromptInfo[2] := FBase.Name;
GetFileScan;
Session.io.PromptInfo[3] := Session.io.OutYN(FScan.NewScan > 0);
Session.io.OutFull (Session.GetPrompt(201));
If (Total MOD Config.FColumns = 0) And (Total > 0) Then Session.io.OutRawLn('');
@ -1188,25 +1191,33 @@ Var
B : Word;
Begin
B := 0;
Reset (FBaseFile);
Repeat
Read (FBaseFile, FBase);
If Session.User.Access(FBase.ListACS) Then Inc(B);
If A = B Then Break;
Until False;
GetFileScan;
Session.io.PromptInfo[1] := FBase.Name;
If FBase.DefScan = 2 Then Begin
FScan.NewScan := 1;
Session.io.OutFullLn (Session.GetPrompt(289));
End Else
If FScan.NewScan = 0 Then Begin
FScan.NewScan := 1;
Session.io.OutFullLn (Session.GetPrompt(204));
End Else Begin
FScan.NewScan := 0;
Session.io.OutFullLn (Session.GetPrompt(203));
End;
@ -2014,6 +2025,7 @@ Var
OkFile := False;
If (FDir.Flags And FDirDeleted <> 0) Then Exit;
If (FDir.Flags AND FDirOffline <> 0) And (Not Session.User.Access(Config.AcsSeeOffline)) Then Exit;
If (FDir.Flags And FDirInvalid <> 0) And (Not Session.User.Access(Config.AcsSeeUnvalid)) Then Exit;
If (FDir.Flags And FDirFailed <> 0) And (Not Session.User.Access(Config.AcsSeeFailed)) Then Exit;
@ -3217,6 +3229,7 @@ Var
Dir : String[40];
Min : Integer;
Sec : Byte;
HangUp : Boolean;
Begin
If FBase.FileName = '' Then Begin
Session.io.OutFullLn(Session.GetPrompt(38));
@ -3267,6 +3280,8 @@ Begin
Else
Dir := FBase.Path;
HangUp := Session.io.GetYN(Session.GetPrompt(66), False);
If SendFile(Dir + FName) Then Begin
Session.SystemLog ('Downloaded: ' + FDir.FileName);
@ -3284,6 +3299,8 @@ Begin
Session.SystemLog ('Download of ' + FDir.FileName + ' FAILED');
FileErase(Session.TempPath + FName);
If HangUp Then XferDisconnect;
End;
1 : Session.io.OutFullLn (Session.GetPrompt(224));
2 : Session.io.OutFullLn (Session.GetPrompt(58));
@ -3300,6 +3317,23 @@ Begin
Session.io.OutFullLn (Session.GetPrompt(51));
End;
Procedure TFileBase.XferDisconnect;
Var
Timer : LongInt;
Begin
Timer := TimerSet(1000);
Session.io.OutFull(Session.GetPrompt(67));
While Not TimerUp(Timer) Do
If Session.io.InKey(1000) <> #255 Then Begin
Session.io.OutRawLn('');
Exit;
End;
Halt(0);
End;
Procedure TFileBase.DownloadBatch;
Var
A : Byte;
@ -3308,6 +3342,7 @@ Var
Dir : String[40];
Old : RecFileBase;
FL : Text;
Hangup : Boolean;
Begin
K := 0;
@ -3324,6 +3359,8 @@ Begin
If SelectProtocol(True, True) = 'Q' Then Exit;
HangUp := Session.io.GetYN(Session.GetPrompt(66), False);
Assign (FL, Session.TempPath + 'file.lst');
ReWrite (FL);
@ -3397,6 +3434,8 @@ Begin
BatchNum := 0;
DirClean (Session.TempPath, '');
If HangUp Then XferDisconnect;
End;
Procedure TFileBase.FileSearch;

View File

@ -928,6 +928,7 @@ Begin
BufAddStr (#27 + '[K');
End;
(*
Function TBBSIO.Pipe2Ansi (Color: Byte) : String;
Begin
Result := '';
@ -967,8 +968,8 @@ Begin
23: Result := Result + #27 + '[47m';
End;
End;
*)
(*
Function TBBSIO.Pipe2Ansi (Color: Byte) : String;
Var
CurFG : Byte;
@ -1033,7 +1034,6 @@ Begin
End;
End;
End;
*)
Function TBBSIO.Attr2Ansi (Attr: Byte) : String;
Begin
@ -1055,6 +1055,8 @@ Procedure TBBSIO.AnsiGotoXY (X: Byte; Y: Byte);
Begin
If Graphics = 0 Then Exit;
If (X = Screen.CursorX) and (Y = Screen.CursorY) Then Exit;
If X = 0 Then X := Screen.CursorX;
If Y = 0 Then Y := Screen.CursorY;
@ -1140,6 +1142,7 @@ Var
Begin
Result := False;
NoFile := True;
FileMode := 66;
If (Pos(PathSep, FName) > 0) Then Begin
If Not FileExist(FName) Then

View File

@ -62,7 +62,7 @@ Type
Procedure GlobalMessageSearch (Mode: Char);
Procedure SetMessagePointers;
Procedure ViewSentEmail;
Function ResolveOrigin (var mArea: RecMessageBase) : String;
Function ResolveOrigin (Var mArea: RecMessageBase) : String;
// QWK and QWKE goodies
Procedure DownloadQWK (Extended: Boolean; Data: String);
Procedure UploadREP;
@ -366,7 +366,7 @@ Begin
For A := 1 to Lines Do
Msg^.DoStringLn(MsgText[A]);
If Session.User.ThisUser.SigUse and (Session.User.ThisUser.SigLength > 0) Then Begin
If (MBase.Flags AND MBAutoSigs <> 0) and Session.User.ThisUser.SigUse and (Session.User.ThisUser.SigLength > 0) Then Begin
Assign (DF, Config.DataPath + 'autosig.dat');
Reset (DF, 1);
@ -1483,6 +1483,18 @@ Var
Session.io.OutRawLn('');
End;
Procedure RemoveNewScan (PromptNumber: SmallInt);
Begin
GetMessageScan;
If MScan.NewScan = 1 Then
If Session.io.GetYN(Session.GetPrompt(PromptNumber), False) Then Begin
MScan.NewScan := 0;
SetMessageScan;
End;
End;
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
@ -1560,7 +1572,7 @@ Var
MsgText[Lines] := MsgBase^.GetString(79);
If MsgText[Lines][1] = #1 Then Begin
If Copy(MsgText[Lines], 1, 6) = #1 + 'MSGID' Then
If Copy(MsgText[Lines], 2, 5) = 'MSGID' Then
ReplyID := Copy(MsgText[Lines], 9, Length(MsgText[Lines]));
Dec (Lines);
@ -1667,6 +1679,9 @@ Var
'I' : Begin
LastRead := MsgBase^.GetHighMsgNum;
Ansi_View_Message := True;
RemoveNewScan(495);
Exit;
End;
'J' : Begin
@ -2077,6 +2092,9 @@ Var
'G' : Break;
'I' : Begin
LastRead := MsgBase^.GetHighMsgNum;
RemoveNewScan(495);
Break;
End;
'?' : Begin
@ -2158,7 +2176,7 @@ Var
Str := MsgBase^.GetString(79);
If Str[1] = #1 Then Begin
If Copy(Str, 1, 6) = #1 + 'MSGID' Then
If Copy(Str, 2, 5) = 'MSGID' Then
ReplyID := Copy(Str, 9, Length(Str));
End Else
Send_Msg_Text (Str);
@ -2220,6 +2238,9 @@ Var
'H' : LastRead := MsgBase^.GetMsgNum - 1;
'I' : Begin
LastRead := MsgBase^.GetHighMsgNum;
RemoveNewScan(494);
Exit;
End;
'J' : Begin
@ -2494,24 +2515,34 @@ Var
Lines : Integer;
Forced : Boolean;
Old : RecMessageBase;
SaveGroup : Boolean;
Begin
Old := MBase;
SaveGroup := Session.User.IgnoreGroup;
If Email Then Begin
Reset (MBaseFile);
Read (MBaseFile, MBase);
Close (MBaseFile);
Session.User.IgnoreGroup := True;
End;
If MBase.FileName = '' Then Begin
Session.io.OutFullLn (Session.GetPrompt(110));
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
If Not Session.User.Access(MBase.PostACS) Then Begin
Session.io.OutFullLn (Session.GetPrompt(105));
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
@ -2583,6 +2614,8 @@ Begin
If MsgTo = '' Then Begin
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
@ -2597,6 +2630,8 @@ Begin
Session.io.OutFull (Session.GetPrompt(307))
Else Begin
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
Until MsgSubj <> '';
@ -2617,6 +2652,8 @@ Begin
If Not OpenCreateBase(MsgBase, MBase) Then Begin
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
@ -2670,6 +2707,7 @@ Begin
Session.io.OutFullLn (Session.GetPrompt(109));
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
End;
Procedure TMsgBase.CheckEMail;
@ -3411,7 +3449,7 @@ Var
Pick : LongInt;
Begin
Result := '';
Loc := Pos('@RANDOM=', mArea.Origin);
Loc := Pos('@RANDOM=', strUpper(mArea.Origin));
If Loc > 0 Then Begin
FN := strStripB(Copy(mArea.Origin, Loc + 8, 255), ' ');

View File

@ -9,21 +9,21 @@ Uses
BBS_Common;
Type
PtrMessageLine = ^RecMessageLine;
RecMessageLine = Array[1..80] of Record
RecAnsiBufferChar = Record
Ch : Char;
Attr : Byte;
End;
RecMessageAnsi = Array[1..mysMaxMsgLines] of RecMessageLine;
// make this a pointer?
RecAnsiBufferLine = Array[1..80] of RecAnsiBufferChar;
RecAnsiBuffer = Array[1..mysMaxMsgLines] of RecAnsiBufferLine;
TMsgBaseAnsi = Class
GotAnsi : Boolean;
GotPipe : Boolean;
GotClear : Boolean;
PipeCode : String[2];
Owner : Pointer;
Data : RecMessageAnsi;
Data : RecAnsiBuffer;
Code : String;
Lines : Word;
CurY : Word;
@ -87,9 +87,10 @@ Begin
Attr := 7;
GotAnsi := False;
GotPipe := False;
GotClear := False;
PipeCode := '';
FillChar (Data, SizeOf(Data), 0);
FillChar (Data, SizeOf(Data), #0);
ResetControlCode;
End;
@ -353,7 +354,7 @@ Begin
Case Ch of
#27 : Escape := 1;
#9 : MoveXY (CurX + 8, CurY);
#12 : {Edit.ClearScreenData};
#12 : GotClear := True;
Else
If Ch = '|' Then
GotPipe := True

View File

@ -151,8 +151,10 @@
064 |01[|10þ|01] |09Search all file groups? |11
; Start your file transfer now &1=selected protocol
065 |CR|12Start your |15|&1 |12transfer now...
066 UNUSED
067 UNUSED
; Disconnect after download?
066 |CR|12Disconnect after file transfer? |11
; Disconneting in 10 seconds, press a key to abort
067 |CR|09Disconnecting in 10 seconds: Press a key to abort.
068 |CR|12You do not have access to upload here!
069 |CR|12Illegal filename.|DE|DE|DE
070 |CR|14Searching for duplicate files ...
@ -345,7 +347,7 @@
; One Liner header
188 |CL|09Ú|$D77Ä|01¿|CR|09³|17 ± |15One Liners|$D64 |01|16³|CR|09À|01|$D77ÄÙ|CR
; One liner prompt
189 |CR |09|$D77Ä|CR |01[|10þ|01] |09Add to the one liners?
189 |CR |09|$D77Ä|CR |01[|10þ|01] |09Add to the one liners? |XX
190 |CR|01[|10þ|01] |09Enter your one liner:|CR
191 |CR|12Unable to view archive.
; Archive view header &1 = Filename
@ -966,3 +968,7 @@
492 |CR|09Forward message to which base (|10?|09/|10List|09): |11
; Sysop password prompt
493 |CR|09Sysop Password: |XX
; Normal msg reader: Remove from newscan? (after I command)
494 |CR|12Remove |15|MB |12from message newscan? |XX
; Lightbar msg reader: Remove from newscan (after I command)
495 |CR|12Remove |15|MB |12from message newscan? |XX

View File

@ -64,6 +64,7 @@ Const
TrashFile : String = '';
TempPath : String = '';
AreasFile : String = '';
FCheckKill : Boolean = False;
Var
ConfigFile : File of RecConfig;
@ -119,7 +120,7 @@ Begin
WriteLn ('-BKILL <ID> <Days> Delete BBSes which haven''t been verified in <DAYS>');
WriteLn ('-BPACK Pack all BBS lists');
WriteLn ('-BSORT <ID> <Type> Sorts and packs BBS list by <type>');
WriteLn ('-FCHECK Checks file entries for correct size and status');
WriteLn ('-FCHECK <KILL> Check filelist for correct size/status');
WriteLn ('-FIXINDEX Fix broken permanent index for msg/file bases');
WriteLn ('-FPACK Pack file bases');
WriteLn ('-FSORT Sort file base entries by filename');
@ -281,7 +282,7 @@ Var
FDirFile : File of RecFileList;
FDir : RecFileList;
TFDirFile : File of RecFileList;
DF : File of Byte;
DF : File;
Begin
Write ('Checking File Bases : ');
@ -305,11 +306,13 @@ Begin
While Not Eof(FDirFile) Do Begin
Read (FDirFile, FDir);
If FDir.Flags And FDirDeleted = 0 Then Begin
If FDir.Flags AND FDirDeleted <> 0 Then Continue;
Assign (DF, FBase.Path + FDir.FileName);
{$I-} Reset (DF); {$I+}
{$I-} Reset (DF, 1); {$I+}
If IoResult <> 0 Then
FDir.Flags := FDir.Flags AND FDirOffline
FDir.Flags := FDir.Flags OR FDirOffline
Else Begin
FDir.Size := FileSize(DF);
@ -321,9 +324,10 @@ Begin
Close (DF);
End;
If (FDir.Flags AND FDirOffline <> 0) and FCheckKill Then Continue;
Write (TFDirFile, FDir);
End;
End;
Close (FDirFile); {delete backup file}
Erase (FDirFile);
@ -1130,7 +1134,13 @@ Begin
End Else
BBSSort := True;
End;
If Temp = '-FCHECK' Then FileCheck := True;
If Temp = '-FCHECK' Then Begin
FileCheck := True;
FCheckKill := strUpper(ParamStr(A+1)) = 'KILL';
If FCheckKill Then Inc(A);
End;
If Temp = '-FIXINDEX' Then FixIndex := True;
If Temp = '-FPACK' Then FilePack := True;
If Temp = '-FSORT' Then FileSort := True;
@ -1161,6 +1171,7 @@ Begin
End;
If Temp = '-UPACK' Then UserPack := True;
If Temp = '-NOCHECK' Then NodeCheck := False;
Inc (A);
End;

View File

@ -569,6 +569,7 @@ Begin
DirFile.Read(Dir);
If (Dir.Flags And FDirDeleted <> 0) Then Continue;
If (Dir.Flags and FDirOffline <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeOffline)) Then Continue;
If (Dir.Flags And FDirInvalid <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeUnvalid)) Then Continue;
If (Dir.Flags And FDirFailed <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeFailed)) Then Continue;

View File

@ -23,6 +23,8 @@ Program Mystic;
{$I M_OPS.PAS}
{.$DEFINE EDITWORK}
Uses
{$IFDEF DEBUG}
HeapTrc,
@ -44,8 +46,23 @@ Uses
bbs_Common,
bbs_Core,
bbs_NodeInfo,
{$IFDEF EDITWORK}
bbs_edit_ansi,
{$ENDIF}
bbs_Cfg_Main;
{$IFDEF EDITWORK}
Procedure TestEditor;
Var
T : TEditorANSI;
Begin
T := TEditorANSI.Create(Pointer(Session));
T.Edit;
T.Free;
End;
{$ENDIF}
Procedure InitClasses;
Begin
Assign (ConfigFile, 'mystic.dat');
@ -359,6 +376,8 @@ Begin
DirChange(JustPath(ParamStr(0)));
//FileMode := 66;
InitClasses;
Screen.TextAttr := 7;
@ -467,6 +486,11 @@ Begin
Set_Node_Action (Session.GetPrompt(345));
{$IFDEF EDITWORK}
TestEditor;
Halt(0);
{$ENDIF}
Session.User.UserLogon1 (UserName, Password, Script);
If Session.TimeOffset > 0 Then

View File

@ -59,7 +59,7 @@ Const
mysMaxMenuCmds = 25; // Max menu commands per item
mysMaxMenuInput = 12;
mysMaxMenuStack = 8;
mysMaxThemeText = 493; // Total prompts in theme file
mysMaxThemeText = 495; // Total prompts in theme file
fn_SemFileEcho = 'echomail.now';
fn_SemFileNews = 'newsmail.now';
@ -325,14 +325,14 @@ Type
inetTNHidden : Boolean;
ThemeOnStart : Boolean;
StartCodePage : Byte;
AcsSeeOffline : String[mysMaxAcsSize];
//inetSMTPRelay : String[30];
//inetSMTPLogin : String[30];
//inetSMTPPW : String[30];
//EmailValidationLevel
//AllowEmailPWReset
Reserved : Array[1..843] of Char;
Reserved : Array[1..812] of Char;
End;
Const

View File

@ -2536,11 +2536,50 @@
! According to a document I saw, the ANSI-BBS C function to move the cursor
should hard stop at 80. Mystic's ANSI parser wraps to the next line which
I think was added in a while back to increase ANSI compatibility. For
now I changed it back to follow what this standard document is claiming,
even if it is sort of against my better judgement.
now I changed it back to follow what this standard document is claiming.
+ If a message bases's data files actually exist, for but some reason the
highest message number is 0 (ie everything has been deleted), Mystic will
now display the "There are no messages in this base" prompt when reading.
+ When downloading a file or a batch, Mystic will now ask the user if they
would like to disconnect after the transfer. Replace two prompts in your
language file:
; Disconnect after download?
066 |CR|12Disconnect after file transfer? |11
; Disconneting in 10 seconds, press a key to abort
067 |CR|09Disconnecting in 10 seconds: Press a key to abort.
! Mystic wasn't properly checking the message base "auto signature" setting
before adding in the user's auto signature.
+ Mystic will now ignore the group membership contraints in the ACS string
when using the MW (write email) menu command.
+ Mystic now has an ACS setting to "see offline" files in the file bases.
This setting is found in System Config -> File Base Settings.
+ If you select the I (Ignore all messages) option while reading message
bases, Mystic will now ask you if you want to remove the base from your
new message scan. Two new prompts go along with this:
; Normal msg reader: Remove from newscan? (after I command)
494 |CR|12Remove |15|MB |12from message newscan? |XX
; Lightbar msg reader: Remove from newscan (after I command)
495 |CR|12Remove |15|MB |12from message newscan? |XX
! MBBSUTIL -NOCHECK option was not bypassing the online user check.
! MBBSUTIL -FCHECK was not properly marking some files OFFLINE when they
should have been.
+ MBBSUTIL -FCHECK now has an optional command after it which will cause
missing files to be removed from the file listing, instead of marked
offline. Add KILL after fcheck to enable this function:
mbbsutil -fcheck kill
<ALPHA 26 RELEASED>