home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / dtx9303 / netz / tpnet / netlog.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-06-02  |  23.9 KB  |  822 lines

  1. {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X+}
  2. (*========================================================*)
  3. (*                        NETLOG.PAS                      *)
  4. (*            (C) 1993 G. Blumert & DMV-Verlag            *)
  5. (*--------------------------------------------------------*)
  6. (* Implementiert die Listen zur Verwaltung der geöffneten *)
  7. (*                          Fenster                       *)
  8. (* Compiler:                                              *)
  9. (*   Turbo-Pascal ab 6.0 oder Turbo-Pascal für Windows    *)
  10. (*========================================================*)
  11.  
  12. UNIT NetLog;
  13.  
  14. INTERFACE
  15. {$IFDEF Windows}
  16. USES
  17.   MyWinDos,
  18.   {$IFDEF Ver70}Objects, OWindows, OMemory,(* Oh-Borland *)
  19.   {$ELSE}       WObjects, {$ENDIF}
  20.   WinProcs, WinTypes, IPX, DPMI;
  21. {$ELSE}
  22. USES
  23.   IPX, Objects, Views, Memory, Dos, App, MsgBox, Drivers;
  24. {$ENDIF}
  25.  
  26. TYPE
  27.   (* Eindeutige Identifikation eines Fensters *)
  28.   pIPX_WindowID = ^tIPX_WindowID;
  29.   tIPX_WindowID = RECORD
  30.     IPX_ID: tIPX_ID;
  31.     Socket: WORD;
  32. {$IFDEF Windows}
  33.     Win_ID: pWindowsObject;
  34. {$ELSE}
  35.     Win_ID: pView
  36. {$ENDIF}
  37.   END;
  38.  
  39.   (* Speichert alle Anwendungen, die sich für die gleiche *)
  40.   (* Datei angemeldet haben.                              *)
  41.   (* Enthält Einträge vom Typ pIPX_WindowID               *)
  42.   pUserColl = ^tUserColl;
  43.   tUserColl = OBJECT(tCollection)  (* besitzendes Fenster *)
  44.  
  45. {$IFDEF Windows}
  46.     Parent: pWindowsObject;
  47. {$ELSE}
  48.     Parent: pView;
  49. {$ENDIF}
  50.     FileName: pString;              (* Name der LOG-Datei *)
  51.  
  52.    (* Erwartet die Socket-Nummer, an der nach Paketen für *)
  53.    (* das Fenster gelauscht wird                          *)
  54.     CONSTRUCTOR Init(aReceiveSocket: WORD);
  55.     DESTRUCTOR Done; VIRTUAL;
  56.  
  57.     (* Gibt den von einer TIPX_WindowID belegten          *)
  58.     (* Speicherplatz frei                                 *)
  59.     PROCEDURE FreeItem(Item: POINTER); VIRTUAL;
  60.  
  61.     (* Liest die Adressen der bereits eingeloggten        *)
  62.     (* Fenster ein                                        *)
  63.     FUNCTION ReadLogFile(VAR f: FILE): BOOLEAN;
  64.  
  65.     (* Schickt die Daten an alle anderen Fenster ab       *)
  66.     PROCEDURE SendCommand(Command: WORD;
  67.                           aUserData: pUserData);
  68.  
  69.     (* Die folgenden beiden Funktionen nicht selber       *)
  70.     (* aufrufen! - bzw. nur, wenn Sie genau wissen, was   *)
  71.     (* Sie tun.                                           *)
  72.     (* Wird von LogColl.LogIn aufgerufen                  *)
  73. {$IFDEF Windows}
  74.     FUNCTION LogIn(aParent: pWindowsObject;
  75.                             aFileName: PathStr): BOOLEAN;
  76. {$ELSE}
  77.     FUNCTION LogIn(aParent: pView;
  78.                    aFileName: PathStr): BOOLEAN;
  79. {$ENDIF}
  80.  
  81.     (* Wird vom Destruktor aufgerufen                     *)
  82.     FUNCTION LogOut: BOOLEAN;
  83.  
  84.     (* Sucht den zum empfangenen Paket gehörigen Absender *)
  85.     (* aus der User-Liste heraus                          *)
  86.     FUNCTION FindSender(aPacket: pIPX_Packet):pIPX_WindowID;
  87.  
  88.     (* Muß von jedem Fenster aufgerufen werden, das eine  *)
  89.     (* LogIn-Message empfangen hat                        *)
  90.     PROCEDURE AddUser(aPacket: pIPX_Packet);
  91.  
  92.     (* Muß von jedem Fenster aufgerufen werden, das eine  *)
  93.     (* LogOut-Message erhalten hat                        *)
  94.     PROCEDURE DeleteUser(aPacket: pIPX_Packet);
  95.   END;
  96.  
  97.   (* Verwaltet alle LOG-Dateien, die die Anwendung nutzt  *)
  98.   (* Enthält Einträge vom Typ PUserColl }                 *)
  99.   pLogColl = ^tLogColl;
  100.   tLogColl = OBJECT(tCollection)
  101.     IsListening: BOOLEAN;
  102.     Socket: WORD;(* Hi-Lo; Hier wird nach Daten gelauscht *)
  103.     CONSTRUCTOR Init;
  104.     DESTRUCTOR Done; VIRTUAL;
  105.  
  106.     (* Setzt IsListening auf TRUE und ruft                *)
  107.     (* ListenForPacket auf                                *)
  108.     PROCEDURE StartListening;
  109.  
  110.     (* Setzt IsListening auf FALSE und bricht             *)
  111.     (* ListenForPacket per CancelEvent ab                 *)
  112.     PROCEDURE StopListening;
  113.  
  114.     (* Meldet die Benutzung der Datei an.                 *)
  115. {$IFDEF Windows}
  116.     FUNCTION LogIn(LogFileName: PathStr; aParent:
  117.                    pWindowsObject): pUserColl;
  118. {$ELSE}
  119.     FUNCTION LogIn(LogFileName: PathStr; aParent: pView):
  120.                                                   pUserColl;
  121. {$ENDIF}
  122.  
  123.     (* Meldet das Fenster wieder ab *)
  124. {$IFDEF Windows}
  125.     FUNCTION LogOut(aParent: pWindowsObject): BOOLEAN;
  126. {$ELSE}
  127.     FUNCTION LogOut(aParent: pView): BOOLEAN;
  128. {$ENDIF}
  129.  
  130.     (* Gibt die User-Liste für das angegebene Fenster     *)
  131.     (* zurück                                             *)
  132. {$IFDEF Windows}
  133.     FUNCTION GetUserColl(aParent: pWindowsObject):pUserColl;
  134.   PRIVATE
  135.     EventProc: POINTER;   (* Per MakeProcInstance         *)
  136.                           (* festgelegte Prot.-Mode-Adr.  *)
  137.     CallBackAdr: POINTER; (* Von DPMI erhaltener Call-    *)
  138.                           (* Back für EventProc           *)
  139.     DOSPtr: POINTER;      (* Real-Mode-Adresse des Event- *)
  140.                           (* Handlers in WinNet           *)
  141. {$ELSE}
  142.     FUNCTION GetUserColl(aParent: pView): pUserColl;
  143. {$ENDIF}
  144.   END;
  145.  
  146.  
  147.   (* Puffert die ankommenden Pakete. Enthält Einträge vom *)
  148.   (* Typ pIPX_Packet.                                     *)
  149.   (* Außerdem ist hier die Stelle, wo das Programm nach   *)
  150.   (* ankommenden Paketen schaut und diese ggf. anfordert. *)
  151.   (* Die Anwendung muß nach Bearbeitung des Pakets        *)
  152.   (* unbedingt ClearPacket aufrufen, da erst dann das     *)
  153.   (* nächste Paket »ausgegeben« wird, bzw. unter der      *)
  154.   (* Speicherplatz erst dann wieder neu belegt wird.      *)
  155.  
  156.   pBuffColl = ^tBuffColl;
  157.   tBuffColl = OBJECT(tCollection)
  158.  
  159.     (* Reserviert Platz für 100 Pakete, da die Routinen   *)
  160.     (* der dynamischen Speicherverwaltung nicht reentrant *)
  161.     (* sind.                                              *)
  162.     CONSTRUCTOR Init;
  163.  
  164.     (* Nach Bearbeitung eines Pakets aufrufen! *)
  165.     PROCEDURE ClearPacket(Packet: pIPX_Packet);
  166.  
  167.     (* Gibt den von einem tIPX_Packet belegten Speicher   *)
  168.     (* frei                                               *)
  169.     PROCEDURE FreeItem(Item: POINTER); VIRTUAL;
  170.  
  171. {$IFNDEF Windows}
  172.     (* TRUE, wenn Daten abgerufen werden können           *)
  173.     FUNCTION PacketAvailable: BOOLEAN;
  174.  
  175.     (* Gibt das nächste Datenpaket zurück                 *)
  176.     FUNCTION GetPacket: pIPX_Packet;
  177.  
  178.   PRIVATE
  179.     PacketInUse            : BOOLEAN;
  180.     (* --> TRUE, wenn Paket in Bearbeitung                *)
  181.     FUNCTION FindUsedPacket: pIPX_Packet;
  182.     (* Ermittelt das nächste empfangene Packet            *)
  183.  {$ENDIF}
  184.   END;
  185.  
  186. (* Überprüft zwei beliebige Datenfelder auf Gleichheit    *)
  187. (* Sollte sich in jeder Utility-Bibliothek befinden       *)
  188. FUNCTION IsEqual(VAR M1, M2; MSize: WORD): BOOLEAN;
  189.  
  190. CONST
  191.   (* Puffert die ankommenden Pakete                       *)
  192.   BuffColl: pBuffColl = NIL;
  193.  
  194.  
  195. IMPLEMENTATION
  196.  
  197. CONST
  198.   (* Hier legt IPX die ankommenden Daten ab               *)
  199.   IPX_PacketBuffer: pIPX_Packet = NIL;
  200.  
  201.   (* Event-Control-Block für die Empfangs-Funktion        *)
  202.   ECB: pECB = NIL;
  203.  
  204.   { Socket, an dem nach Paketen gelauscht wird }
  205.   ReceiveSocket: WORD = 0;
  206.  
  207.  
  208. {$IFDEF Windows}
  209.   Packet_Sel: LongInt = 0;  (* Von GlobalDOSAlloc ...     *)
  210.   ECB_Sel   : LongInt = 0;  (* zurückgegebene Werte       *)
  211. {$ENDIF}
  212.  
  213. (* Gibt TRUE zurück, wenn eine andere Anwendung der       *)
  214. (* Empfänger des Pakets ist                               *)
  215. FUNCTION IsDifferentNode(Packet: pIPX_Packet): BOOLEAN;
  216. BEGIN
  217.   WITH Packet^ DO IsDifferentNode :=
  218.     (NOT IsEqual(Dest,MyIPX_ID,SizeOf(tIPX_ID))) OR
  219.     (ReceiveSocket <> Dest_Socket)
  220. END;
  221.  
  222. (* Überprüft zwei beliebige Datenfelder auf Gleichheit    *)
  223. FUNCTION IsEqual(VAR M1, M2; MSize: WORD): BOOLEAN;
  224.                                                   ASSEMBLER;
  225. ASM
  226.   CLD
  227.   PUSH    DS                             (* DS sichern    *)
  228.   LES     DI, M1                         (* ES:DI = M1    *)
  229.   LDS     SI, M2                         (* DS:SI = M2    *)
  230.   MOV     CX, MSize                      (* Länge         *)
  231.   XOR     AX, AX
  232.   TEST    CX, 1                          (* Länge gerade? *)
  233.   JZ      @SeekWord
  234.   CMPSB                                  (* Nein          *)
  235.   JNZ     @Ab                            (* Ungleich?     *)
  236. @SeekWord:
  237.   SHR     CX, 1                          (* /2            *)
  238.   JCXZ    @AbTrue                        (* schon fertig? *)
  239.   REPE    CMPSW
  240.   JNZ     @Ab                            (* Ungleich?     *)
  241. @AbTrue:
  242.   Inc     AL                             (* Nein - AL = 1 *)
  243. @Ab:
  244.   POP     DS
  245. END;
  246.  
  247. (*--------------------------------------------------------*)
  248. (* Es folgt der Eventhandler, der bei Eintreffen eines    *)
  249. (* Paketes angesprungen wird. Dieser muß als FAR          *)
  250. (* definiert sein.                                        *)
  251. (* Die Stack-Prüfung darf nicht eingeschaltet sein, da    *)
  252. (* nicht der Turbo-Pascal-Stapel benutzt wird, was die    *)
  253. (* Stack-Prüfroutine meist merkt.                         *)
  254. (* Die Register brauchen nicht gesichert werden,  aber    *)
  255. (* das Datensegment muß richtig gesetzt sein              *)
  256.  
  257. {$IFOPT S+}
  258.   {$S-}
  259.   {$DEFINE CheckStack}
  260. {$ENDIF}
  261.  
  262. {$IFDEF Windows}
  263.  
  264. PROCEDURE DoEvent; FAR;
  265. VAR
  266.   p       : pIPX_Packet;
  267.   UserColl: pUserColl;
  268.  
  269.   (* Gibt TRUE zurück, wenn das Paket »leer« ist          *)
  270.   FUNCTION IsEmpty(Item: pIPX_Packet): BOOLEAN; FAR;
  271.   BEGIN
  272.     IsEmpty := Item^.Data.Command = 0;
  273.   END;
  274.  
  275. BEGIN
  276.   p := BuffColl^.FirstThat(@IsEmpty);
  277.   IF p <> NIL THEN BEGIN              (* Noch Platz frei? *)
  278.     p^ := IPX_PacketBuffer^;
  279.     WITH p^.Data DO
  280.       PostMessage(DestWin^.hWindow, Command, 0, LongInt(p))
  281.   END;     (* Hier könnte man jetzt mit ELSE weitermachen *)
  282.            (* und eine Fehlerbehandlung einbauen.         *)
  283.            (* Außerdem könnte man prüfen, ob das Fenster  *)
  284.            (* überhaupt noch existiert, und anderenfalls  *)
  285.            (* gleich ClearPacket aufrufen, damit der      *)
  286.            (* Speicherplatz wieder freigegeben wird.      *)
  287.  
  288.   (* Auf das nächste Paket warten                         *)
  289.   ListenForPacket(Ptr(HiWord(ECB_Sel), 0));
  290. END;
  291.  
  292. PROCEDURE IPX_Event; FAR; ASSEMBLER;
  293. ASM
  294.   PUSH  ES
  295.   PUSH  DI
  296.   MOV   AX, [SI]                         (* IP vom Stapel *)
  297.   MOV   ES:[DI+2AH], AX
  298.   MOV   AX, [SI+2]                       (* CS vom Stapel *)
  299.   MOV   ES:[DI+2CH], AX
  300.   MOV   AX, Seg @Data
  301.   MOV   DS, AX
  302.   CALL  DoEvent
  303.   POP   DI
  304.   POP   ES
  305.   IRET
  306. END;
  307.  
  308. {$ELSE}
  309.  
  310. PROCEDURE IPX_Event; FAR;
  311. VAR
  312.   p       : pIPX_Packet;
  313.   UserColl: pUserColl;
  314.  
  315.   FUNCTION IsEmpty(Item: pIPX_Packet): BOOLEAN; FAR;
  316.   BEGIN
  317.     IsEmpty := Item^.Data.Command = 0;
  318.   END;
  319.  
  320. BEGIN
  321.   ASM
  322.     MOV    AX, Seg @Data
  323.     MOV    DS, AX
  324.   END;
  325.   p := BuffColl^.FirstThat(@IsEmpty);
  326.   IF p <> NIL THEN p^ := IPX_PacketBuffer^;
  327.   ListenForPacket(ECB);
  328. END;
  329. {$ENDIF}
  330.  
  331. {$IFDEF CheckStack}
  332. (* Falls Stackprüfung vorher aktiv, wieder einschalten    *)
  333.   {$S+}
  334.   {$UNDEF CheckStack}
  335. {$ENDIF}
  336. (*--------------------------------------------------------*)
  337.  
  338. CONSTRUCTOR tBuffColl.Init;
  339. VAR
  340.   i: INTEGER;
  341.   p: pIPX_Packet;
  342. BEGIN
  343.   tCollection.Init(100, 0);
  344.   FOR i := 0 TO 99 DO BEGIN
  345.     p := MemAlloc(SizeOf(tIPX_Packet));
  346.     IF p <> NIL THEN BEGIN
  347.       FillChar(p^, SizeOf(tIPX_Packet), 0);
  348.       Insert(p)
  349.     END
  350.   END
  351. END;
  352.  
  353. (* Achtung: Es kann passieren, daß hier Packets ankommen, *)
  354. (* die gar nicht in der Collection enthalten sind!        *)
  355. (* Ist zwar nicht die feine englische Art, spart aber     *)
  356. (* etwas Code.                                            *)
  357. PROCEDURE tBuffColl.ClearPacket(Packet: pIPX_Packet);
  358. BEGIN
  359.   Packet^.Data.Command := 0;
  360. {$IFNDEF Windows}
  361.   IF IndexOf(Packet) <> -1 THEN PacketInUse := FALSE
  362. {$ENDIF}
  363. END;
  364.  
  365. PROCEDURE tBuffColl.FreeItem(Item: POINTER);
  366. BEGIN
  367.   FreeMem(Item, SizeOf(tIPX_Packet));
  368. END;
  369.  
  370. {$IFNDEF Windows}
  371.  
  372. (* TRUE, wenn ein Paket empfangen wurde                   *)
  373. FUNCTION tBuffColl.PacketAvailable: BOOLEAN;
  374. BEGIN
  375.   PacketAvailable := (NOT PacketInUse)
  376.                      AND (FindUsedPacket <> NIL)
  377. END;
  378.  
  379. (* Gibt das erste benutzte Paket oder NIL zurück          *)
  380. FUNCTION tBuffColl.FindUsedPacket: pIPX_Packet;
  381.   FUNCTION NotEmpty(Item: pIPX_Packet): BOOLEAN; FAR;
  382.   BEGIN
  383.     NotEmpty := Item^.Data.Command <> 0;
  384.   END;
  385. BEGIN
  386.   FindUsedPacket := FirstThat(@NotEmpty);
  387. END;
  388.  
  389. FUNCTION tBuffColl.GetPacket: pIPX_Packet;
  390. BEGIN
  391.   GetPacket := FindUsedPacket;
  392.   PacketInUse := TRUE;
  393. END;
  394.  
  395. {$ENDIF}
  396.  
  397. CONSTRUCTOR tUserColl.Init(aReceiveSocket: WORD);
  398. BEGIN
  399.   tCollection.Init(10,5);
  400.   ReceiveSocket := aReceiveSocket;
  401.   Parent        := NIL;
  402.   FileName      := NIL;
  403. END;
  404.  
  405. DESTRUCTOR tUserColl.Done;
  406. BEGIN
  407.   IF FileName <> NIL THEN BEGIN
  408.     LogOut;
  409.     DisposeStr(FileName);
  410.   END;
  411.   tCollection.Done;
  412. END;
  413.  
  414. PROCEDURE tUserColl.FreeItem(Item: POINTER);
  415. BEGIN
  416.   FreeMem(Item,SizeOf(tIPX_WindowID))
  417. END;
  418.  
  419. FUNCTION tUserColl.ReadLogFile(VAR f: FILE): BOOLEAN;
  420. VAR
  421.   IDPtr: pIPX_WindowID;
  422. BEGIN
  423.   ReadLogFile := FALSE;
  424.   WHILE NOT EoF(f) DO BEGIN
  425.     IDPtr := MemAlloc(SizeOf(tIPX_WindowID));
  426.     IF IDPtr = NIL THEN BEGIN
  427. {$IFNDEF Windows}
  428.       Application^.OutOfMemory;
  429.                   (* Hat Borland bei TPW leider vergessen *)
  430. {$ENDIF}
  431.       Exit
  432.     END;
  433.     BlockRead(f,IDPtr^, SizeOf(tIPX_WindowID));
  434.     Insert(IDPtr)
  435.   END;
  436.   ReadLogFile := TRUE
  437. END;
  438.  
  439. {$IFDEF Windows}
  440. FUNCTION tUserColl.LogIn(aParent: pWindowsObject;
  441.                          aFileName: PathStr): BOOLEAN;
  442. {$ELSE}
  443. FUNCTION tUserColl.LogIn(aParent: pView;
  444.                          aFileName: PathStr): BOOLEAN;
  445. {$ENDIF}
  446. VAR
  447.   f: FILE;
  448.  
  449. BEGIN
  450.   LogIn := FALSE;
  451.   Parent := aParent;
  452.   Assign(f, aFileName);
  453.   IF FSearch(aFileName, '') <> '' THEN BEGIN
  454.                                    (* Logdatei vorhanden? *)
  455.     Reset(f,1);
  456.     IF NOT ReadLogFile(f) THEN Exit;
  457.   END ELSE Rewrite(f, 1);
  458.  
  459.   (* Eigene Adresse eintragen *)
  460.   BlockWrite(f, MyIPX_ID, SizeOf(MyIPX_ID)); 
  461.   BlockWrite(f, ReceiveSocket, SizeOf(ReceiveSocket));
  462.   BlockWrite(f, aParent, SizeOf(aParent));
  463.   Close(f);
  464.   LogIn := TRUE;
  465.   FileName := NewStr(aFileName);
  466.   SendCommand(wm_LoggedIn, NIL)
  467. END;
  468.  
  469. FUNCTION tUserColl.LogOut: BOOLEAN;
  470. VAR
  471.   f    : FILE;
  472.   fSize: LongInt;
  473.  
  474.   PROCEDURE DoWrite(Item: pIPX_WindowID); FAR;
  475.   BEGIN
  476.     BlockWrite(f, Item^, SizeOf(Item^));
  477.   END;
  478.  
  479. BEGIN                             (* von tUserColl.LogOut *)
  480.   Assign(f,FileName^);
  481.   Rewrite(f, 1);
  482.   ForEach(@DoWrite);
  483.   fSize := FileSize(f);
  484.   Close(f);
  485.   IF fSize = 0 THEN Erase(f)
  486.                ELSE SendCommand(wm_LoggedOut, NIL)
  487. END;
  488.  
  489. {$IFDEF Windows}
  490. PROCEDURE tUserColl.SendCommand(Command: WORD;
  491.                                 aUserData: pUserData);
  492. VAR
  493.   AnECB     : pECB;
  494.   Packet    : pIPX_Packet;
  495.   DosECB,
  496.   DosPacket : LongInt;
  497.  
  498.   PROCEDURE DoSend(Item: pIPX_WindowID); FAR;
  499.   BEGIN
  500.     FillChar(AnECB^, SizeOf(TECB), 0);
  501.     WITH AnECB^, Item^ DO BEGIN
  502.       Imm_Adr := IPX_ID.NodeAdr;
  503.       Frag_Count := 1;
  504.       Frag_Adr := Ptr(HiWord(DosPacket), 0);
  505.       Frag_Size := SizeOf(tIPX_Packet);
  506.     END;
  507.     FillChar(Packet^, SizeOf(Packet^), 0);
  508.     WITH Packet^, Item^ DO BEGIN
  509.       Dest := IPX_ID;
  510.       Dest_Socket       := Item^.Socket;
  511.       Data.SourceWin    := Parent;
  512.       Data.DestWin      := Win_ID;
  513.       Data.SourceSocket := ReceiveSocket;
  514.       Data.Command      := Command;
  515.       IF aUserData <> NIL THEN Data.UserData := aUserData^
  516.     END;
  517.     (* Nachrichten an andere Anwendungen über das Netz    *)
  518.     (* schicken                                           *)
  519.     IF IsDifferentNode(Packet) THEN
  520.       SendPacketWithoutSocket(Ptr(HiWord(DosECB), 0), AnECB)
  521.     ELSE BEGIN
  522.       Packet^.Source := MyIPX_ID;
  523.       WITH Packet^.Data DO
  524.         SendMessage(DestWin^.hWindow, Command, 0,
  525.                     LongInt(Packet))
  526.     END
  527.   END;
  528.  
  529. BEGIN
  530.   DosECB    := GlobalDosAlloc(SizeOf(TECB));
  531.   DosPacket := GlobalDosAlloc(SizeOf(tIPX_Packet));
  532.   AnECB     := Ptr(LoWord(DosECB), 0);
  533.   Packet    := Ptr(LoWord(DosPacket), 0);
  534.   ForEach(@DoSend);
  535.   GlobalDosFree(LoWord(DosECB));
  536.   GlobalDosFree(LoWord(DosPacket))
  537. END;
  538.  
  539. {$ELSE}
  540.  
  541. PROCEDURE tUserColl.SendCommand(Command: WORD;
  542.                                 aUserData: pUserData);
  543. VAR
  544.   AnECB : TECB;
  545.   Packet: tIPX_Packet;
  546.  
  547.   PROCEDURE DoSend(Item: pIPX_WindowID); FAR;
  548.   BEGIN
  549.     FillChar(AnECB,SizeOf(TECB), 0);
  550.     WITH AnECB, Item^ DO BEGIN
  551.       Imm_Adr    := IPX_ID.NodeAdr;
  552.       Frag_Count := 1;
  553.       Frag_Adr   := @Packet;
  554.       Frag_Size  := SizeOf(tIPX_Packet);
  555.     END;
  556.     FillChar(Packet, SizeOf(Packet), 0);
  557.     WITH Packet, Item^ DO BEGIN
  558.       Dest              := IPX_ID;
  559.       Dest_Socket       := Item^.Socket;
  560.       Data.SourceWin    := Parent;
  561.       Data.DestWin      := Win_ID;
  562.       Data.SourceSocket := ReceiveSocket;
  563.       Data.Command      := Command;
  564.       IF aUserData <> NIL THEN Data.UserData := aUserData^
  565.     END;
  566.     (* Nachrichten an andere Anwendungen über das Netz    *)
  567.     (* schicken                                           *)
  568.     IF IsDifferentNode(@Packet) THEN
  569.       SendPacketWithoutSocket(@AnECB)
  570.     ELSE BEGIN
  571.       Packet.Source := MyIPX_ID;
  572.       WITH Packet.Data DO
  573.         Message(DestWin, evBroadcast, Command, @Packet)
  574.     END
  575.   END;
  576.  
  577. BEGIN ForEach(@DoSend) END;
  578. {$ENDIF}
  579.  
  580. FUNCTION tUserColl.FindSender(aPacket: pIPX_Packet):
  581.                                               pIPX_WindowID;
  582.  
  583.   FUNCTION DoFind(Item: pIPX_WindowID): BOOLEAN; FAR;
  584.   BEGIN
  585.     WITH aPacket^, Item^ DO DoFind :=
  586.       (Win_ID = Data.SourceWin) AND
  587.       IsEqual(IPX_ID, Source, SizeOf(Source)) AND
  588.       (Socket = Data.SourceSocket)
  589.   END;
  590.  
  591. BEGIN
  592.   FindSender := FirstThat(@DoFind);
  593. END;
  594.  
  595. PROCEDURE tUserColl.AddUser(aPacket: pIPX_Packet);
  596. VAR
  597.   WinID: pIPX_WindowID;
  598. BEGIN
  599.   WinID := MemAlloc(SizeOf(tIPX_WindowID));
  600.   IF WinID <> NIL THEN WITH WinID^, aPacket^ DO BEGIN
  601.     Win_ID := Data.SourceWin;
  602.     IPX_ID := Source;
  603.     Socket := Data.SourceSocket;
  604.     Insert(WinID);
  605.   END
  606. {$IFNDEF Windows}
  607.    ELSE Application^.OutOfMemory
  608. {$ENDIF}
  609. END;
  610.  
  611. PROCEDURE tUserColl.DeleteUser(aPacket: pIPX_Packet);
  612. VAR
  613.   WinID: pIPX_WindowID;
  614. BEGIN
  615.   WinID := FindSender(aPacket);
  616.   IF WinID <> NIL THEN Free(WinID) ELSE BEGIN
  617. {$IFDEF Windows}
  618.     MessageBox(GetFocus,
  619.                'Ungⁿltige LogOut-Message empfangen!',
  620.                'Fehler!',
  621.                mb_OK OR mb_IconExclamation);
  622. {$ELSE}
  623.     MessageBox(^C'Ungültige Logout-Message empfangen!', NIL,
  624.                                      mfError OR mfOkButton);
  625. {$ENDIF}
  626.     BuffColl^.ClearPacket(aPacket)
  627.   END
  628. END;
  629.  
  630. CONSTRUCTOR tLogColl.Init;
  631. LABEL NoMem;                (* Da staunt der Purist . . . *)
  632. VAR
  633.   osResult: BYTE;
  634.   DOSAdr  : POINTER;
  635. BEGIN
  636.   tCollection.Init(10, 5);
  637.   IsListening := FALSE;
  638.  
  639. {$IFDEF Windows}
  640.   EventProc := MakeProcInstance(@IPX_Event, hInstance);
  641.                                          (* Event-Handler *)
  642.   CallBackAdr := GetCallBack(EventProc);
  643.                                       (* Adresse für DPMI *)
  644.   DOSAdr := InitIPX(CallBackAdr);
  645.   IF DOSAdr = NIL THEN BEGIN
  646.     MessageBox(GetFocus, 'WinNet nicht installiert!',
  647.                          NIL, mb_OK OR mb_IconHand);
  648.  
  649. {$ELSE}
  650.   IF NOT InitIPX THEN BEGIN
  651.     MessageBox('IPX nicht geladen!', NIL,
  652.                mfError OR mfOkButton);
  653. {$ENDIF}
  654.     Fail;
  655.   END;
  656.   Socket := 0;
  657.   OpenSocket(Socket, osResult, os_AutoClose);
  658.   IF osResult <> osm_SocketOk THEN BEGIN
  659.     IF osResult = osm_SocketAlreadyOpen
  660. {$IFDEF Windows}
  661.      THEN MessageBox(GetFocus,
  662.                      'Socket bereits ge÷ffnet!',
  663.                      'Fehler',
  664.                      mb_OK OR mb_IconExclamation)
  665.      ELSE MessageBox(GetFocus,
  666.                      'Keine freien Sockets mehr!', 'Fehler',
  667.                      mb_OK OR mb_IconExclamation);
  668. {$ELSE}
  669.      THEN MessageBox('Socket bereits geöffnet!', NIL,
  670.                      mfError OR mfOkButton)
  671.      ELSE MessageBox('Keine freien Sockets mehr!', NIL,
  672.                      mfError OR mfOkButton);
  673. {$ENDIF}
  674.     Fail;
  675.   END;
  676. {$IFDEF Windows}
  677.   Packet_Sel := GlobalDosAlloc(SizeOf(tIPX_Packet));
  678.   IF Packet_Sel <> 0 THEN
  679.     IPX_PacketBuffer := Ptr(LoWord(Packet_Sel), 0);
  680. {$ELSE}
  681.   IPX_PacketBuffer := MemAlloc(SizeOf(tIPX_Packet));
  682. {$ENDIF}
  683.   IF IPX_PacketBuffer = NIL THEN BEGIN
  684. NoMem:
  685.     {$IFNDEF Windows} Application^.OutOfMemory; {$ENDIF}
  686.     Fail;
  687.   END;
  688.   FillChar(IPX_PacketBuffer^,SizeOf(tIPX_Packet),0);
  689. {$IFDEF Windows}
  690.   ECB_Sel := GlobalDosAlloc(SizeOf(TECB));
  691.   IF ECB_Sel <> 0 THEN ECB := Ptr(LoWord(ECB_Sel),0);
  692. {$ELSE}
  693.   ECB := MemAlloc(SizeOf(TECB));
  694. {$ENDIF}
  695.   IF ECB = NIL THEN GOTO NoMem;
  696.                  (* GOTO is'n prima Befehl - ... manchmal *)
  697.   FillChar(ECB^,SizeOf(TECB),0);
  698.   WITH ECB^ DO BEGIN                     (* ECB ausfüllen *)
  699. {$IFDEF Windows}
  700.     ESR_Adr := DOSAdr;
  701. {$ELSE}
  702.     ESR_Adr := @IPX_Event;               (* Event-Handler *)
  703. {$ENDIF}
  704.     FillChar(Imm_Adr, SizeOf(Imm_Adr), $FF);
  705.                             (* Empfangen von allen Knoten *)
  706.     Frag_Count := 1;        (* Nur 1 Datenpaket           *)
  707. {$IFDEF Windows}
  708.     Frag_Adr := Ptr(HiWord(Packet_Sel), 0);
  709. {$ELSE}
  710.     Frag_Adr := IPX_PacketBuffer;
  711. {$ENDIF}
  712.     Frag_Size := SizeOf(tIPX_Packet)
  713.   END;
  714.   ECB^.Socket := Socket;        (* Zum Zwischenspeichern: *)
  715.   BuffColl := New(pBuffColl, Init);
  716. END;
  717.  
  718. (*-------------------  Aufräumen  ------------------------*)
  719. DESTRUCTOR tLogColl.Done;
  720. BEGIN
  721.   FreeAll;
  722.   IF Socket <> 0 THEN BEGIN
  723.     (* Eigentlich überflüssig, doch zur Sicherheit . . .: *)
  724.     StopListening;          
  725.     CloseSocket(Socket);
  726. {$IFDEF Windows}
  727.     FreeCallBack(CallBackAdr);
  728.     FreeProcInstance(EventProc);
  729.   END;
  730.   IF Packet_Sel <> 0 THEN GlobalDosFree(LoWord(Packet_Sel));
  731.   IF ECB_Sel <> 0 THEN GlobalDosFree(LoWord(ECB_Sel));
  732. {$ELSE}
  733.   END;
  734.   IF IPX_PacketBuffer <> NIL THEN
  735.     FreeMem(IPX_PacketBuffer, SizeOf(tIPX_Packet));
  736.   IF ECB <> NIL THEN FreeMem(ECB, SizeOf(TECB));
  737. {$ENDIF}
  738.   IF BuffColl <> NIL THEN Dispose(BuffColl, Done)
  739. END;
  740.  
  741. (* Ermittelt die zum Fenster gehörige User-Liste          *)
  742. {$IFDEF Windows}
  743. FUNCTION tLogColl.GetUserColl(aParent: pWindowsObject):
  744.                                                   pUserColl;
  745. {$ELSE}
  746. FUNCTION tLogColl.GetUserColl(aParent: pView): pUserColl;
  747. {$ENDIF}
  748.  
  749.   FUNCTION FindParent(Item: pUserColl): BOOLEAN; FAR;
  750.   BEGIN
  751.     FindParent := aParent = Item^.Parent;
  752.   END;
  753.  
  754. BEGIN
  755.   GetUserColl := FirstThat(@FindParent);
  756. END;
  757.  
  758. PROCEDURE tLogColl.StartListening;
  759. BEGIN
  760.   IF NOT IsListening THEN BEGIN
  761.                             (* Wird etwa schon gelauscht? *)
  762. {$IFDEF Windows}
  763.     ListenForPacket(Ptr(HiWord(ECB_Sel),0));
  764. {$ELSE}
  765.     ListenForPacket(ECB);
  766. {$ENDIF}
  767.     IsListening := TRUE
  768.   END
  769. END;
  770.  
  771. PROCEDURE tLogColl.StopListening;
  772. BEGIN
  773.   IF IsListening THEN BEGIN
  774.                         (* Wird überhaupt noch gelauscht? *)
  775.     IsListening := FALSE;
  776. {$IFDEF Windows}
  777.     CancelEvent(Ptr(HiWord(ECB_Sel),0));
  778. {$ELSE}
  779.     CancelEvent(ECB);
  780. {$ENDIF}
  781.   END
  782. END;
  783.  
  784. {$IFDEF Windows}
  785. FUNCTION tLogColl.LogIn(LogFileName: PathStr;
  786.                         aParent: pWindowsObject): pUserColl;
  787. {$ELSE}
  788. FUNCTION tLogColl.LogIn(LogFileName: PathStr;
  789.                         aParent: pView): pUserColl;
  790. {$ENDIF}
  791. VAR UserColl: pUserColl;
  792. BEGIN
  793.   LogIn := NIL;
  794.   UserColl := New(pUserColl,Init(Socket));
  795.   IF UserColl^.LogIn(aParent, LogFileName) THEN BEGIN
  796.     Insert(UserColl);
  797.     StartListening;
  798.     LogIn := UserColl
  799.   END
  800. END;
  801.  
  802. {$IFDEF Windows}
  803. FUNCTION tLogColl.LogOut(aParent: pWindowsObject): BOOLEAN;
  804. {$ELSE}
  805. FUNCTION tLogColl.LogOut(aParent: pView): BOOLEAN;
  806. {$ENDIF}
  807. VAR UserColl: pUserColl;
  808. BEGIN
  809.   LogOut := FALSE;
  810.   UserColl := GetUserColl(aParent);
  811.   IF UserColl <> NIL THEN BEGIN
  812.     Free(UserColl);
  813.     IF Count = 0 THEN StopListening; (* Letzter Lauscher? *)
  814.     LogOut := TRUE
  815.   END;
  816. END;
  817.  
  818. END.
  819.  
  820. (*========================================================*)
  821. (*                     Ende von NETLOG.PAS                *)
  822.