diff --git a/mystic/109to110.pas b/mystic/109to110.pas index 36157ce..1743778 100644 --- a/mystic/109to110.pas +++ b/mystic/109to110.pas @@ -582,7 +582,9 @@ Begin FillChar (Config.NetAddress, SizeOf(Config.NetAddress), #0); FillChar (Config.NetDesc, SizeOf(Config.NetDesc), #0); FillChar (Config.NetDomain, SizeOf(Config.NetDomain), #0); - FillChar (Config.NetUplink, SizeOf(Config.NetUplink), 0); + FillChar (Config.NetPrimary, SizeOf(Config.NetPrimary), 0); + + Config.NetPrimary[2] := True; For A := 1 to 20 Do Begin Config.NetAddress[A].Zone := NetAddress[A].Zone; @@ -635,15 +637,15 @@ Begin Config.inetFTPDupes := inetFTPDupes; Config.inetFTPPortMin := inetFTPPortMin; Config.inetFTPPortMax := inetFTPPortMax; - Config.inetFTPAnon := inetFTPAnon; + Config.inetFTPPassive := False; Config.inetFTPTimeout := inetFTPTimeout; { new in 1.10 a11 } - Config.TemplatePath := SysPath + 'template' + PathChar; - Config.MenuPath := SysPath + 'menus' + PathChar; - Config.TextPath := SysPath + 'text' + PathChar; - Config.WebPath := SysPath + 'http' + PathChar; + Config.MenuPath := SysPath + 'menus' + PathChar; + Config.TextPath := SysPath + 'text' + PathChar; + Config.OutBoundPath := SysPath + 'echomail' + PathChar + 'out' + PathChar + 'fidonet' + PathChar; + Config.InBoundPath := SysPath + 'echomail' + PathChar + 'in' + PathChar; Config.PWChange := 0; Config.LoginAttempts := 3; diff --git a/mystic/bbs_cfg_menuedit.pas b/mystic/bbs_cfg_menuedit.pas index 63f214a..cfad1ed 100644 --- a/mystic/bbs_cfg_menuedit.pas +++ b/mystic/bbs_cfg_menuedit.pas @@ -675,6 +675,8 @@ Var Begin Result := ''; + If Not DirExists(Theme.MenuPath) Then Exit; + Box := TAnsiMenuBox.Create; List := TAnsiMenuList.Create; diff --git a/mystic/bbs_cfg_msgbase.pas b/mystic/bbs_cfg_msgbase.pas index 19c9bf1..6d4bad2 100644 --- a/mystic/bbs_cfg_msgbase.pas +++ b/mystic/bbs_cfg_msgbase.pas @@ -111,47 +111,48 @@ Begin Box.Shadow := False; Box.Header := ' Index ' + strI2S(MBase.Index) + ' '; - Box.Open (3, 5, 77, 22); + Box.Open (3, 4, 77, 22); - VerticalLine (17, 6, 21); - VerticalLine (66, 6, 21); + VerticalLine (17, 5, 20); + VerticalLine (66, 5, 21); - Form.AddStr ('N', ' Name' , 11, 6, 19, 6, 6, 30, 40, @MBase.Name, Topic + 'Message base description'); - Form.AddStr ('W', ' Newsgroup' , 6, 7, 19, 7, 11, 30, 60, @MBase.NewsName, Topic + 'Newsgroup name'); - Form.AddStr ('Q', ' QWK Name' , 7, 8, 19, 8, 10, 13, 13, @MBase.QwkName, Topic + 'Qwk Short name'); - Form.AddStr ('8', ' Echo Tag' , 7, 9, 19, 9, 10, 30, 40, @MBase.EchoTag, Topic + 'FTN EchoTag'); - Form.AddStr ('F', ' File Name' , 6, 10, 19, 10, 11, 30, 40, @MBase.FileName, Topic + 'Message base storage file name'); - Form.AddPath ('P', ' Path' , 11, 11, 19, 11, 6, 30, 80, @MBase.Path, Topic + 'Message base storage path'); - Form.AddStr ('L', ' List ACS' , 7, 12, 19, 12, 10, 30, 30, @MBase.ListACS, Topic + 'Access required to see in base list'); - Form.AddStr ('R', ' Read ACS' , 7, 13, 19, 13, 10, 30, 30, @MBase.ReadACS, Topic + 'Access required to read messages'); - Form.AddStr ('C', ' Post ACS' , 7, 14, 19, 14, 10, 30, 30, @MBase.PostACS, Topic + 'Access required to post messages'); - Form.AddStr ('Y', ' Sysop ACS' , 6, 15, 19, 15, 11, 30, 30, @MBase.SysopACS, Topic + 'Access required for Sysop access'); - Form.AddNone ('D', ' Net Address' , 4, 16, 19, 16, 13, Topic + 'Net/EchoMail Address'); - Form.AddNone ('7', ' Export To' , 6, 17, 19, 17, 11, Topic + 'Export messages to these nodes'); - Form.AddStr ('I', ' Origin' , 9, 18, 19, 18, 8, 30, 50, @MBase.Origin, Topic + 'Message base origin line'); - Form.AddStr ('S', ' Sponsor' , 8, 19, 19, 19, 9, 30, 30, @MBase.Sponsor, Topic + 'User name of base''s sponser'); - Form.AddStr ('T', ' R Template' , 5, 20, 19, 20, 12, 20, 20, @MBase.RTemplate, Topic + 'Template for full screen reader'); - Form.AddStr ('M', ' L Template' , 5, 21, 19, 21, 12, 20, 20, @MBase.ITemplate, Topic + 'Template for lightbar message list'); + Form.AddStr ('N', ' Name' , 11, 5, 19, 5, 6, 30, 40, @MBase.Name, Topic + 'Message base description'); + Form.AddStr ('W', ' Newsgroup' , 6, 6, 19, 6, 11, 30, 60, @MBase.NewsName, Topic + 'Newsgroup name'); + Form.AddStr ('Q', ' QWK Name' , 7, 7, 19, 7, 10, 13, 13, @MBase.QwkName, Topic + 'Qwk Short name'); + Form.AddStr ('8', ' Echo Tag' , 7, 8, 19, 8, 10, 30, 40, @MBase.EchoTag, Topic + 'FTN EchoTag'); + Form.AddStr ('F', ' File Name' , 6, 9, 19, 9, 11, 30, 40, @MBase.FileName, Topic + 'Message base storage file name'); + Form.AddPath ('P', ' Path' , 11, 10, 19, 10, 6, 30, 80, @MBase.Path, Topic + 'Message base storage path'); + Form.AddStr ('L', ' List ACS' , 7, 11, 19, 11, 10, 30, 30, @MBase.ListACS, Topic + 'Access required to see in base list'); + Form.AddStr ('R', ' Read ACS' , 7, 12, 19, 12, 10, 30, 30, @MBase.ReadACS, Topic + 'Access required to read messages'); + Form.AddStr ('C', ' Post ACS' , 7, 13, 19, 13, 10, 30, 30, @MBase.PostACS, Topic + 'Access required to post messages'); + Form.AddStr ('Y', ' Sysop ACS' , 6, 14, 19, 14, 11, 30, 30, @MBase.SysopACS, Topic + 'Access required for Sysop access'); + Form.AddNone ('D', ' Net Address' , 4, 15, 19, 15, 13, Topic + 'Net/EchoMail Address'); + Form.AddNone ('7', ' Export To' , 6, 16, 19, 16, 11, Topic + 'Export messages to these nodes'); + Form.AddStr ('I', ' Origin' , 9, 17, 19, 17, 8, 30, 50, @MBase.Origin, Topic + 'Message base origin line'); + Form.AddStr ('S', ' Sponsor' , 8, 18, 19, 18, 9, 30, 30, @MBase.Sponsor, Topic + 'User name of base''s sponser'); + Form.AddStr ('T', ' R Template' , 5, 19, 19, 19, 12, 20, 20, @MBase.RTemplate, Topic + 'Template for full screen reader'); + Form.AddStr ('M', ' L Template' , 5, 20, 19, 20, 12, 20, 20, @MBase.ITemplate, Topic + 'Template for lightbar message list'); - Form.AddAttr ('Q', ' Quote Color' , 53, 6, 68, 6, 13, @MBase.ColQuote, Topic + 'Color for quoted text'); - Form.AddAttr ('X', ' Text Color' , 54, 7, 68, 7, 12, @MBase.ColText, Topic + 'Color for message text'); - Form.AddAttr ('E', ' Tear Color' , 54, 8, 68, 8, 12, @MBase.ColTear, Topic + 'Color for tear line'); - Form.AddAttr ('G', ' Origin Color', 52, 9, 68, 9, 14, @MBase.ColOrigin, Topic + 'Color for origin line'); - Form.AddAttr ('K', ' Kludge Color', 52, 10, 68, 10, 14, @MBase.ColKludge, Topic + 'Color for kludge line'); - Form.AddWord ('M', ' Max Msgs' , 56, 11, 68, 11, 10, 5, 0, 65535, @MBase.MaxMsgs, Topic + 'Maximum number of message in base'); - Form.AddWord ('1', ' Max Msg Age' , 53, 12, 68, 12, 13, 5, 0, 65535, @MBase.MaxAge, Topic + 'Maximum age (days) to keep messages'); - Form.AddTog ('2', ' New Scan' , 56, 13, 68, 13, 10, 6, 0, 2, 'No Yes Forced', @MBase.DefNScan, Topic + 'Newscan default for users'); - Form.AddTog ('3', ' QWK Scan' , 56, 14, 68, 14, 10, 6, 0, 2, 'No Yes Forced', @MBase.DefQScan, Topic + 'QWKscan default for users'); - Form.AddBits ('4', ' Real Names' , 54, 15, 68, 15, 12, MBRealNames, @MBase.Flags, Topic + 'Use real names in this base?'); - Form.AddBits ('5', ' Autosigs' , 56, 16, 68, 16, 10, MBAutoSigs, @MBase.Flags, Topic + 'Allow auto signatures in this base?'); - Form.AddBits ('6', ' Kill Kludge' , 53, 17, 68, 17, 13, MBKillKludge, @MBase.Flags, Topic + 'Filter out kludge lines'); - Form.AddBits ('V', ' Private' , 57, 18, 68, 18, 9, MBPrivate, @MBase.Flags, Topic + 'Is this a private base?'); - Form.AddTog ('A', ' Base Type' , 55, 19, 68, 19, 11, 9, 0, 3, 'Local EchoMail Newsgroup Netmail', @MBase.NetType, Topic + 'Message base type'); - Form.AddTog ('B', ' Base Format' , 53, 20, 68, 20, 13, 6, 0, 1, 'JAM Squish', @MBase.BaseType, Topic + 'Message base storage format'); - Form.AddStr ('H', ' Header' , 58, 21, 68, 21, 8, 9, 20, @MBase.Header, Topic + 'Display file name of msg header'); + Form.AddAttr ('Q', ' Quote Color' , 53, 5, 68, 5, 13, @MBase.ColQuote, Topic + 'Color for quoted text'); + Form.AddAttr ('X', ' Text Color' , 54, 6, 68, 6, 12, @MBase.ColText, Topic + 'Color for message text'); + Form.AddAttr ('E', ' Tear Color' , 54, 7, 68, 7, 12, @MBase.ColTear, Topic + 'Color for tear line'); + Form.AddAttr ('G', ' Origin Color', 52, 8, 68, 8, 14, @MBase.ColOrigin, Topic + 'Color for origin line'); + Form.AddAttr ('K', ' Kludge Color', 52, 9, 68, 9, 14, @MBase.ColKludge, Topic + 'Color for kludge line'); + Form.AddWord ('M', ' Max Msgs' , 56, 10, 68, 10, 10, 5, 0, 65535, @MBase.MaxMsgs, Topic + 'Maximum number of message in base'); + Form.AddWord ('1', ' Max Msg Age' , 53, 11, 68, 11, 13, 5, 0, 65535, @MBase.MaxAge, Topic + 'Maximum age (days) to keep messages'); + Form.AddTog ('2', ' New Scan' , 56, 12, 68, 12, 10, 6, 0, 2, 'No Yes Forced', @MBase.DefNScan, Topic + 'Newscan default for users'); + Form.AddTog ('3', ' QWK Scan' , 56, 13, 68, 13, 10, 6, 0, 2, 'No Yes Forced', @MBase.DefQScan, Topic + 'QWKscan default for users'); + Form.AddTog ('A', ' Base Type' , 55, 14, 68, 14, 11, 9, 0, 3, 'Local EchoMail Newsgroup Netmail', @MBase.NetType, Topic + 'Message base type'); + Form.AddTog ('B', ' Base Format' , 53, 15, 68, 15, 13, 6, 0, 1, 'JAM Squish', @MBase.BaseType, Topic + 'Message base storage format'); + Form.AddStr ('H', ' Header' , 58, 16, 68, 16, 8, 9, 20, @MBase.Header, Topic + 'Display file name of msg header'); + Form.AddBits ('4', ' Real Names' , 54, 17, 68, 17, 12, MBRealNames, @MBase.Flags, Topic + 'Use real names in this base?'); + Form.AddBits ('5', ' Autosigs' , 56, 18, 68, 18, 10, MBAutoSigs, @MBase.Flags, Topic + 'Allow auto signatures in this base?'); + Form.AddBits ('6', ' Kill Kludge' , 53, 19, 68, 19, 13, MBKillKludge, @MBase.Flags, Topic + 'Filter out kludge lines'); + Form.AddBits ('V', ' Private' , 57, 20, 68, 20, 9, MBPrivate, @MBase.Flags, Topic + 'Is a private only base?'); + Form.AddBits ('9', ' Pvt Reply' , 55, 21, 68, 21, 11, MBPrivReply, @MBase.Flags, Topic + 'Allow private posts in public?'); Repeat - WriteXY (19, 16, 113, strPadR(strAddr2Str(Config.NetAddress[MBase.NetAddr]), 19, ' ')); + WriteXY (19, 15, 113, strPadR(strAddr2Str(Config.NetAddress[MBase.NetAddr]), 19, ' ')); Links := FileByteSize(MBase.Path + MBase.FileName + '.lnk'); @@ -160,7 +161,7 @@ Begin Else Links := 0; - WriteXY (19, 17, 113, strI2S(Links) + ' node(s)'); + WriteXY (19, 16, 113, strI2S(Links) + ' node(s)'); Case Form.Execute of 'D' : MBase.NetAddr := Configuration_EchoMailAddress(False); diff --git a/mystic/bbs_cfg_syscfg.pas b/mystic/bbs_cfg_syscfg.pas index 002651a..a0953a0 100644 --- a/mystic/bbs_cfg_syscfg.pas +++ b/mystic/bbs_cfg_syscfg.pas @@ -316,7 +316,7 @@ Begin Form.AddByte ('D', ' Dupe IP Limit', 32, 13, 49, 13, 15, 3, 2, 255, @Config.inetFTPDupes, Topic + 'Max connections with same IP'); Form.AddWord ('I', ' Data Port Min', 32, 14, 49, 14, 15, 5, 0, 65535, @Config.inetFTPPortMin, Topic + 'Passive port range (minimum)'); Form.AddWord ('A', ' Data Port Max', 32, 15, 49, 15, 15, 5, 0, 65535, @Config.inetFTPPortMax, Topic + 'Passive port range (maximum)'); - Form.AddBol ('Y', ' Allow Anonymous', 30, 16, 49, 16, 17, 3, @Config.inetFTPAnon, Topic + 'Allow anonymous users'); + Form.AddBol ('Y', ' Allow Passive', 32, 16, 49, 16, 15, 3, @Config.inetFTPPassive, Topic + 'Allow passive data transfers'); Form.Execute; Form.Free; diff --git a/mystic/bbs_common.pas b/mystic/bbs_common.pas index bb6cdf8..3c300b5 100644 --- a/mystic/bbs_common.pas +++ b/mystic/bbs_common.pas @@ -187,6 +187,8 @@ End; Function ShellDOS (ExecPath: String; Command: String) : LongInt; Begin + Session.SystemLog('DEBUG: In ShellOS for: (' + ExecPath + ') ' + Command); + Session.io.BufFlush; {$IFDEF WINDOWS} @@ -210,7 +212,11 @@ Begin Screen.SetRawMode(False); {$ENDIF} - If ExecPath <> '' Then DirChange(ExecPath); + If ExecPath <> '' Then Begin + Session.SystemLog('DEBUG: ShellOS changing DIR to: ' + ExecPath); + + DirChange(ExecPath); + End; {$IFDEF UNIX} Result := Shell (Command); @@ -218,8 +224,13 @@ Begin {$IFDEF WINDOWS} If Command <> '' Then Command := '/C' + Command; + + Session.SystemLog('DEBUG: ShellOS EXEC' + GetEnv('COMSPEC') + ' ' + Command); + Exec (GetEnv('COMSPEC'), Command); Result := DosExitCode; + + Session.SystemLog('DEBUG: ShellOS returned: ' + strI2S(Result)); {$ENDIF} {$IFDEF UNIX} diff --git a/mystic/bbs_edit_ansi.pas b/mystic/bbs_edit_ansi.pas index 6511c2c..a1246dd 100644 --- a/mystic/bbs_edit_ansi.pas +++ b/mystic/bbs_edit_ansi.pas @@ -43,8 +43,9 @@ Type Forced : Boolean; Done : Boolean; Subject : String; + Template : String; - Constructor Create (Var O: Pointer); + Constructor Create (Var O: Pointer; TemplateFile: String); Destructor Destroy; Override; Function IsAnsiLine (Line: LongInt) : Boolean; @@ -90,7 +91,7 @@ Uses bbs_Common, bbs_Ansi_MenuBox; -Constructor TEditorANSI.Create (Var O: Pointer); +Constructor TEditorANSI.Create (Var O: Pointer; TemplateFile: String); Begin Inherited Create; @@ -116,6 +117,7 @@ Begin LastLine := 1; CutPasted := False; CutTextPos := 0; + Template := TemplateFile; FillChar (CutText, SizeOf(CutText), 0); End; @@ -392,10 +394,12 @@ Begin Session.io.PromptInfo[2] := Subject; - Session.io.OutFile ('ansiedit', True, 0); + Session.io.OutFile (Template, True, 0); - WinX1 := 1; - WinX2 := 79; + WinX1 := 1; + WinX2 := 79; +// WinX1 := Session.io.ScreenInfo[1].X; +// WinX2 := Session.io.ScreenInfo[2].X; WinY1 := Session.io.ScreenInfo[1].Y; WinY2 := Session.io.ScreenInfo[2].Y; diff --git a/mystic/bbs_filebase.pas b/mystic/bbs_filebase.pas index 2d2e4a4..7082d91 100644 --- a/mystic/bbs_filebase.pas +++ b/mystic/bbs_filebase.pas @@ -143,7 +143,7 @@ Begin Res := Pos(UpCase(LineBuf[0]), 'RSZ') > 0; - //Session.SystemLog('DEBUG: DSZ Status character: ' + LineBuf[0]); +// Session.SystemLog('DEBUG: DSZ Status character: ' + LineBuf[0]); While WordPos < 11 Do Begin If LineBuf[Count] = #32 Then Begin @@ -185,12 +185,12 @@ Begin Exit; End; - //Session.SystemLog('DEBUG: DSZ Searching for: ' + FName); +// Session.SystemLog('DEBUG: DSZ Searching for: ' + FName); While Not Eof(LogFile) Do Begin DszGetFile(LogFile, FileName, Status); - //Session.SystemLog('DEBUG: DSZ GetFile returned: ' + FileName + ' (success ' + strI2S(Ord(Status)) + ')'); +// Session.SystemLog('DEBUG: DSZ GetFile returned: ' + FileName + ' (success ' + strI2S(Ord(Status)) + ')'); If strUpper(FileName) = strUpper(FName) Then Begin Result := Status; @@ -303,6 +303,8 @@ Var If Command = '@ZMODEM8' Then Protocol := New(ZmodemProtocolPTR, Init(Client, True)) Else Begin +// Session.SystemLog('DEBUG: No internal protocol found'); + {$IFDEF UNIX} Client.Free; {$ENDIF} @@ -572,6 +574,8 @@ Begin Else Command := Protocol.RecvCmd; +// Session.SystemLog('DEBUG: Exec Protocol: ' + Command); + If Command[1] = '@' Then ExecInternal Else @@ -764,10 +768,16 @@ Function TFileBase.SendFile (Data: String) : Boolean; Begin Result := False; +// Session.SystemLog('DEBUG: In SendFile checking if exists: ' + Data); + If Not FileExist(Data) Then Exit; +// Session.SystemLog('DEBUG: Calling SelectProtocol w/ use default'); + If SelectProtocol(True, False) = 'Q' Then Exit; +// Session.SystemLog('DEBUG: Calling ExecuteProtocol'); + ExecuteProtocol(2, Data); Session.io.OutRawLn (''); @@ -1344,8 +1354,12 @@ Function TFileBase.SelectProtocol (UseDefault, Batch: Boolean) : Char; Begin Result := False; +// Session.SystemLog('DEBUG: In LoadByByDefault.'); + If Key = 'Q' Then Exit; + FileMode := 66; + Reset (ProtocolFile); While Not Eof(ProtocolFile) Do Begin @@ -1358,6 +1372,8 @@ Function TFileBase.SelectProtocol (UseDefault, Batch: Boolean) : Char; End; Close(ProtocolFile); + +// Session.SystemLog('DEBUG: LoadKeyByDefault result=' + Session.io.OutYN(Result)); End; Var @@ -1369,6 +1385,8 @@ Begin SavedP2 := Session.io.PromptInfo[2]; Result := Session.User.ThisUser.Protocol; +//Session.SystemLog('DEBUG: In SelectProtocol'); + If Not LoadByKey(Result) Then Begin Keys := 'Q'; @@ -1418,6 +1436,8 @@ Var A : Byte; Temp2 : String[60]; Begin +// Session.SystemLog('DEBUG: In ExecuteArchive'); + If Temp = '' Then Case GetArchiveType(FName) of 'A' : Temp := 'ARJ'; @@ -1431,6 +1451,10 @@ Begin '?' : Temp := strUpper(JustFileExt(FName)); End; +// Session.SystemLog('DEBUG: ExecArc found type ' + Temp); + + FileMode := 66; + Reset (ArcFile); Repeat @@ -1441,6 +1465,8 @@ Begin Read (ArcFile, Arc); +// Session.SystemLog('DEBUG: ExecArc read one'); + If (Not Arc.Active) or ((Arc.OSType <> OSType) and (Arc.OSType <> 3)) Then Continue; @@ -1449,6 +1475,8 @@ Begin Close (ArcFile); +// Session.SystemLog('DEBUG: ExecArc found config for ' + Arc.Ext); + Case Mode of 1 : Temp2 := Arc.Pack; 2 : Temp2 := Arc.Unpack; @@ -1472,6 +1500,8 @@ Begin Inc(A); End; + Session.SystemLog('DEBUG: ExecArc build exec for: ' + Temp); + ShellDOS ('', Temp); End; diff --git a/mystic/bbs_general.pas b/mystic/bbs_general.pas index 1168cbe..12478b5 100644 --- a/mystic/bbs_general.pas +++ b/mystic/bbs_general.pas @@ -58,7 +58,7 @@ Var Editor : TEditorANSI; Count : LongInt; Begin - Editor := TEditorANSI.Create(Pointer(Session)); + Editor := TEditorANSI.Create(Pointer(Session), Template); For Count := 1 to Lines Do Editor.SetLineText (Count, Session.Msgs.MsgText[Count]); diff --git a/mystic/bbs_io.pas b/mystic/bbs_io.pas index 4d9864d..a5db011 100644 --- a/mystic/bbs_io.pas +++ b/mystic/bbs_io.pas @@ -991,6 +991,7 @@ Begin If (Color < 8) and (CurFG > 7) Then Prefix := '0;'; If (Color > 7) and (CurFG < 8) Then Prefix := '1;'; + If Color > 7 Then Dec(Color, 8); Case Color of @@ -1035,6 +1036,7 @@ Begin End; End; +(* Function TBBSIO.Attr2Ansi (Attr: Byte) : String; Begin Result := ''; @@ -1043,6 +1045,67 @@ Begin Result := Pipe2Ansi(Attr AND $F) + Pipe2Ansi(((Attr SHR 4) AND 7) + 16); End; +*) + +Function TBBSIO.Attr2Ansi (Attr: Byte) : String; +Const + AnsiTable : String[8] = '04261537'; +Var + OldFG : LongInt; + OldBG : LongInt; + FG : LongInt; + BG : LongInt; + + Procedure AddSep (Ch: Char); + Begin + If Length(Result) > 0 Then + Result := Result + ';'; + + Result := Result + Ch; + End; + +Begin + Result := ''; + + If (Attr = Screen.TextAttr) or (Graphics = 0) Then Exit; + + FG := Attr and $F; + BG := Attr shr 4; + OldFG := Screen.TextAttr and $F; + OldBG := Screen.TextAttr shr 4; + + If (OldFG <> 7) or (FG = 7) or ((OldFG > 7) and (FG < 8)) or ((OldBG > 7) and (BG < 8)) Then Begin + Result := '0'; + OldFG := 7; + OldBG := 0; + End; + + If (FG > 7) and (OldFG < 8) Then Begin + AddSep('1'); + + OldFG := OldFG or 8; + End; + +// If (BG and 8) <> (OldBG and 8) Then Begin +// AddSep('5'); + +// OldBG := OldBG or 8; +// End; + + If (FG <> OldFG) Then Begin + AddSep('3'); + + Result := Result + AnsiTable[(FG and 7) + 1]; + End; + + If (BG <> OldBG) Then Begin + AddSep('4'); + + Result := Result + AnsiTable[(BG and 7) + 1]; + End; + + Result := #27 + '[' + Result + 'm'; +End; Procedure TBBSIO.AnsiColor (A : Byte); Begin @@ -1819,6 +1882,16 @@ Var pWrite (Ch); End; + Procedure Clear; + Begin + Str := ''; + StrPos := 1; + Junk := 1; + CurPos := 1; + + ReDraw; + End; + Begin If UseInLimit Then Begin Field := InLimit; @@ -1945,6 +2018,12 @@ Begin Case Ch of #02 : ReDraw; #08 : If StrPos > 1 Then Begin + If (Default <> '') And (Str = Default) Then Begin + Clear; + + Continue; + End; + Dec (StrPos); Delete (Str, StrPos, 1); @@ -1963,15 +2042,12 @@ Begin End; End; #13 : Break; - ^Y : Begin - Str := ''; - StrPos := 1; - Junk := 1; - CurPos := 1; - ReDraw; - End; + ^Y : Clear; #32.. - #254: If Length(Str) < Max Then + #254: Begin + If (Default <> '') And (Str = Default) Then Clear; + + If Length(Str) < Max Then Case Mode of 1 : AddChar (Ch); 2 : AddChar (UpCase(Ch)); @@ -2013,6 +2089,7 @@ Begin 7 : AddChar(LoCase(Ch)); 9 : AddChar(Ch); End; + End; End; Until False; diff --git a/mystic/bbs_menus.pas b/mystic/bbs_menus.pas index 21bbad5..4ed89fc 100644 --- a/mystic/bbs_menus.pas +++ b/mystic/bbs_menus.pas @@ -574,56 +574,63 @@ Begin If ReDraw Then Break; End; - Case Ch of - #08 : If Length(Temp) > 0 Then Begin - Dec (Temp[0]); + If Session.io.IsArrow Then Begin + If Pos(Ch, ExtKeys) > 0 Then Begin - TBBSCore(Owner).io.OutBS(1, True); - End; - #09, - #27 : If Pos(Ch, ExtKeys) > 0 Then Begin - Translate; + Translate; + Break; + End; + End Else + Case Ch of + #08 : If Length(Temp) > 0 Then Begin + Dec (Temp[0]); - Break; - End; - #13 : Begin - If Temp = '' Then Temp := 'ENTER'; - - Break; - End; - #32.. - #126: If Length(Temp) < mysMaxMenuInput Then Begin - If TBBSCore(Owner).io.IsArrow And (Pos(Ch, ExtKeys) > 0) Then Begin + TBBSCore(Owner).io.OutBS(1, True); + End; + #09, + #27 : If Pos(Ch, ExtKeys) > 0 Then Begin Translate; + Break; End; + #13 : Begin + If Temp = '' Then Temp := 'ENTER'; - If UseHotKeys Then Begin - ValidKey := False; - Found := False; - Count := 0; - - Repeat - Inc (Count); - - If SpecialKey(Data.Item[Count]^.HotKey) Or Not TBBSCore(Owner).User.Access(Data.Item[Count]^.Access) Then Continue; - - Found := Data.Item[Count]^.HotKey = Temp + UpCase(Ch); - - If Not ValidKey Then - ValidKey := Temp + UpCase(Ch) = Copy(Data.Item[Count]^.HotKey, 1, Length(Temp + Ch)); - Until Found or (Count >= Data.NumItems); - - If Found And (TBBSCore(Owner).User.Access(Data.Item[Count]^.Access)) Then Begin - AddChar; + Break; + End; + #32.. + #126: If Length(Temp) < mysMaxMenuInput Then Begin + If TBBSCore(Owner).io.IsArrow And (Pos(Ch, ExtKeys) > 0) Then Begin + Translate; Break; + End; + + If UseHotKeys Then Begin + ValidKey := False; + Found := False; + Count := 0; + + Repeat + Inc (Count); + + If SpecialKey(Data.Item[Count]^.HotKey) Or Not TBBSCore(Owner).User.Access(Data.Item[Count]^.Access) Then Continue; + + Found := Data.Item[Count]^.HotKey = Temp + UpCase(Ch); + + If Not ValidKey Then + ValidKey := Temp + UpCase(Ch) = Copy(Data.Item[Count]^.HotKey, 1, Length(Temp + Ch)); + Until Found or (Count >= Data.NumItems); + + If Found And (TBBSCore(Owner).User.Access(Data.Item[Count]^.Access)) Then Begin + AddChar; + Break; + End Else + If ValidKey Then AddChar; End Else - If ValidKey Then AddChar; - End Else - AddChar; - End; + AddChar; + End; + End; End; - End; If Data.Info.CharType <> 2 Then TBBSCore(Owner).io.OutRawLn(''); diff --git a/mystic/bbs_msgbase.pas b/mystic/bbs_msgbase.pas index a72a72a..a54579e 100644 --- a/mystic/bbs_msgbase.pas +++ b/mystic/bbs_msgbase.pas @@ -466,6 +466,12 @@ Begin Continue; End; + If TempMsg^.IsPriv And Not Session.User.IsThisUser(TempMsg^.GetTo) Then Begin + TempMsg^.SeekNext; + + Continue; + End; + If NoRead And Session.User.IsThisUser(TempMsg^.GetTo) And TempMsg^.IsRcvd Then Begin TempMsg^.SeekNext; @@ -634,7 +640,7 @@ Begin End; If MBase.NetType > 0 Then Begin - Msg^.DoStringLn (#13 + '--- ' + mysSoftwareID + ' BBS v' + mysVersion + ' (' + OSID + ')'); + Msg^.DoStringLn (#13 + '--- ' + mysSoftwareID + ' v' + mysVersion + ' (' + OSID + ')'); Msg^.DoStringLn (' * Origin: ' + ResolveOrigin(MBase) + ' (' + strAddr2Str(Msg^.GetOrigAddr) + ')'); End; End; @@ -1172,6 +1178,7 @@ Var Lines : SmallInt; Total : LongInt; ReplyBase : RecMessageBase; + IsPrivate : Boolean; Begin ReplyBase := MBase; @@ -1227,6 +1234,11 @@ Begin Set_Node_Action (Session.GetPrompt(349)); + IsPrivate := ReplyBase.Flags AND MBPrivate <> 0; + + If (ReplyBase.Flags AND MBPrivate = 0) AND (ReplyBase.Flags AND MBPrivReply <> 0) Then + IsPrivate := Session.io.GetYN(Session.GetPrompt(514), False); + Repeat If ListMode = 0 Then Session.io.OutFull (Session.GetPrompt(407)) @@ -1237,7 +1249,7 @@ Begin If ToWho = '' Then Exit; - If Not Email Then Break; + If Not (Email or IsPrivate) Then Break; If Not Session.User.FindUser(ToWho, False) Then Begin Session.io.PromptInfo[1] := ToWho; @@ -1328,7 +1340,7 @@ Begin AssignMessageData(MsgNew, ReplyBase); Case ReplyBase.NetType of - 2 : MsgNew^.SetTo('All'); + 2 : MsgNew^.SetTo('All'); //Lang++ 3 : Begin MsgNew^.SetDest (Addr); MsgNew^.SetOrig (GetMatchedAddress(Config.NetAddress[ReplyBase.NetAddr], Addr)); @@ -1341,8 +1353,9 @@ Begin MsgNew^.SetTo (ToWho); End; - MsgNew^.SetSubj (Subj); + MsgNew^.SetSubj (Subj); MsgNew^.SetRefer (MsgBase^.GetMsgNum); + MsgNew^.SetPriv (IsPrivate); AppendMessageText (MsgNew, Lines, ReplyID); @@ -1408,15 +1421,17 @@ Begin Repeat Session.io.PromptInfo[1] := MsgBase^.GetTo; Session.io.PromptInfo[2] := MsgBase^.GetSubj; + Session.io.PromptInfo[3] := Session.io.OutYN(MsgBase^.IsSent); If MBase.NetType = 3 Then Begin MsgBase^.GetDest(DestAddr); + Session.io.PromptInfo[1] := Session.io.PromptInfo[1] + ' (' + strAddr2Str(DestAddr) + ')'; End; Session.io.OutFull (Session.GetPrompt(296)); - Case Session.io.OneKey('ABQ!', True) of + Case Session.io.OneKey('ABCQ!', True) of 'A' : Begin Session.io.OutFull (Session.GetPrompt(297)); @@ -1443,6 +1458,7 @@ Begin MsgBase^.SetSubj(Session.io.GetInput(50, 50, 11, MsgBase^.GetSubj)); End; + 'C' : MsgBase^.SetSent(NOT MsgBase^.IsSent); '!' : Begin Temp1 := MsgBase^.GetSubj; @@ -1712,7 +1728,10 @@ Var MsgBase^.MsgStartUp; Case ScanMode of - 0 : Res := True; + 0 : If MsgBase^.IsPriv Then + Res := Session.User.IsThisUser(MsgBase^.GetTo) or Session.User.IsThisUser(MsgBase^.GetFrom) + Else + Res := True; 1 : Res := Session.User.IsThisUser(MsgBase^.GetTo); 2 : Res := Session.User.IsThisUser(MsgBase^.GetTo) or Session.User.IsThisUser(MsgBase^.GetFrom); 3 : Begin @@ -2900,6 +2919,7 @@ Var Forced : Boolean; Old : RecMessageBase; SaveGroup : Boolean; + IsPrivate : Boolean; Begin Old := MBase; SaveGroup := Session.User.IgnoreGroup; @@ -2932,10 +2952,14 @@ Begin Set_Node_Action (Session.GetPrompt(349)); - MsgTo := ''; - MsgSubj := ''; - MsgAddr := ''; - Forced := False; + MsgTo := ''; + MsgSubj := ''; + MsgAddr := ''; + Forced := False; + IsPrivate := MBase.Flags AND MBPrivate <> 0; + + If (MBase.Flags AND MBPrivate = 0) AND (MBase.Flags AND MBPrivReply <> 0) Then + IsPrivate := Session.io.GetYN(Session.GetPrompt(513), False); For A := 1 to strWordCount(Data, ' ') Do Begin TempStr := strWordGet(A, Data, ' '); @@ -2973,7 +2997,7 @@ Begin If Not strStr2Addr(MsgAddr, DestAddr) Then MsgTo := ''; End; End Else - If MBase.Flags and MBPrivate <> 0 Then Begin + If IsPrivate Then Begin If MsgTo = '' Then Begin Session.io.OutFull (Session.GetPrompt(450)); @@ -3044,6 +3068,7 @@ Begin MsgBase^.SetTo (MsgTo); MsgBase^.SetSubj (MsgSubj); + MsgBase^.SetPriv (IsPrivate); If MBase.NetType = 3 Then Begin MsgBase^.SetDest (DestAddr); @@ -3747,7 +3772,7 @@ Begin Msg^.DoStringLn(MsgText[Count]); If mArea.NetType > 0 Then Begin - Msg^.DoStringLn (#13 + '--- ' + mysSoftwareID + ' BBS v' + mysVersion + ' (' + OSID + ')'); + Msg^.DoStringLn (#13 + '--- ' + mysSoftwareID + ' v' + mysVersion + ' (' + OSID + ')'); Msg^.DoStringLn (' * Origin: ' + ResolveOrigin(mArea) + ' (' + strAddr2Str(Msg^.GetOrigAddr) + ')'); End; @@ -4245,7 +4270,7 @@ Begin FileMode := 66; Old := MBase; - Temp := strPadR('Produced By ' + mysSoftwareID + ' BBS v' + mysVersion + '. ' + CopyID, 128, ' '); + Temp := strPadR('Produced By ' + mysSoftwareID + ' v' + mysVersion + '. ' + CopyID, 128, ' '); Assign (DataFile, Session.TempPath + 'messages.dat'); ReWrite (DataFile, 1); @@ -4303,11 +4328,23 @@ Begin If FileExist(Config.QwkNews) Then FileCopy(Config.qwkNews, Session.TempPath + JustFile(Config.qwkNews)); If FileExist(Config.QwkGoodbye) Then FileCopy(Config.qwkGoodbye, Session.TempPath + JustFile(Config.qwkGoodbye)); +// Session.SystemLog('DEBUG: Archiving QWK packet'); + If Session.LocalMode Then Begin Session.FileBase.ExecuteArchive (Config.QWKPath + Temp, Session.User.ThisUser.Archive, Session.TempPath + '*', 1); Session.io.OutFullLn (Session.GetPrompt(235)); End Else Begin +// Session.SystemLog('DEBUG: Arc QWK: Nonlocal mode'); + Session.FileBase.ExecuteArchive (Session.TempPath + Temp, Session.User.ThisUser.Archive, Session.TempPath + '*', 1); + +// If FileExist(Session.TempPath + Temp) Then +// Session.SystemLog('DEBUG: QWK successfully archived') +// Else +// Session.SystemLog('DEBUG: Could not find QWK archived packet'); + +// Session.SystemLog('DEBUG: QWK calling SendFile on "' + Temp + '"'); + Session.FileBase.SendFile (Session.TempPath + Temp); End; diff --git a/mystic/bbs_user.pas b/mystic/bbs_user.pas index 29ae462..19b664b 100644 --- a/mystic/bbs_user.pas +++ b/mystic/bbs_user.pas @@ -1201,7 +1201,7 @@ Begin Halt(0); End; - Session.io.OutFullLn ('|CL' + mysSoftwareID + ' BBS v' + mysVersion + ' for ' + OSID + ' Node |ND'); + Session.io.OutFullLn ('|CL' + mysSoftwareID + ' v' + mysVersion + ' for ' + OSID + ' Node |ND'); Session.io.OutFullLn (CopyID); If Config.DefTermMode = 0 Then diff --git a/mystic/default.txt b/mystic/default.txt index 0e437d1..ada8773 100644 --- a/mystic/default.txt +++ b/mystic/default.txt @@ -566,7 +566,7 @@ 294 |CR|12Delete this BBS from the list? |11 295 |CR|12You did not add this BBS entry. ; editing message display -296 |CL|14Message Editor|CR|CR|03A. To : |&1|CRB. Subj : |&2|CR|CR|09Command: (!) Edit text, (Q)uit: |XX +296 |16|CL|09|17 ° |15Message Editing |$X79 |16|CR|CR|09(|11A|09) |03To: |11|&1|CR|09(|11B|09) |03Subject: |11|&2|CR|09(|11C|09) |03Sent: |11|&3|CR|CR|09Edit option (|11!|09) Edit text, (|11Q|09)uit? |11 ; editing message to 297 |CR|09To: |XX ; editing message net address @@ -1014,3 +1014,7 @@ 511 |CR|09Select message base for reply [|10?|09/|10List|09]: |11 ; Message "replying to X base" prompt &1=base name 512 |CR|03Posting reply message to base |11|&1|03. +; Message post: "post msg as private" in pub/priv type base +513 |CR|12Post this as a private message? |11 +; Message reply: "post msg as private" in pub/priv type base +514 |CR|12Post this as a private message? |11 diff --git a/mystic/mbbsutil.pas b/mystic/mbbsutil.pas index ebf7a80..f66f7c5 100644 --- a/mystic/mbbsutil.pas +++ b/mystic/mbbsutil.pas @@ -1107,7 +1107,7 @@ Begin TextAttr := 7; WriteLn; - WriteLn ('MBBSUTIL: ', mysSoftwareID, ' BBS Utilities Version ', mysVersion, ' (', OSID, ')'); + WriteLn ('MBBSUTIL: ', mysSoftwareID, ' Utilities Version ', mysVersion, ' (', OSID, ')'); WriteLn ('Copyright (C) ', mysCopyYear, ' By James Coyle. All Rights Reserved.'); WriteLn; diff --git a/mystic/mis_client_ftp.pas b/mystic/mis_client_ftp.pas index 0f50597..1dc8b01 100644 --- a/mystic/mis_client_ftp.pas +++ b/mystic/mis_client_ftp.pas @@ -1,7 +1,8 @@ -{$I M_OPS.PAS} - Unit MIS_Client_FTP; +{$I M_OPS.PAS} +{.$DEFINE FTPDEBUG} + // does not send file/directory datestamps // does not support uploading (need to make bbs functions generic for this // and for mbbsutil -fupload command) @@ -102,6 +103,22 @@ Const re_DLLimit = '550 Download limit would be exceeded'; re_DLRatio = '550 Download/upload ratio would be exceeded'; +{$IFDEF FTPDEBUG} +Procedure LOG (Str: String); +Var + T : Text; +Begin + Assign (T, 'ftpdebug.txt'); + {$I-} Append(T); {$I+} + + If IoResult <> 0 Then ReWrite(T); + + WriteLn(T, Str); + + Close(T); +End; +{$ENDIF} + Function CreateFTP (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TIOSocket) : TServerClient; Begin Result := TFTPServer.Create(Owner, CliSock); @@ -261,6 +278,9 @@ Begin If IsPassive Then Begin WaitSock := TIOSocket.Create; + WaitSock.FTelnetServer := False; + WaitSock.FTelnetClient := False; + WaitSock.WaitInit(DataPort); DataSocket := WaitSock.WaitConnection; @@ -419,18 +439,34 @@ Var WaitSock : TIOSocket; Begin If LoggedIn Then Begin + If Not bbsConfig.inetFTPPassive Then Begin + Client.WriteLine(re_BadCommand); + Exit; + End; + DataPort := Random(bbsConfig.inetFTPPortMax - bbsConfig.inetFTPPortMin) + bbsConfig.inetFTPPortMin; + {$IFDEF FTPDEBUG} LOG('PASV on host ' + Client.HostIP + ' port ' + strI2S(DataPort)); {$ENDIF} + Client.WriteLine(re_PassiveOK + '(' + strReplace(Client.HostIP, '.', ',') + ',' + strI2S(WordRec(DataPort).Hi) + ',' + strI2S(WordRec(DataPort).Lo) + ').'); IsPassive := True; WaitSock := TIOSocket.Create; + WaitSock.FTelnetServer := False; + WaitSock.FTelnetClient := False; + + {$IFDEF FTPDEBUG} LOG('PASV Init'); {$ENDIF} + WaitSock.WaitInit(DataPort); + {$IFDEF FTPDEBUG} LOG('PASV Wait'); {$ENDIF} + DataSocket := WaitSock.WaitConnection; + {$IFDEF FTPDEBUG} LOG('PASV WaitDone'); {$ENDIF} + If Not Assigned(DataSocket) Then Begin WaitSock.Free; Client.WriteLine(re_NoData); @@ -536,12 +572,20 @@ Var DirFile : TBufFile; Dir : RecFileList; Begin + {$IFDEF FTPDEBUG} LOG('LIST Calling FindDirectory'); {$ENDIF} + If LoggedIn Then Begin TempPos := FindDirectory(TempBase); + {$IFDEF FTPDEBUG} LOG('Back From FindDirectory. Result ' + strI2S(TempPos)); {$ENDIF} + If TempPos = -1 Then Begin + {$IFDEF FTPDEBUG} LOG('Opening data session'); {$ENDIF} + OpenDataSession; + {$IFDEF FTPDEBUG} LOG('Back from data session'); {$ENDIF} + FBaseFile := TBufFile.Create(FileBufSize); If FBaseFile.Open(bbsConfig.DataPath + 'fbases.dat', fmOpen, fmRWDN, SizeOf(RecFileBase)) Then Begin @@ -754,6 +798,8 @@ Begin cmdREIN; Repeat + {$IFDEF FTPDEBUG} LOG('Execute loop'); {$ENDIF} + If Client.WaitForData(bbsConfig.inetFTPTimeout * 1000) = 0 Then Break; If Terminated Then Exit; @@ -767,6 +813,8 @@ Begin Else Data := ''; + {$IFDEF FTPDEBUG} LOG('Cmd: ' + Cmd + ' Data: ' + Data); {$ENDIF} + If Cmd = 'CDUP' Then cmdCDUP Else If Cmd = 'CWD' Then cmdCWD Else If Cmd = 'EPRT' Then cmdEPRT Else diff --git a/mystic/records.pas b/mystic/records.pas index 2aa52b0..4bab4b4 100644 --- a/mystic/records.pas +++ b/mystic/records.pas @@ -21,7 +21,7 @@ // protocol: active, no 4gig limitation, can batch, etc Const - mysSoftwareID = 'Mystic'; // no idea + mysSoftwareID = 'Mystic BBS'; mysCopyYear = '1997-2013'; // its been a long time! mysVersion = '1.10 A33'; // current version mysDataChanged = '1.10 A11'; // version of last records change @@ -36,7 +36,7 @@ Const {$IFDEF LINUX} PathChar = '/'; LineTerm = #10; - OSID = 'Linux'; + {$IFDEF CPUARM} OSID = 'Raspberry Pi'; {$ELSE} OSID = 'Linux'; {$ENDIF} OSType = 1; {$ENDIF} @@ -59,7 +59,7 @@ Const mysMaxMenuCmds = 25; // Max menu commands per item mysMaxMenuInput = 12; mysMaxMenuStack = 8; - mysMaxThemeText = 512; + mysMaxThemeText = 514; fn_SemFileEcho = 'echomail.now'; fn_SemFileNews = 'newsmail.now'; @@ -306,7 +306,7 @@ Type inetFTPDupes : Byte; inetFTPPortMin : Word; inetFTPPortMax : Word; - inetFTPAnon : Boolean; + inetFTPPassive : Boolean; inetFTPTimeout : Word; inetNNTPUse : Boolean; inetNNTPPort : Word; @@ -475,7 +475,7 @@ Const MBAutosigs = $00000004; // 3 MBNoAttach = $00000008; // 4 MBPrivate = $00000010; // 5 - MBCrossPost = $00000020; // 6 + MBPrivReply = $00000020; // 6 Type RecMessageBase = Record // MBASES.DAT diff --git a/mystic/todo.pas b/mystic/todo.pas index fae1583..8609989 100644 --- a/mystic/todo.pas +++ b/mystic/todo.pas @@ -26,6 +26,10 @@ BUGS AND POSSIBLE ISSUES FUTURE / IDEAS / WORK IN PROGRESS / NOTES ========================================= +- Fix up new FS editor to use passed template and editor contraints. + - Test with file description editor. +- ACS to allow "selecable reply base" +- Strip pipe colors/ANSI from message option? - AREAS.BBS import? - PGUP/DOWN moves bases in message base editor? - AreaFix diff --git a/mystic/whatsnew.txt b/mystic/whatsnew.txt index 1b13f27..5b80643 100644 --- a/mystic/whatsnew.txt +++ b/mystic/whatsnew.txt @@ -3272,3 +3272,40 @@ + Message base editor now has a Move command. You must first Copy a message base, and then move to where you want to move it to and then /M to move it. + + + FTP server now has the option to allow passive data transfers or not, and + this has replaced the "Allow Anonymous" which does not exist at this time. + Please review your configuration. If you or users have issues with passive + turn it off. The default should set it to off now. + + + When editing a posted message, Mystic now allows the option to set the + echomail "sent" flag. Prompt #296 has been updated for this new option. A + new default follows: + + ; editing message display + 296 |16|CL|09|17 ° |15Message Editing |$X79 |16|CR|CR|09(|11A|09) |03To: |11|&1|CR|09(|11B|09) |03Subject: |11|&2|CR|09(|11C|09) |03Sent: |11|&3|CR|CR|09Edit option (|11!|09) Edit text, (|11Q|09)uit? |11 + + + When Mystic gives an input prompt with a default text value, pressing a + backspace will now automatically erase the default. Likewise, typing any + key will erase the default. + + + Added a new flag into message bases called Pvt Reply. If this is set to + true then Mystic will allow private replies/posts to a message based + marked as public. This basically creates a "public/private" type base. + + Two new prompts are added for this: + + ; Message post: "post msg as private" in pub/priv type base + 513 |CR|12Post this as a private message? |11 + + ; Message reply: "post msg as private" in pub/priv type base + 514 |CR|12Post this as a private message? |11 + + ! When using extended hotkeys in a standard menu (ie UP,DOWN,PGUP,DOWN,etc) + Mystic was bleeding input during some events, and also allowing input + and redrawing the menu when invalid input was entered. This is now fixed. + + + Further optimized the on-the-fly ANSI optimization generated by Mystic. I + think its probably not possible to make it more efficient now. + +