1 Unit PTMsg;
2 
3 InterFace
4 
5 Uses
6   DOS,
7   Types, GeneralP,
8   Log, MKMsgAbs, MKGlobT,
9   PTRegKey, TickType, TickCons, PTVar, PTProcs;
10 
11 Procedure ProcessMail;
12 
13 Procedure ConnectArea(Name: String; DReScan: Boolean; RSParams: String);
14 Procedure ReScan(Name, Params: String);
15 Procedure DisConnectArea(Name: String);
16 Procedure SendRsp(_Type: Word; Params: String);
17 Procedure SetActive(Act: Boolean);
18 Procedure SetPack(Pack: String);
19 Procedure AKAMatch(InAddr: TNetAddr; var OutAddr: TNetAddr);
20 
21 Implementation
22 
23 Procedure ProcessMail;
24 Var
25   MKAddr: AddrType;
26   A1: TNetAddr;
27   Pwd: String;
28   s1: String;
29   DoReScan: Boolean;
30   ReScanParams: String;
31   DoDelReq: Boolean;
32   Body: PString80List;
33   CurBody: PString80List;
34 
35   Begin
36   DoReScan := False;
37   ReScanParams := '';
38   DoDelReq := Cfg^.DelReq;
39   With NM^ do
40     Begin
41     LogSetCurLevel(LogHandle, 3);
42     LogWriteLn(LogHandle, 'Processing msg #'+IntToStr(GetMsgNum));
43 
44     MsgTxtStartUp;
45     SetRcvd(True);
46     ReWriteHdr;
47 
48     GetOrig(MKAddr);
49     MKAddr2TNetAddr(MKAddr, A1);
50     LogSetCurLevel(LogHandle, 2);
51     LogWriteLn(LogHandle, 'From: '+GetFrom+' ('+Addr2Str(A1)+')');
52 
53     GetDest(MKAddr);
54     MKAddr2TNetAddr(MKAddr, A1);
55     LogSetCurLevel(LogHandle, 5);
56     LogWriteLn(LogHandle, 'To: '+GetTo+' ('+Addr2Str(A1)+')');
57 
58     GetOrig(MKAddr);
59     MKAddr2TNetAddr(MKAddr, A1);
60     Pwd := UpStr(GetSubj);
61 
62     If ((A1.Zone = 0) and (A1.Net = 0) and (A1.Node = 0)) then
63       Begin
64       LogSetCurLevel(LogHandle, 2);
65       LogWriteLn(LogHandle, 'Unlisted sender: '+Addr2Str(A1));
66       SendRsp(rs_Unlisted, '');
67       Exit;
68       End;
69     CurUser := Cfg^.Users;
70     While (not CompAddr(CurUser^.Addr, A1)) and (CurUser^.Next <> Nil) do
71       CurUser := CurUser^.Next;
72     If (not CompAddr(CurUser^.Addr, A1)) then
73       Begin
74       LogSetCurLevel(LogHandle, 2);
75       LogWriteLn(LogHandle, 'Unlisted sender: '+Addr2Str(A1));
76       SendRsp(rs_Unlisted, '');
77       Exit;
78       End;
79     If (UpStr(CurUser^.Pwd) <> Pwd) then
80       Begin
81       LogSetCurLevel(LogHandle, 2);
82       LogWriteLn(LogHandle, 'Wrong password! User: "'+CurUser^.Pwd+'" Msg: "'+Pwd+'"');
83       SendRsp(rs_WrongPwd, Pwd);
84       Exit;
85       End;
86 
87     {read mail into stringlist}
88     New(Body); Body^.s := ''; Body^.Next := NIL;
89     CurBody := Body;
90     While not EOM do
91      Begin
92      New(CurBody^.Next);
93      CurBody := CurBody^.Next;
94      CurBody^.Next := NIL;
95      CurBody^.s := GetString;
96      End;
97     CurBody := Body;
98 
99     While (CurBody^.Next <> NIL) do
100       Begin
101       CurBody := CurBody^.Next;
102       s1 := UpStr(CurBody^.s);
103       s1 := KillTrailingSpcs(KillLeadingSpcs(s1));
104       If (s1[1] = #1) then Continue;
105       If (s1 = '') then Continue;
106       If (s1 = #10) then Continue;
107       If (s1[1] = '%') then
108         Begin
109         Delete(s1, 1, 1);
110         If Pos('RESCAN', s1) = 1 then
111           Begin
112           DoRescan := True;
113           If (Length(s1) > 7) then ReScanParams := Copy(s1, 8, Length(s1) - 8)
114           Else ReScanParams := '';
115           End
116         Else If Pos('PAUSE', s1) = 1 then
117           Begin
118           If ((CurUser^.May and um_Pause) = 0) then
119             Begin
120             LogSetCurLevel(LogHandle, 2);
121             LogWriteLn(LogHandle, 'User isn''t allowed to pause');
122             SendRsp(rs_NoPause, '');
123             End
124           Else
125             Begin
126             SetActive(False);
127             LogSetCurLevel(LogHandle, 3);
128             LogWriteLn(LogHandle, 'paused.');
129             SendRsp(rs_Pause, '');
130             End;
131           End
132         Else If Pos('RESUME', s1) = 1 then
133           Begin
134           If ((CurUser^.May and um_Pause) = 0) then
135             Begin
136             LogSetCurLevel(LogHandle, 2);
137             LogWriteLn(LogHandle, 'User isn''t allowed to resume');
138             SendRsp(rs_NoPause, '');
139             End
140           Else
141             Begin
142             SetActive(True);
143             LogSetCurLevel(LogHandle, 3);
144             LogWriteLn(LogHandle, 'resumed.');
145             SendRsp(rs_Resume, '');
146             End;
147           End
148         Else If Pos('PACK', s1) = 1 then
149           Begin
150           If ((CurUser^.May and um_Compression) = 0) then
151             Begin
152             LogSetCurLevel(LogHandle, 2);
153             LogWriteLn(LogHandle, 'User isn''t allowed change compression');
154             SendRsp(rs_NoComp, '');
155             End
156           Else
157             Begin
158             Delete(s1, 1, 5);
159             SetPack(s1);
160             End;
161           End
162         Else If Pos('COMPRESSION', s1) = 1 then
163           Begin
164           If ((CurUser^.May and um_Compression) = 0) then
165             Begin
166             LogSetCurLevel(LogHandle, 2);
167             LogWriteLn(LogHandle, 'User isn''t allowed change compression');
168             SendRsp(rs_NoComp, '');
169             End
170           Else
171             Begin
172             Delete(s1, 1, 12);
173             SetPack(s1);
174             End;
175           End
176         Else If Pos('COMPRESS', s1) = 1 then
177           Begin
178           If ((CurUser^.May and um_Compression) = 0) then
179             Begin
180             LogSetCurLevel(LogHandle, 2);
181             LogWriteLn(LogHandle, 'User isn''t allowed change compression');
182             SendRsp(rs_NoComp, '');
183             End
184           Else
185             Begin
186             Delete(s1, 1, 9);
187             SetPack(s1);
188             End;
189           End
190         Else If (Pos('LIST', s1) = 1) then
191           Begin
192           SendRsp(rs_List, '');
193           LogSetCurLevel(LogHandle, 3);
194           LogWriteLn(LogHandle, 'sent list of available areas');
195           End
196         Else If (Pos('QUERY', s1) = 1) then
197           Begin
198           SendRsp(rs_Query, '');
199           LogSetCurLevel(LogHandle, 3);
200           LogWriteLn(LogHandle, 'sent list of connected areas');
201           End
202         Else If (Pos('UNLINKED', s1) = 1) then
203           Begin
204           SendRsp(rs_Unlinked, '');
205           LogSetCurLevel(LogHandle, 3);
206           LogWriteLn(LogHandle, 'sent list of disconnected areas');
207           End
208         Else If (Pos('HELP', s1) = 1) then
209           Begin
210           SendRsp(rs_Help, '');
211           LogSetCurLevel(LogHandle, 3);
212           LogWriteLn(LogHandle, 'sent help.');
213           End
214         Else If (Pos('QUIT', s1) = 1) then
215           Begin
216           Break;
217           End
218         Else If (Pos('NOTE', s1) = 1) then
219           Begin
220           Break;
221           LogSetCurLevel(LogHandle, 3);
222           LogWriteLn(LogHandle, '%NOTE');
223           DoDelReq := False;
224           End
225         Else
226           Begin
227           LogSetCurLevel(LogHandle, 2);
228           LogWriteLn(LogHandle, 'Unknown command "'+s1+'"');
229           SendRsp(rs_UnKnownCmd, s1);
230           SendRsp(rs_Help, '');
231           End;
232         End
233       Else If (Copy(s1, 1, 3) = '---') then
234         Begin
235         Break;
236         End
237       Else If (s1[1] = '-') then
238         Begin
239         Delete(s1, 1, 1);
240         s1 := KillTrailingSpcs(KillLeadingSpcs(s1));
241         If (s1[1] <> '-') then
242           Begin
243           If ((CurUser^.May and um_DisConnect) = 0) then
244             Begin
245             LogSetCurLevel(LogHandle, 2);
246             LogWriteLn(LogHandle, 'User isn''t allowed to disconnect areas');
247             SendRsp(rs_NoDisConnect, '');
248             End
249           Else
250             Begin
251             DisConnectArea(s1);
252             End;
253           End;
254         End
255       Else If (s1[1] = '=') then
256         Begin
257         Delete(s1, 1, 1);
258         s1 := KillTrailingSpcs(KillLeadingSpcs(s1));
259         If ((CurUser^.May and um_Connect) = 0) then
260           Begin
261           LogSetCurLevel(LogHandle, 2);
262           LogWriteLn(LogHandle, 'User isn''t allowed to connect areas');
263           SendRsp(rs_NoConnect, '');
264           End
265         Else
266           Begin
267           ConnectArea(s1, True, ReScanParams);
268           End;
269         End
270       Else If (Pos('...', s1) <> 1) then
271         Begin
272         If (s1[1] = '+') then Delete(s1, 1, 1);
273         s1 := KillTrailingSpcs(KillLeadingSpcs(s1));
274         If ((CurUser^.May and um_Connect) = 0) then
275           Begin
276           LogSetCurLevel(LogHandle, 2);
277           LogWriteLn(LogHandle, 'User isn''t allowed to connect areas');
278           SendRsp(rs_NoConnect, '');
279           End
280         Else
281           Begin
282           ConnectArea(s1, DoRescan, ReScanParams);
283           End;
284         End;
285       End;
286 
287     CurBody := Body;
288     While (CurBody <> NIL) do
289      Begin
290      Body := CurBody^.Next;
291      Dispose(CurBody);
292      CurBody := Body;
293      End;
294 
295     If Cfg^.DelReq then DeleteMsg;
296     End;
297   End;
298 
299 Procedure ConnectArea(Name: String; DReScan: Boolean; RSParams: String);
300 Var
301   DoReScan: Boolean;
302   i: LongInt;
303   s: String;
304   ReScanParams: String;
305   A1: TNetAddr;
306   Found: Boolean;
307   DoAddArea: Boolean;
308   SecFault: Boolean;
309 
310   Begin
311   DoReScan := DReScan;
312   ReScanParams := RSParams;
313   Found := False;
314   DoAddArea := False;
315   SecFault := False;
316   s := Name;
317   i := Pos(',R', s);
318   If (i > 0) then
319     Begin
320     DoReScan := True;
321     If (i < (Length(s) - 3)) then ReScanParams := Copy(s, i+3, Length(s) - i - 3);
322     s := Copy(s, 1, i - 1);
323     End;
324   CurArea := Cfg^.Areas;
325   While (CurArea^.Next <> Nil) do
326     Begin
327     While ((CurArea^.Next <> Nil) and (not Match(UpStr(CurArea^.Name), s))) do CurArea := CurArea^.Next;
328     If not (CurArea^.Group in CurUser^.Groups) then
329       Begin
330       If CurArea^.Next <> Nil then
331         Begin
332         CurArea := CurArea^.Next;
333         Continue;
334         End;
335       SecFault := True;
336       End
337     Else
338       Begin
339       If (CurArea^.Level > CurUser^.Level) then
340         Begin
341         If CurArea^.Next <> Nil then
342           Begin
343           CurArea := CurArea^.Next;
344           Continue;
345           End;
346         SecFault := True;
347         End
348       Else
349         Begin
350         If ((CurArea^.Flags and fa_RemoteChange) = 0) then
351           Begin
352           LogSetCurLevel(LogHandle, 2);
353           LogWriteLn(LogHandle, 'Area "'+CurArea^.Name+'" may not be linked remotely');
354           SendRsp(rs_NoRemote, CurArea^.Name);
355           If CurArea^.Next <> Nil then
356             Begin
357             CurArea := CurArea^.Next;
358             Continue;
359             End;
360           SecFault := True;
361           End;
362         End;
363       End;
364     If (not Match(UpStr(CurArea^.Name), s)) or SecFault then
365       Begin
366       If not Found then
367         Begin
368         LogSetCurLevel(LogHandle, 2);
369         LogWriteLn(LogHandle, 'Area "'+s+'" not found');
370         SendRsp(rs_UnKnownArea, s);
371         End;
372       End
373     Else
374       Begin
375       Found := True;
376       CurConnUser := CurArea^.Users;
377       DoAddArea := False;
378       If (CurConnUser <> NIL) then
379         Begin
380         While ((CurConnUser^.Next <> Nil) and (CurConnUser^.User <> CurUser)) do CurConnUser := CurConnUser^.Next;
381         If (CurConnUser^.User <> CurUser) then
382           Begin
383           New(CurConnUser^.Next);
384           CurConnUser^.Next^.Prev := CurConnUser;
385           CurConnUser := CurConnUser^.Next;
386           CurConnUser^.Next := Nil;
387           CurConnUser^.User := CurUser;
388           CurConnUser^.Receive := CurUser^.Receives;
389           CurConnUser^.Send := CurUser^.Sends;
390           DoAddArea := True;
391           End;
392         End
393       Else
394         Begin
395         New(CurArea^.Users);
396         CurConnUser := CurArea^.Users;
397         CurConnUser^.Prev := NIL;
398         CurConnUser^.Next := NIL;
399         CurConnUser^.User := CurUser;
400         CurConnUser^.Receive := CurUser^.Receives;
401         CurConnUser^.Send := CurUser^.Sends;
402         DoAddArea := True;
403         End;
404       If DoAddArea then
405         Begin
406         DoAddArea := False;
407         With Ini do
408           Begin
409           SetSection('USER');
410             Repeat
411             While (UpStr(ReSecEnName) <> 'ADDR') do If not SetNextOpt then Break;
412             If (UpStr(ReSecEnName) <> 'ADDR') then Break;
413             Str2Addr(ReSecEnValue, A1);
414             If CompAddr(A1, CurUser^.Addr) then Break;
415             SetNextOpt;
416             Until CompAddr(A1, CurUser^.Addr);
417           If (not CompAddr(A1, CurUser^.Addr)) then
418             Begin
419             LogSetCurLevel(LogHandle, 1);
420             LogWriteLn(LogHandle, 'User "'+CurUser^.Name+'" ('+Addr2Str(CurUser^.Addr)+') not found in ConfigFile!');
421             End
422           Else
423             Begin
424             LogSetCurLevel(LogHandle, 4);
425             LogWriteLn(LogHandle, 'Connected to '+CurArea^.Name);
426             SendRsp(rs_Connect, CurArea^.Name);
427             InsertSecEntry('Area', CurArea^.Name, '');
428             End;
429           End;
430         End
431       Else
432         Begin
433         If (Pos('*', Name) = 0) and (Pos('?', Name) = 0) then
434           Begin
435           LogSetCurLevel(LogHandle, 4);
436           LogWriteLn(LogHandle, 'Already connected to '+s);
437           SendRsp(rs_AlreadyConn, s);
438           End;
439         End;
440       End;
441     If (CurArea^.Next <> Nil) then CurArea := CurArea^.Next;
442     End;
443   If DoReScan then ReScan(s, ReScanParams);
444   End;
445 
446 Procedure DisConnectArea(Name: String);
447 Var
448   A1: TNetAddr;
449   s: String;
450   Found: Boolean;
451   SecFault: Boolean;
452 
453   Begin
454   CurArea := Cfg^.Areas;
455   Found := False;
456   SecFault := False;
457   While (CurArea^.Next <> Nil) do
458     Begin
459     While ((CurArea^.Next <> Nil) and (not Match(UpStr(CurArea^.Name), Name))) do CurArea := CurArea^.Next;
460     If ((CurArea^.Flags and fa_RemoteChange) = 0) then
461       Begin
462       LogSetCurLevel(LogHandle, 2);
463       LogWriteLn(LogHandle, 'Area "'+CurArea^.Name+'" may not be unlinked remotely');
464       SendRsp(rs_NoRemote, CurArea^.Name);
465       If CurArea^.Next <> Nil then
466         Begin
467         CurArea := CurArea^.Next;
468         Continue;
469         End;
470       SecFault := True;
471       End;
472     If ((CurArea^.Flags and fa_Mandatory) > 0) then
473       Begin
474       LogSetCurLevel(LogHandle, 2);
475       LogWriteLn(LogHandle, 'Area "'+CurArea^.Name+'" is mandatory');
476       SendRsp(rs_Mandatory, CurArea^.Name);
477       If CurArea^.Next <> Nil then
478         Begin
479         CurArea := CurArea^.Next;
480         Continue;
481         End;
482       SecFault := True;
483       End;
484     If (not Match(UpStr(CurArea^.Name), Name)) or SecFault then
485       Begin
486       If (not Found) and (not SecFault) then
487         Begin
488         LogSetCurLevel(LogHandle, 2);
489         LogWriteLn(LogHandle, 'Area "'+Name+'" not found');
490         SendRsp(rs_UnKnownArea, Name);
491         End;
492       End
493     Else
494       Begin
495       Found := True;
496       If (CurArea^.Users <> Nil) then
497         Begin
498         CurConnUser := CurArea^.Users;
499         While ((CurConnUser^.Next <> Nil) and (CurConnUser^.User <> CurUser)) do CurConnUser := CurConnUser^.Next;
500         If (CurConnUser^.User = CurUser) then
501           Begin
502           If (CurConnUser^.Next <> Nil) then
503             Begin
504             If (CurConnUser = CurArea^.Users) then
505               Begin
506               CurArea^.Users := CurConnUser^.Next;
507               End
508             Else
509               Begin
510               CurConnUser^.Prev^.Next := CurConnUser^.Next;
511               CurConnUser^.Next^.Prev := CurConnUser^.Prev;
512               End;
513             End
514           Else
515             Begin
516             If (CurConnUser = CurArea^.Users) then
517               Begin
518               CurArea^.Users := Nil;
519               End
520             Else
521               Begin
522               CurConnUser^.Prev^.Next := Nil;
523               End;
524             End;
525           Dispose(CurConnUser);
526           CurConnUser := NIL;
527           With Ini do
528             Begin
529             SetSection('USER');
530               Repeat
531               While (UpStr(ReSecEnName) <> 'ADDR') do If not SetNextOpt then Break;
532               If (UpStr(ReSecEnName) <> 'ADDR') then Break;
533               Str2Addr(ReSecEnValue, A1);
534               If CompAddr(A1, CurUser^.Addr) then Break;
535               SetNextOpt;
536               Until CompAddr(A1, CurUser^.Addr);
537             If (not CompAddr(A1, CurUser^.Addr)) then
538               Begin
539               LogSetCurLevel(LogHandle, 1);
540               LogWriteLn(LogHandle, 'User "'+CurUser^.Name+'" ('+Addr2Str(CurUser^.Addr)+') not found in ConfigFile!');
541               End
542             Else
543               Begin
544                 Repeat
545                 If not SetNextOpt then Break;
546                 s := UpStr(ReSecEnValue);
547                 If (Pos(',', s) <> 0) then s := Copy(s, 1, Pos(',', s) - 1);
548               Until ((UpStr(ReSecEnName) = 'AREA') and Match(s, UpStr(Name)));
549               If Match(s, UpStr(Name)) then
550                 Begin
551                 LogSetCurLevel(LogHandle, 4);
552                 LogWriteLn(LogHandle, 'DisConnected from '+s);
553                 SendRsp(rs_DisConnect, s);
554                 DelCurEntry(False);
555                 End;
556               End;
557             End;
558           End
559         Else
560           Begin
561           If (Pos('*', Name) = 0) and (Pos('?', Name) = 0) then
562             Begin
563             LogSetCurLevel(LogHandle, 4);
564             LogWriteLn(LogHandle, 'Not connected to '+Name);
565             SendRsp(rs_NotConn, Name);
566             End;
567           End;
568         End
569       Else
570         Begin
571         If (Pos('*', Name) = 0) and (Pos('?', Name) = 0) then
572           Begin
573           LogSetCurLevel(LogHandle, 4);
574           LogWriteLn(LogHandle, 'Not connected to '+Name);
575           SendRsp(rs_NotConn, Name);
576           End;
577         End;
578       End;
579     If (CurArea^.Next <> Nil) then CurArea := CurArea^.Next;
580     End;
581   End;
582 
583 Procedure ReScan(Name, Params: String);
584   Begin
585   If ((CurUser^.May and um_Rescan) = 0) then
586     Begin
587     LogSetCurLevel(LogHandle, 2);
588     LogWriteLn(LogHandle, 'User isn''t allowed to rescan areas');
589     SendRsp(rs_NoReScan, '');
590     End
591   Else
592     Begin
593     LogSetCurLevel(LogHandle, 3);
594     LogWriteLn(LogHandle, 'Rescan not implemented.');
595     SendRsp(rs_NotImplemented, 'Rescan');
596     End;
597   End;
598 
599 Procedure SendRsp(_Type: Word; Params: String);
600 Var
601   s: String;
602   DT: TimeTyp;
603   MKAddr: AddrType;
604   A1: TNetAddr;
605 
606   Procedure SendList;
607   Var
608     CA: PArea;
609     CG: Byte;
610     CCG: Byte;
611     Found: Byte;
612 
613     Begin
614     With NM2^ do
615       Begin
616       DoStringLn('List of areas available to you:');
617       DoStringLn('');
618       For CG := 1 to 255 do If (CG in CurUser^.Groups) then
619        Begin
620        Found := 0;
621        For CCG := 1 to Cfg^.NumGroups do If (Cfg^.Groups[CCG].Index = CG) then
622         Begin Found := CCG; Break; End;
623        If (Found > 0) then DoStringLn('Group '+Cfg^.Groups[Found].Name)
624        Else DoStringLn('Group <unknown>');
625        CA := Cfg^.Areas;
626        If (CA^.Group = CG) and
627          (CA^.Level <= CurUser^.Level) then
628           DoStringLn(CA^.Name+Copy(Leer, 1, 30-Length(CA^.Name))+CA^.Desc);
629          Repeat
630          CA := CA^.Next;
631          If (CA^.Group = CG) and ((CA^.Flags and fa_Hidden) = 0) and
632            (CA^.Level <= CurUser^.Level) then
633             DoStringLn(CA^.Name+Copy(Leer, 1, 30-Length(CA^.Name))+CA^.Desc);
634          Until (CA^.Next = Nil);
635        DoStringLn('');
636        End;
637       End;
638     End;
639 
640   Procedure SendQuery;
641   Var
642     CA: PArea;
643     CG: Byte;
644     CCG: Byte;
645     Found: Byte;
646     WroteGroup: Boolean;
647 
CheckConnnull648     Function CheckConn: Boolean;
649     Var
650       CCU: PConnectedUser;
651 
652       Begin
653       CheckConn := False;
654       If (CA^.Users = NIL) then Exit;
655       CCU := CA^.Users;
656       If (CCU^.User = CurUser) then
657         Begin
658         CheckConn := True;
659         Exit;
660         End;
661       If (CCU^.Next = NIL) then Exit;
662         Repeat
663         CCU := CCU^.Next;
664         If (CCU^.User = CurUser) then
665           Begin
666           CheckConn := True;
667           Exit
668           End;
669         Until (CCU^.Next = NIL);
670       End;
671 
672     Begin
673     With NM2^ do
674       Begin
675       DoStringLn('List of connected areas:');
676       DoStringLn('');
677       For CG := 1 to 255 do
678        Begin
679        WroteGroup := False;
680        CA := Cfg^.Areas;
681        If ((CA^.Group = CG) and CheckConn) then
682         Begin
683         If not WroteGroup then
684          Begin
685          WroteGroup := True;
686          Found := 0;
687          For CCG := 1 to Cfg^.NumGroups do If (Cfg^.Groups[CCG].Index = CG) then
688           Begin Found := CCG; Break; End;
689          If (Found > 0) then DoStringLn('Group '+Cfg^.Groups[Found].Name)
690          Else DoStringLn('Group <unknown>');
691          End;
692         DoStringLn(CA^.Name+Copy(Leer, 1, 30-Length(CA^.Name))+CA^.Desc);
693         End;
694          Repeat
695          CA := CA^.Next;
696          If ((CA^.Group = CG) and CheckConn) then
697           Begin
698           If not WroteGroup then
699            Begin
700            WroteGroup := True;
701            Found := 0;
702            For CCG := 1 to Cfg^.NumGroups do If (Cfg^.Groups[CCG].Index = CG) then
703             Begin Found := CCG; Break; End;
704            If (Found > 0) then DoStringLn('Group '+Cfg^.Groups[Found].Name)
705            Else DoStringLn('Group <unknown>');
706            End;
707           DoStringLn(CA^.Name+Copy(Leer, 1, 30-Length(CA^.Name))+CA^.Desc);
708           End;
709          Until (CA^.Next = Nil);
710        If WroteGroup then DoStringLn('');
711        End;
712       End;
713     End;
714 
715   Procedure SendUnlinked;
716   Var
717     CA: PArea;
718     CG: Byte;
719     CCG: Byte;
720     Found: Byte;
721     WroteGroup: Boolean;
722 
CheckConnnull723     Function CheckConn: Boolean;
724     Var
725       CCU: PConnectedUser;
726 
727       Begin
728       CheckConn := False;
729       If (CA^.Users = NIL) then Exit;
730       CCU := CA^.Users;
731       If (CCU^.User = CurUser) then
732         Begin
733         CheckConn := True;
734         Exit;
735         End;
736       If (CCU^.Next = NIL) then Exit;
737         Repeat
738         CCU := CCU^.Next;
739         If (CCU^.User = CurUser) then
740           Begin
741           CheckConn := True;
742           Exit
743           End;
744         Until (CCU^.Next = NIL);
745       End;
746 
747     Begin
748     With NM2^ do
749       Begin
750       DoStringLn('List of disconnected areas:');
751       DoStringLn('');
752       For CG := 1 to 255 do If (CG in CurUser^.Groups) then
753        Begin
754        CA := Cfg^.Areas;
755        WroteGroup := False;
756        If (CA^.Group = CG) and (CA^.Level <= CurUser^.Level) and
757          (not CheckConn) then
758          Begin
759          If not WroteGroup then
760           Begin
761           WroteGroup := True;
762           Found := 0;
763           For CCG := 1 to Cfg^.NumGroups do If (Cfg^.Groups[CCG].Index = CG) then
764            Begin Found := CCG; Break; End;
765           If (Found > 0) then DoStringLn('Group '+Cfg^.Groups[Found].Name)
766           Else DoStringLn('Group <unknown>');
767           End;
768          DoStringLn(CA^.Name+Copy(Leer, 1, 30-Length(CA^.Name))+CA^.Desc);
769          End;
770 
771          Repeat
772          CA := CA^.Next;
773          If (CA^.Group = CG) and (CA^.Level <= CurUser^.Level) and
774            ((CA^.Flags and fa_Hidden) = 0) and (not CheckConn) then
775            Begin
776            If not WroteGroup then
777             Begin
778             WroteGroup := True;
779             Found := 0;
780             For CCG := 1 to Cfg^.NumGroups do If (Cfg^.Groups[CCG].Index = CG) then
781              Begin Found := CCG; Break; End;
782             If (Found > 0) then DoStringLn('Group '+Cfg^.Groups[Found].Name)
783             Else DoStringLn('Group <unknown>');
784             End;
785            DoStringLn(CA^.Name+Copy(Leer, 1, 30-Length(CA^.Name))+CA^.Desc);
786            End;
787          Until (CA^.Next = Nil);
788        If WroteGroup then DoStringLn('');
789        End;
790       End;
791     End;
792 
793   Procedure UnListed;
794     Begin
795     NM2^.DoStringLn('You are not listed in the configuration. Did you use the right AKA?');
796     End;
797 
798   Procedure WrongPwd;
799     Begin
800     NM2^.DoStringLn('Wrong password:"'+Params+'"');
801     End;
802 
803   Procedure UnKnownCmd;
804     Begin
805     NM2^.DoStringLn('Unknown command: "'+Params+'"');
806     End;
807 
808   Procedure NoDisConnect;
809     Begin
810     NM2^.DoStringLn('You are not allowed to disconnect areas.');
811     End;
812 
813   Procedure NoConnect;
814     Begin
815     NM2^.DoStringLn('You are not allowed to connect areas.');
816     End;
817 
818   Procedure NoReScan;
819     Begin
820     NM2^.DoStringLn('You are not allowed to rescan areas.');
821     End;
822 
823   Procedure UnKnownArea;
824     Begin
825     NM2^.DoStringLn('Unknown area: "'+Params+'"');
826     End;
827 
828   Procedure AlreadyConn;
829     Begin
830     NM2^.DoStringLn('Area "'+Params+'" already connected.');
831     End;
832 
833   Procedure NotConn;
834     Begin
835     NM2^.DoStringLn('Area "'+Params+'" not connected.');
836     End;
837 
838   Procedure NoPause;
839     Begin
840     NM2^.DoStringLn('You are not allowed to pause.');
841     End;
842 
843   Procedure NoComp;
844     Begin
845     NM2^.DoStringLn('You are not allowed to change compression.');
846     End;
847 
848   Procedure UnKnownPacker;
849     Begin
850     NM2^.DoStringLn('Unknown packer: "'+Params+'"');
851     End;
852 
853   Procedure NotImplemented;
854     Begin
855     NM2^.DoStringLn(Params+' not implemented yet.');
856     End;
857 
858   Procedure Connect;
859     Begin
860     NM2^.DoStringLn(Params+' linked.');
861     End;
862 
863   Procedure DisConnect;
864     Begin
865     NM2^.DoStringLn(Params+' unlinked.');
866     End;
867 
868   Procedure Pause;
869     Begin
870     NM2^.DoStringLn('Paused.');
871     End;
872 
873   Procedure Resume;
874     Begin
875     NM2^.DoStringLn('Resumed.');
876     End;
877 
878   Procedure PackFiles;
879     Begin
880     NM2^.DoStringLn('PackFiles: '+Params);
881     End;
882 
883   Procedure PackTICs;
884     Begin
885     NM2^.DoStringLn('PackTICs: '+Params);
886     End;
887 
888   Procedure Packer;
889     Begin
890     NM2^.DoStringLn('Packer: '+Params);
891     End;
892 
893   Procedure NoRemote;
894     Begin
895     NM2^.DoStringLn(Params+' may not be (un)linked remotely.');
896     End;
897 
898   Procedure Mandatory;
899     Begin
900     NM2^.DoStringLn(Params+' is mandatory.');
901     End;
902 
903   Procedure UnKnownResponse;
904     Begin
905     NM2^.DoStringLn('Unknown response (#'+Params+'). Please report to SysOp!');
906     End;
907 
908   Procedure Help;
909     Begin
910     With NM2^ do
911       Begin
912       DoStringLn('available commands:');
913       DoStringLn('');
914       DoStringLn('%HELP           this help :)');
915       DoStringLn('%LIST           list of areas available to you');
916       DoStringLn('%QUERY          list of connected areas');
917       DoStringLn('%UNLINKED       list of disconnected areas');
918       DoStringLn('%PACK           \ on = pack all, off = pack none, files = pack files,');
919       DoStringLn('%COMPRESS       | tics = pack tics, Extension = set packer to use');
920       DoStringLn('%COMPRESSION    / examples: "%PACK ON", "%PACK ZIP"');
921       DoStringLn('%PAUSE          stop sending files (e.g. for holiday)');
922       DoStringLn('%RESUME         resume sending files (holiday over :) )');
923       DoStringLn('%QUIT           everything below (e.g. signature) is ignored');
924       DoStringLn('%NOTE           everything below is ignored, message will NOT be deleted');
925       DoStringLn('<Area>          connect area');
926       DoStringLn('+<Area>         connect area');
927       DoStringLn('-<Area>         disconnect area');
928       End;
929     End;
930 
931   Procedure ParamNeeded;
932     Begin
933     NM2^.DoStringLn(Params+': parameter needed');
934     End;
935 
936 
937   Begin
938   With NM2^ do
939     Begin
940     StartNewMsg;
941     s := 'ProTick';
942     SetFrom(s);
943     SetKillSent(Cfg^.DelRsp);
944     If (_Type <> rs_Unlisted) then
945       Begin
946       SetTo(CurUser^.Name);
947       TNetAddr2MKAddr(CurUser^.Addr, MKAddr);
948       SetDest(MKAddr);
949       If not CompAddr(CurUser^.OwnAddr, EmptyAddr) then A1 := CurUser^.OwnAddr
950       Else AKAMatch(CurUser^.Addr, A1);
951       End
952     Else
953       Begin
954       SetTo(NM^.GetFrom);
955       NM^.GetOrig(MKAddr);
956       SetDest(MKAddr);
957       MKAddr2TNetAddr(MKAddr, A1);
958       AKAMatch(A1, A1);
959       End;
960     TNetAddr2MKAddr(A1, MKAddr);
961     SetOrig(MKAddr);
962     SetLocal(True);
963     SetPriv(True);
964     SetSubj('FileFix response');
965     Today(DT);
966     If (DT.Year > 100) then DT.Year := DT.Year mod 100;
967     Now(DT);
968     If (DT.Month > 9) then s := IntToStr(DT.Month) + '-'
969     Else s := '0' + IntToStr(DT.Month) + '-';
970     If (DT.Day > 9) then s := s + IntToStr(DT.Day) + '-'
971     Else s := s + '0' + IntToStr(DT.Day) + '-';
972     If (DT.Year > 9) then s := s + IntToStr(DT.Year)
973     Else s := s + '0' + IntToStr(DT.Year);
974     SetDate(s);
975     If (DT.Hour > 9) then s := IntToStr(DT.Hour) + ':'
976     Else s := '0' + IntToStr(DT.Hour) + ':';
977     If (DT.Min > 9) then s := s + IntToStr(DT.Min)
978     Else s := s + '0' + IntToStr(DT.Min);
979     SetTime(s);
980     SetRefer(NM^.GetMsgNum);
981     DoKludgeLn(#01'MSGID: '+Addr2Str(A1)+' '+GetMsgID);
982 
983     Case _Type of
984       rs_List: SendList;
985       rs_Unlisted: UnListed;
986       rs_WrongPwd: WrongPwd;
987       rs_UnKnownCmd: UnKnownCmd;
988       rs_NoDisConnect: NoDisConnect;
989       rs_NoConnect: NoConnect;
990       rs_NoReScan: NoReScan;
991       rs_UnKnownArea: UnKnownArea;
992       rs_AlreadyConn: AlreadyConn;
993       rs_NotConn: NotConn;
994       rs_NoPause: NoPause;
995       rs_NoComp: NoComp;
996       rs_UnKnownPacker: UnKnownPacker;
997       rs_NotImplemented: NotImplemented;
998       rs_Help: Help;
999       rs_ParamNeeded: ParamNeeded;
1000       rs_Connect: Connect;
1001       rs_DisConnect: DisConnect;
1002       rs_Pause: Pause;
1003       rs_Resume: Resume;
1004       rs_PackFiles: PackFiles;
1005       rs_PackTICs: PackTICs;
1006       rs_Packer: Packer;
1007       rs_NoRemote: NoRemote;
1008       rs_Mandatory: Mandatory;
1009       rs_Query: SendQuery;
1010       rs_Unlinked: SendUnlinked;
1011       Else UnKnownResponse;
1012       End;
1013 
1014     DoStringLn('');
1015     DoStringLn('--- ProTick'+Version);
1016     If (WriteMsg <> 0) then
1017       Begin
1018       LogSetCurLevel(LogHandle, 1);
1019       LogWriteLn(LogHandle, 'Couldn''t write response!');
1020       Exit;
1021       End;
1022     NM^.InitMsgHdr;
1023     NM^.MsgTxtStartUp;
1024     NM^.SetSeeAlso(GetMsgNum);
1025     NM^.ReWriteHdr;
1026     End;
1027   End;
1028 
1029 Procedure SetActive(Act: Boolean);
1030 Var
1031   s1: String;
1032   A1: TNetAddr;
1033 
1034   Begin
1035   CurUser^.Active := Act;
1036   With Ini do
1037     Begin
1038     SetSection('USER');
1039       Repeat
1040       While (UpStr(ReSecEnName) <> 'ADDR') do If not SetNextOpt then Break;
1041       If (UpStr(ReSecEnName) <> 'ADDR') then Break;
1042       Str2Addr(ReSecEnValue, A1);
1043       If CompAddr(A1, CurUser^.Addr) then Break;
1044       SetNextOpt;
1045       Until CompAddr(A1, CurUser^.Addr);
1046     If not CompAddr(A1, CurUser^.Addr) then
1047       Begin
1048       LogSetCurLevel(LogHandle, 1);
1049       LogWriteLn(LogHandle, 'User "'+CurUser^.Name+'" ('+Addr2Str(CurUser^.Addr)+') not found in ConfigFile!');
1050       End
1051     Else
1052       Begin
1053       While ((UpStr(ReSecEnName) <> 'USER') and (UpStr(ReSecEnName) <> 'ACTIVE')) do If not SetNextOpt then Break;
1054       If (UpStr(ReSecEnName) = 'ACTIVE') then
1055         Begin
1056         If Act then WriteSecEntry('Active', 'Yes', '')
1057         Else WriteSecEntry('Active', 'No', '');
1058         End
1059       Else If (UpStr(ReSecEnName) = 'USER') then
1060         Begin
1061         SetPrevOpt;
1062         If Act then InsertSecEntry('Active', 'Yes', '')
1063         Else InsertSecEntry('Active', 'No', '');
1064         End
1065       Else
1066         Begin
1067         If Act then AddSecEntry('Active', 'Yes', '')
1068         Else AddSecEntry('Active', 'No', '');
1069         End;
1070       If Act then
1071         Begin
1072         LogSetCurLevel(LogHandle, 2);
1073         LogWriteLn(LogHandle, 'Set User '+CurUser^.Name+' ('+Addr2Str(CurUser^.Addr)+') to ACTIVE');
1074         End
1075       Else
1076         Begin
1077         LogSetCurLevel(LogHandle, 2);
1078         LogWriteLn(LogHandle, 'Set User '+CurUser^.Name+' ('+Addr2Str(CurUser^.Addr)+') to PASSIVE');
1079         End;
1080       End;
1081     End;
1082   End;
1083 
1084 Procedure SetPack(Pack: String);
1085 {PACK=ON/OFF/J/N/Y/YES/NO/JA/NEIN/0/1/ALL/FILES/TICS/NONE/<ArcExt>}
1086 Var
1087   s: String;
1088   A1: TNetAddr;
1089   i: LongInt;
1090   ChTICs, ChFiles, ChPacker: Boolean;
1091   Found: LongInt;
1092 
1093   Begin
1094   ChTICs := False;
1095   ChFiles := False;
1096   ChPacker := False;
1097   While (Length(s) > 0) and (s[1] = ' ') do Delete(s, 1, 1);
1098   If (s = '') then
1099     Begin
1100     LogSetCurLevel(LogHandle, 3);
1101     LogWriteLn(LogHandle, 'set compression: parameter needed');
1102     SendRsp(rs_ParamNeeded, 'set compression');
1103     End;
1104   s := UpStr(Pack);
1105   If ((s = 'ON') or (s = 'Y') or (s = 'YES') or (s = '1') or (s = 'J') or
1106     (s = 'JA') or (s = 'ALL')) then
1107     Begin
1108     ChTICs := not CurUser^.PackTICs;
1109     ChFiles := not CurUser^.PackFiles;
1110     CurUser^.PackTICs := True;
1111     CurUser^.PackFiles := True;
1112     End
1113   Else If ((s = 'OFF') or (s = 'N') or (s = 'NO') or (s = '0') or (s = 'NEIN') or
1114     (s = 'NONE')) then
1115     Begin
1116     ChTICs := CurUser^.PackTICs;
1117     ChFiles := CurUser^.PackFiles;
1118     CurUser^.PackTICs := False;
1119     CurUser^.PackFiles := False;
1120     End
1121   Else If (s = 'FILES') then
1122     Begin
1123     ChTICs := not CurUser^.PackTICs;
1124     ChFiles := CurUser^.PackFiles;
1125     CurUser^.PackTICs := False;
1126     CurUser^.PackFiles := True;
1127     End
1128   Else If (s = 'TICS') then
1129     Begin
1130     ChTICs := CurUser^.PackTICs;
1131     ChFiles := not CurUser^.PackFiles;
1132     CurUser^.PackTICs := True;
1133     CurUser^.PackFiles := False;
1134     End
1135   Else
1136     Begin
1137     Found := 1;
1138     For i := 1 to Cfg^.NumPacker do If (s = Cfg^.Packer[i].Ext) then Begin Found := i; Break; End;
1139     If (s = Cfg^.Packer[Found].Ext) then
1140       Begin
1141       CurUser^.Packer := Cfg^.Packer[Found].Index;
1142       ChPacker := True;
1143       End
1144     Else
1145       Begin
1146       LogSetCurLevel(LogHandle, 3);
1147       LogWriteLn(LogHandle, 'Unknown Packer "'+s+'"');
1148       SendRsp(rs_UnKnownPacker, s);
1149       End;
1150     End;
1151   With Ini do
1152     Begin
1153     If ChFiles then
1154       Begin
1155       SetSection('USER');
1156         Repeat
1157         While (UpStr(ReSecEnName) <> 'ADDR') do If not SetNextOpt then Break;
1158         If (UpStr(ReSecEnName) <> 'ADDR') then Break;
1159         Str2Addr(ReSecEnValue, A1);
1160         If CompAddr(A1, CurUser^.Addr) then Break;
1161         SetNextOpt;
1162         Until CompAddr(A1, CurUser^.Addr);
1163       If not CompAddr(A1, CurUser^.Addr) then
1164         Begin
1165         LogSetCurLevel(LogHandle, 1);
1166         LogWriteLn(LogHandle, 'User "'+CurUser^.Name+'" ('+Addr2Str(CurUser^.Addr)+') not found in ConfigFile!');
1167         End
1168       Else
1169         Begin
1170         While ((UpStr(ReSecEnName) <> 'USER') and (UpStr(ReSecEnName) <> 'PACKFILES')) do If not SetNextOpt then Break;
1171         If (UpStr(ReSecEnName) = 'PACKFILES') then
1172           Begin
1173           If CurUser^.PackFiles then WriteSecEntry('PackFiles', 'Yes', '')
1174           Else WriteSecEntry('PackFiles', 'No', '');
1175           End
1176         Else If (UpStr(ReSecEnName) = 'USER') then
1177           Begin
1178           SetPrevOpt;
1179           If CurUser^.PackFiles then InsertSecEntry('PackFiles', 'Yes', '')
1180           Else InsertSecEntry('PackFiles', 'No', '');
1181           End
1182         Else
1183           Begin
1184           If CurUser^.PackFiles then AddSecEntry('PackFiles', 'Yes', '')
1185           Else AddSecEntry('PackFiles', 'No', '');
1186           End;
1187         If CurUser^.PackFiles then
1188           Begin
1189           LogSetCurLevel(LogHandle, 3);
1190           LogWriteLn(LogHandle, 'Set PackFiles for User '+CurUser^.Name+' ('+Addr2Str(CurUser^.Addr)+') to Yes');
1191           SendRsp(rs_PackFiles, 'On');
1192           End
1193         Else
1194           Begin
1195           LogSetCurLevel(LogHandle, 3);
1196           LogWriteLn(LogHandle, 'Set PackFiles for User '+CurUser^.Name+' ('+Addr2Str(CurUser^.Addr)+') to No');
1197           SendRsp(rs_PackFiles, 'Off');
1198           End;
1199         End;
1200       End;
1201     If ChTICs then
1202       Begin
1203       SetSection('USER');
1204         Repeat
1205         While (UpStr(ReSecEnName) <> 'ADDR') do If not SetNextOpt then Break;
1206         If (UpStr(ReSecEnName) <> 'ADDR') then Break;
1207         Str2Addr(ReSecEnValue, A1);
1208         If CompAddr(A1, CurUser^.Addr) then Break;
1209         SetNextOpt;
1210         Until CompAddr(A1, CurUser^.Addr);
1211       If not CompAddr(A1, CurUser^.Addr) then
1212         Begin
1213         LogSetCurLevel(LogHandle, 1);
1214         LogWriteLn(LogHandle, 'User "'+CurUser^.Name+'" ('+Addr2Str(CurUser^.Addr)+') not found in ConfigFile!');
1215         End
1216       Else
1217         Begin
1218         While ((UpStr(ReSecEnName) <> 'USER') and (UpStr(ReSecEnName) <> 'PACKTICS')) do If not SetNextOpt then Break;
1219         If (UpStr(ReSecEnName) = 'PACKTICS') then
1220           Begin
1221           If CurUser^.PackTICs then WriteSecEntry('PackTICs', 'Yes', '')
1222           Else WriteSecEntry('PackTICs', 'No', '');
1223           End
1224         Else If (UpStr(ReSecEnName) = 'USER') then
1225           Begin
1226           SetPrevOpt;
1227           If CurUser^.PackTICs then InsertSecEntry('PackTICs', 'Yes', '')
1228           Else InsertSecEntry('PackTICs', 'No', '');
1229           End
1230         Else
1231           Begin
1232           If CurUser^.PackTICs then AddSecEntry('PackTICs', 'Yes', '')
1233           Else AddSecEntry('PackTICs', 'No', '');
1234           End;
1235         If CurUser^.PackTICs then
1236           Begin
1237           LogSetCurLevel(LogHandle, 3);
1238           LogWriteLn(LogHandle, 'Set PackTICs for User '+CurUser^.Name+' ('+Addr2Str(CurUser^.Addr)+') to Yes');
1239           SendRsp(rs_PackTICs, 'On');
1240           End
1241         Else
1242           Begin
1243           LogSetCurLevel(LogHandle, 3);
1244           LogWriteLn(LogHandle, 'Set PackTICs for User '+CurUser^.Name+' ('+Addr2Str(CurUser^.Addr)+') to No');
1245           SendRsp(rs_PackTICs, 'Off');
1246           End;
1247         End;
1248       End;
1249     If ChPacker then
1250       Begin
1251       SetSection('USER');
1252         Repeat
1253         While (UpStr(ReSecEnName) <> 'ADDR') do If not SetNextOpt then Break;
1254         If (UpStr(ReSecEnName) <> 'ADDR') then Break;
1255         Str2Addr(ReSecEnValue, A1);
1256         If CompAddr(A1, CurUser^.Addr) then Break;
1257         SetNextOpt;
1258         Until CompAddr(A1, CurUser^.Addr);
1259       If not CompAddr(A1, CurUser^.Addr) then
1260         Begin
1261         LogSetCurLevel(LogHandle, 1);
1262         LogWriteLn(LogHandle, 'User "'+CurUser^.Name+'" ('+Addr2Str(CurUser^.Addr)+') not found in ConfigFile!');
1263         End
1264       Else
1265         Begin
1266         While ((UpStr(ReSecEnName) <> 'USER') and (UpStr(ReSecEnName) <> 'PACKER')) do If not SetNextOpt then Break;
1267         If (UpStr(ReSecEnName) = 'PACKER') then
1268           Begin
1269           WriteSecEntry('Packer', IntToStr(CurUser^.Packer), '')
1270           End
1271         Else If (UpStr(ReSecEnName) = 'USER') then
1272           Begin
1273           SetPrevOpt;
1274           InsertSecEntry('Packer', IntToStr(CurUser^.Packer), '')
1275           End
1276         Else
1277           Begin
1278           AddSecEntry('Packer', IntToStr(CurUser^.Packer), '')
1279           End;
1280         Found := 1;
1281         For i := 1 to Cfg^.NumPacker do If (CurUser^.Packer = Cfg^.Packer[i].Index) then Begin Found := i; Break; End;
1282         LogSetCurLevel(LogHandle, 3);
1283         LogWriteLn(LogHandle, 'Set Packer for User '+CurUser^.Name+' ('+
1284           Addr2Str(CurUser^.Addr)+') to '+IntToStr(CurUser^.Packer)+' ('+
1285           Cfg^.Packer[Found].Ext+')');
1286         SendRsp(rs_Packer, Cfg^.Packer[Found].Ext);
1287         End;
1288       End;
1289     End;
1290   End;
1291 
1292 Procedure AKAMatch(InAddr: TNetAddr; var OutAddr: TNetAddr);
1293 Var
1294   i: Byte;
1295   Found: Boolean;
1296 
1297   Begin
1298   Found := False;
1299   For i := 1 to Cfg^.NumAddrs do If (InAddr.Zone = Cfg^.Addrs[i].Zone) then
1300     Begin
1301     Found := True;
1302     OutAddr := Cfg^.Addrs[i];
1303     Break;
1304     End;
1305   If not Found then OutAddr := Cfg^.Addrs[1];
1306   End;
1307 
1308 
1309 End.
1310