home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / FAQSYS18.ZIP / FAQS.DAT / IPX.DOC < prev    next >
Internet Message Format  |  1994-10-03  |  23KB

  1. From: s921878@minyos.xx.rmit.EDU.AU (Daniel John Lee Parnell)
  2. Subject: Re: IPX document in x2ftp
  3. To: jon@stekt.oulu.fi
  4. Date: Mon, 3 Oct 1994 10:34:04 +1000 (EST)
  5. Content-Type: text/plain; charset=US-ASCII
  6. Content-Length: 23154
  7.  
  8.  
  9. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  10.  
  11.          IIIIII   PPPPPP     XX         XX
  12.            II     PP    PP    XX       XX
  13.            II     PP    PP     XX     XX
  14.            II     PP    PP      XX   XX
  15.            II     PP    PP       XX XX
  16.            II     PPPPPP          XXX
  17.            II     PP             XX XX
  18.            II     PP            XX   XX
  19.            II     PP           XX     XX     How to send IPX packets over a
  20.            II     PP          XX       XX    network by Daniel Parnell
  21.          IIIIII   PP         XX         XX   s921878@minyos.xx.rmit.oz.au
  22.                                              daniel@bunyip.ph.rmit.oz.au
  23.  
  24.                                              Started : 29th March     1994
  25.                                              Last Mod:  2nd September 1994
  26.  
  27. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  28.  
  29.  
  30.   On March 24th 1994 I managed to send my first IPX packet.  This was a very
  31. exciting moment for me as it opened up a vast number of applications that
  32. were before closed to me.  NETWORKED GAMES!!!  :)    This document attempts
  33. to guide the would be IPXer in the techniques of sending IPX packets.
  34. Admittedly, it has only been 5 days since my first sucessful packet, but in
  35. that short time I have developed a set of routines that seem to work quite
  36. well.  :)   These routines are included in appendix A and an example program
  37. is included in appendix B.  These routines are written in Turbo Pascal 6.0,
  38. but should be reasonably portable to other languages.
  39.  
  40.   First of all, a little background.  IPX is a protocol that allows packets
  41. of information to be sent over a network.  These packets can be sent from one
  42. machine to another or sent to all machines (nodes).  Sending a packet to all
  43. machines is called a BROADCAST.  A broadcast will usually be confined to just
  44. the local network, however there are ways around this which I will not go
  45. into here.  ;)  These packets have a specific structure which is shown in
  46. figure 1.
  47.  
  48.                         Figure 1 - The IPX header
  49.    ------------------------------------------------------------------------
  50.    | Name          | Size (bytes) | Description                           |
  51.    ----------------|--------------|---------------------------------------|
  52.    |Check          | 2 bytes      | Bigendian check sum                   |
  53.    |Length         | 2 bytes      | Bigendian length of packet            |
  54.    |tc             | 1 byte       | Transport control (age of packet)     |
  55.    |pType          | 1 byte       | Packet type  (always use 0)           |
  56.    |dest           | 12 bytes     | Address of destination node           |
  57.    |src            | 12 bytes     | Address of source node                |
  58.    ----------------|--------------|---------------------------------------|
  59.  
  60.   By the way, bigendian means that the first byte holds the most significant
  61. value, which is the opposite of the normal way of doing things on the PC.
  62.  
  63.   For reasons better known to Novell, the checksum is always set to $ffff.
  64. The length field contains the total length of the packet, including the IPX
  65. header.  Transport control keeps a count of the number of routers a packet
  66. has been through.  The format of the address is shown in Figure 2.
  67.  
  68.                        Figure 2 - The net address field
  69.    ------------------------------------------------------------------------
  70.    | Name          | Size (bytes) | Description                           |
  71.    ----------------|--------------|---------------------------------------|
  72.    |network        | 4 bytes      | Network address                       |
  73.    |node           | 6 bytes      | Node address                          |
  74.    |socket         | 2 byte       | Socket number                         |
  75.    ----------------|--------------|---------------------------------------|
  76.  
  77.   Sockets are a device that lets a node decide if it will act on a packet.
  78. It allows multiple programs on the one PC to use IPX packets completely
  79. transparent to the others.  It also means that a broadcasted packet will only
  80. be received by a machine if it has a socket open for that which the packet is
  81. addressed.  So packets can be ignored by nodes that are not capable of
  82. accepting them.  Special care must be taken to ensure that no two programs try
  83. to send different types of packets to the same socket!
  84.  
  85.   The next order of bussiness is to tell the PC that we want to open a socket.
  86. This is accomplished by creating an Event Control Block (ECB).  Figure 3 shows
  87. the format of the ECB.
  88.  
  89.                       Figure 3 - Format of the ECB
  90.    ------------------------------------------------------------------------
  91.    | Name          | Size (bytes) | Description                           |
  92.    ----------------|--------------|---------------------------------------|
  93.    |Link           | 4 bytes      | Pointer to next ECB?                  |
  94.    |ESR            | 4 bytes      | Pointer to Event Service Routine      |
  95.    |InUse          | 1 byte       | Flag telling the ECB status           |
  96.    |complete       | 1 byte       | Flag telling the ECB completion code  |
  97.    |socket         | 2 bytes      | Bigendian socket number for ECB       |
  98.    |IPXwork        | 4 bytes      | Work space for IPX                    |
  99.    |Dwork          | 12 bytes     | Work space for driver                 |
  100.    |immedAddr      | 12 bytes     | Address to send to.                   |
  101.    |fragCount      | 2 bytes      | Number of fragments                   |
  102.    |FragData       | 4 bytes      | Pointer to data fragment              |
  103.    |FragSize       | 2 bytes      | Size of data fragment                 |
  104.    ----------------|--------------|---------------------------------------|
  105.  
  106.   All the fields in the ECB should be set to zero before initializing the ECB.
  107. This makes the code to initialize the ECB much nicer!  No ESR is used in my
  108. routines which means the the program must constantly ckeck the ECB to see if
  109. a packet has arrived.  I don't see this as any great drawback however.
  110.  
  111.   To send a broadcast, set the node address to all $ff.  This is done
  112. automatically by my routines.
  113.  
  114.   FragData must be initialized to point to the IPX header and the data we want
  115. to send MUST follow directly after this header.  An example of this can be
  116. seen in Appendix B in the definition of the record type "Packet".  The ECB
  117. need not be included in the packet record, but for simplicity I chose to do
  118. so.
  119.  
  120.   The procedures InitSendPacket and InitReceivePacket give examples of the
  121. initialization of both the ECB and IPX header.
  122.  
  123.   Once all of the fields are initialized, it is necessary to tell the IPX
  124. driver about our ECB.  This is done by first opening a socket to use.
  125. Interrupt $7A is assigned to the Novell API, and is the old way of accessing
  126. the routines.  It is however a much easier to use than the recommended method
  127. (in my opinion anyway).  The sub-functions that we use are given in Table 1.
  128.  
  129.                                 Table 1
  130. -----------------------------------------------------------------------------
  131. |Function|Name        |Regs                                                 |
  132. -----------------------------------------------------------------------------
  133. |  $0000 |Open Socket |AL=Longevity  DX=Socket number  (bigendian)          |
  134. |        |            |Returns:AL=Error code  DX=Socket Number  (bigendian) |
  135. -----------------------------------------------------------------------------
  136. |  $0001 |Close Socket|DX=Socket number  (bigendian)                        |
  137. -----------------------------------------------------------------------------
  138. |  $0003 |Send Packet |ES=Seg of ECB  SI=Offset of ECB                      |
  139. -----------------------------------------------------------------------------
  140. |  $0004 |Listen for  |ES=Seg of ECB  SI=Offset of ECB                      |
  141. |        |packet      |Returns:AL=Error code                                |
  142. -----------------------------------------------------------------------------
  143. |  $0009 |Get Local   |ES=Seg of address array   SI=Offset of address array |
  144. |        |Address     |                                                     |
  145. -----------------------------------------------------------------------------
  146. |  $000A |Im Idle     |None                                                 |
  147. -----------------------------------------------------------------------------
  148.  
  149.   NOTE:  The function number is stored in BX.
  150.  
  151.   After attempting to open a socket it is advisable to test if IPX is
  152. present.  This is done by calling int $2F with AX=$7F00.  If on return AL
  153. does not  contain $FF, then IPX is not installed.  This is also a good point
  154. to get your local address as your program should only have to do this once.
  155. See the procedure InitIPX in appendix A for an example of this.
  156.  
  157.   Once we have an open socket and some set up ECBs and IPX headers, we can
  158. tell the IPX driver about them.   First we will look at a recieving ECB and
  159. IPX header, followed by a sending.
  160.  
  161.   For a recieve record, the IPX header does not need to be initialized at all.
  162. However, I think it is a good idea to zero all the fields just be on the safe
  163. side.  The ECB however, does need to have several fields set.  The inUse flag
  164. should be set to $1D  (don't ask me why, actually it works without this, but
  165. several of the recources I consulted did this).  The socket number must be
  166. initialized, and remember, this is bigendian so be careful!  Finally the
  167. fragCount, fragData and fragSize fields must be set.  All the other fields
  168. should be set to zero!
  169.  
  170.   Once all these fields are set, call "Listen For Packet" to tell the IPX
  171. driver about the ECB.  This will return immediatly, but if any packets arrive
  172. for that socket they will be placed into the record.  To see if a packet has
  173. arrived, it is necessary to check the InUse flag in the ECB.  If this is $00,
  174. then a packet has arrived and needs to be processed before another can be
  175. accepted.  If a packet arrives when there is an unprocessed packet, then it
  176. will be lost.  This means that a packet should be processed as soon as
  177. possible.  The record can be released by simply calling "Listen For Packet"
  178. again.
  179.  
  180.   OK, we now have a recieve record waiting for a packet to arrive.  Now we
  181. need a send record!  A send record needs all of the same fields as a receive
  182. record, but on top of that it also needs the IPX header to be filled in.
  183. The checksum is set to $ffff and the packet type is set to $00 (this is a
  184. packet exchange packet).  Next the destination address is set.  For a
  185. broadcast you should set the net address to your local net address, the node
  186. sould be the broadcast node ($ff,$ff,$ff,$ff,$ff,$ff) and the socket should be
  187. set up.  Your program should set up the source address with the info from the
  188. localAddr record, and the source socket can be anything, but again, for
  189. simplicity I usually set it to the same value as the destination socket.
  190.  
  191.   We then put some data into the data portion of the record and call "Send
  192. Packet".  The packet will then be sent to the destination node on the network.
  193. If the node field is set to the broadcast address, the packet will be sent to
  194. all nodes on the network, including the source node.
  195.  
  196.   As a point of interest, you should call "Im idle" whenever your program
  197. isn't doing anything an particular to allow the IPX driver to run more
  198. quickly.
  199.  
  200.  
  201.   So there you have it.  Hopefully you should now be able to send and receive
  202. IPX packets on a network.  Have fun!
  203.  
  204.                                 Daniel Parnell
  205.  
  206. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  207.  
  208.     A    PPPPP  PPPPP  EEEEEE N       N DDDDDD  IIIII X     X         A
  209.    A A   P    P P    P E      NN      N D     D   I   X     X        A A
  210.   A   A  P    P P    P E      N N     N D     D   I   X     X       A   A
  211.  A     A P    P P    P E      N  N    N D     D   I    X   X       A     A
  212.  A     A P    P P    P E      N   N   N D     D   I     X X        A     A
  213.  AAAAAAA PPPPP  PPPPP  EEEE   N    N  N D     D   I      X         AAAAAAA
  214.  A     A P      P      E      N     N N D     D   I     X X        A     A
  215.  A     A P      P      E      N      NN D     D   I    X   X       A     A
  216.  A     A P      P      E      N       N D     D   I   X     X      A     A
  217.  A     A P      P      E      N       N D     D   I   X     X      A     A
  218.  A     A P      P      EEEEEE N       N DDDDDD  IIIII X     X      A     A
  219.  
  220. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  221.  
  222. { IPX 1.0 By Daniel Parnell 22 March 1994  s921878@minyos.xx.rmit.oz.au
  223.  
  224.   This unit allows the sending of IPX packets over a Novell network
  225.  
  226.   Use it if you want, but please give me some credit for it :)
  227.  
  228.   See the other file which is a chat program for info on how to use this unit
  229.  
  230. }
  231. unit ipx;
  232.  
  233. interface
  234.  
  235. uses dos;
  236.  
  237. type
  238.   netAddr  = array[1..4] of byte;    { The address of a network }
  239.   nodeAddr = array[1..6] of byte;    { The address of a node in a network }
  240.  
  241.   address  = array[0..1] of word;    { A pointer to the data 0=offset 1=seg }
  242.  
  243.   netAddress = record
  244.                  Net    : netAddr;   { network address }
  245.                  Node   : nodeAddr;  { node address }
  246.                  Socket : word;      { Big endian socket number}
  247.                end;
  248.  
  249.   localAddrT = record
  250.                  Net    : netAddr;   { my network address }
  251.                  Node   : nodeAddr;  { my node address }
  252.                end;
  253.  
  254.   ECBType = record
  255.               link      : address;    { Pointer to next ECB? }
  256.               ESR       : address;    { Event Service Routine 00000000h if none }
  257.               inUse     : byte;       { In use flag }
  258.               complete  : byte;       { Completeing flag }
  259.               socket    : word;       { Big endian socket number }
  260.               IPXwork   : array[1..4] of byte;  { IPX work space }
  261.               Dwork     : array[1..12] of byte; { Driver work space }
  262.               immedAddr : nodeAddr;   { Immediate local node address }
  263.               fragCount : word;       { Fragment count }
  264.               fragData  : address;    { Pointer to data fragment }
  265.               fragSize  : word;       { Size of data fragment }
  266.             end;
  267.  
  268.   IPXheader = record
  269.                 check  : word;                { big endian checksum }
  270.                 length : word;                { big endian length in bytes }
  271.                 tc     : byte;                { transport control }
  272.                 pType  : byte;                { packet type }
  273.                 dest   : netAddress;          { destination network address }
  274.                 src    : netAddress;          { source network address }
  275.               end;
  276.  
  277. const
  278.   MYSOCKET  : word = $869C;        { This is the DOOM official socket number }
  279.   BROADCAST : nodeAddr = ($ff,$ff,$ff,$ff,$ff,$ff);  { Address for broadcast }
  280.  
  281. var
  282.   localAddr    : localAddrT;
  283.  
  284. function  IPXopenSocket(longevity : byte; var socketNumber : word):byte;
  285. procedure IPXcloseSocket(socketNumber : word);
  286. procedure GetLocalAddress;
  287. procedure IPXsendPacket(var E : ECBtype);
  288. function  IPXlistenForPacket(var E : ECBtype):byte;
  289. procedure ImIdle;
  290. procedure InitSendPacket(var ecb : ecbType; var ipx : ipxHeader; size,sock : word);
  291. procedure InitReceivePacket(var ecb : ecbType; var ipx : ipxHeader; size,sock : word);
  292. procedure InitIPX;
  293.  
  294. implementation
  295.  
  296. { Open a socket
  297.   PARAMS:  longevity = $00 for open till close or terminate
  298.                      = $ff for open till close  use for TSR
  299.  
  300.            socketNumber = 0 for dynamic allocation
  301.                         = anything else
  302.  
  303.   RETURNS: completion code $00 = success
  304.                            $fe = socket table full
  305.                            $ff = socket already open }
  306. function IPXopenSocket(longevity : byte; var socketNumber : word):byte;
  307. var
  308.   regs : registers;
  309.  
  310. begin
  311.   regs.bx:=$0000;
  312.   regs.al:=longevity;
  313.   regs.dx:=swap(socketNumber);
  314.  
  315.   intr($7A,regs);
  316.  
  317.   if socketNumber=$0000 then
  318.     socketNumber:=swap(regs.dx);
  319.  
  320.   IPXopenSocket:=regs.al;
  321. end;
  322.  
  323. { Close a socket
  324.   PARMS:  socketNumber = a socket to close }
  325. procedure IPXcloseSocket(socketNumber : word);
  326. var
  327.   regs : registers;
  328.  
  329. begin
  330.   regs.bx:=$0001;
  331.   regs.dx:=swap(socketNumber);
  332.  
  333.   intr($7A,regs);
  334. end;
  335.  
  336. { Get my address and put it into the local address array! }
  337. procedure GetLocalAddress;
  338. var
  339.   regs : registers;
  340.  
  341. begin
  342.   regs.bx:=$0009;
  343.   regs.es:=seg(localAddr);
  344.   regs.si:=ofs(localAddr);
  345.   intr($7A,regs);
  346. end;
  347.  
  348. { Send an IPX packet
  349. PARAMS:  var E = an initialized Event Control Block }
  350. procedure IPXsendPacket(var E : ECBtype);
  351. var
  352.   regs : registers;
  353.  
  354. begin
  355.   regs.bx:=$0003;
  356.   regs.es:=seg(E);
  357.   regs.SI:=ofs(E);
  358.  
  359.   intr($7A,regs);
  360. end;
  361.  
  362. { Listen for an IPX packet
  363. PARAMS:  var E = an initialize Event Control Block
  364.  
  365. RETURNS: 0 for OK, nonzero for an error ????}
  366. function IPXlistenForPacket(var E : ECBtype):byte;
  367. var
  368.   regs : registers;
  369.  
  370. begin
  371.   regs.bx:=$0004;
  372.   regs.es:=seg(E);
  373.   regs.SI:=ofs(E);
  374.  
  375.   intr($7A,regs);
  376.  
  377.   IPXlistenForPacket:=regs.al;
  378. end;
  379.  
  380. { Tell the IPX driver that we aren't doing anything at the moment }
  381. procedure ImIdle;
  382. var
  383.   regs : registers;
  384.  
  385. begin
  386.   regs.bx:=$000A;
  387.  
  388.   intr($7A,regs);
  389. end;
  390.  
  391. { Set up the fields in a send IPX record }
  392. procedure InitSendPacket(var ecb : ecbType; var ipx : ipxHeader; size,sock : word);
  393. begin
  394.   fillChar(ecb,sizeOf(ecb),#0);
  395.   fillChar(ipx,sizeOf(ipx),#0);
  396.   with ecb do
  397.     begin
  398.       socket:=swap(sock);               { Big endian socket number }
  399.       fragCount:=1;                     { Fragment count }
  400.       fragData[0]:=ofs(IPX);            { Pointer to data fragment }
  401.       fragData[1]:=seg(IPX);
  402.       fragSize:=sizeof(IPX)+size;       { Size of data fragment }
  403.       immedAddr:=BROADCAST;             { Needs to be BROADCAST?? }
  404.     end;
  405.  
  406.   with ipx do
  407.     begin
  408.       check:=$ffff;                     { NO CHECKSUM }
  409.       ptype:=0;                         { Packet exchange packet }
  410.       dest.net:=localAddr.net;          { Send to this network }
  411.       dest.node:=BROADCAST;             { Send to everybody! }
  412.       dest.socket:=swap(sock);          { Send to my socket }
  413.       src.net:=localAddr.net;           { From this net }
  414.       src.node:=localAddr.node;         { From ME }
  415.       src.socket:=swap(sock);           { From my socket }
  416.     end;
  417. end;
  418.  
  419. { Set up the fields in a recieve IPX record }
  420. procedure InitReceivePacket(var ecb : ecbType; var ipx : ipxHeader; size,sock : word);
  421. begin
  422.   fillChar(ecb,sizeOf(ecb),#0);
  423.   fillChar(ipx,sizeOf(ipx),#0);
  424.   with ecb do
  425.     begin
  426.       inUse:=$1d;                               { ???? }
  427.       socket:=swap(sock);                       { Big endian socket number }
  428.       fragCount:=1;                             { Fragment count }
  429.       fragData[0]:=ofs(IPX);                    { Pointer to data fragment }
  430.       fragData[1]:=seg(IPX);
  431.       fragSize:=sizeof(IPX)+size;               { Size of data fragment }
  432.     end;
  433.  
  434.   if IPXlistenForPacket(ecb)<>0 then ;          { Tell IPX to listen }
  435. end;
  436.  
  437. { Set up IPX and get the local address }
  438. procedure InitIPX;
  439. var
  440.   i    : integer;
  441.   regs : registers;
  442.  
  443. begin
  444.   regs.ax:=$7A00;
  445.   intr($2f,regs);
  446.  
  447.   if regs.al<>255 then
  448.     begin
  449.       writeln('ERROR WHILE INITIALIZING IPX!');
  450.       halt(1);
  451.     end;
  452.  
  453.   getLocalAddress;
  454. end;
  455.  
  456.  
  457. begin
  458. end.
  459.  
  460. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  461.  
  462.     A    PPPPP  PPPPP  EEEEEE N       N DDDDDD  IIIII X     X      BBBBBB
  463.    A A   P    P P    P E      NN      N D     D   I   X     X      B     B
  464.   A   A  P    P P    P E      N N     N D     D   I   X     X      B     B
  465.  A     A P    P P    P E      N  N    N D     D   I    X   X       B     B
  466.  A     A P    P P    P E      N   N   N D     D   I     X X        B     B
  467.  AAAAAAA PPPPP  PPPPP  EEEE   N    N  N D     D   I      X         BBBBBB
  468.  A     A P      P      E      N     N N D     D   I     X X        B     B
  469.  A     A P      P      E      N      NN D     D   I    X   X       B     B
  470.  A     A P      P      E      N       N D     D   I   X     X      B     B
  471.  A     A P      P      E      N       N D     D   I   X     X      B     B
  472.  A     A P      P      EEEEEE N       N DDDDDD  IIIII X     X      BBBBBB
  473.  
  474. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  475.  
  476. program CHAT;
  477. uses CRT,IPX;
  478.  
  479. type
  480.   Packet = record
  481.              ecb  : ECBType;
  482.              IPX  : IPXheader;
  483.              data : string;
  484.            end;
  485.  
  486. var
  487.   send,receive : Packet;
  488.  
  489. procedure Main;
  490.   
  491. var
  492.   line   : string;
  493.   y      : integer;
  494.   done   : boolean;
  495.   k      : char;
  496.   i      : integer;
  497.   handle : string;
  498.  
  499. begin
  500.   ClrScr;
  501.   writeln('CHATER BOX v0.5 By Daniel Parnell  25th March 1994');
  502.   writeln;
  503.   write('Enter your handle :');
  504.   readln(handle);
  505.  
  506.   window(1,1,80,23);
  507.   textBackground(Blue);
  508.   textColor(Yellow);
  509.   clrScr;
  510.   window(1,24,80,25);
  511.   textBackground(Red);
  512.   textColor(Yellow);
  513.   clrScr;
  514.  
  515.   y:=1;
  516.   line:='';
  517.   done:=FALSE;
  518.  
  519.   repeat
  520.     repeat
  521.     until KeyPressed or (receive.ecb.inuse=0);
  522.  
  523.     if receive.ecb.inuse=0 then
  524.       begin
  525.         window(1,1,80,23);
  526.         gotoXY(1,y);
  527.         textBackground(Blue);
  528.         textColor(Yellow);
  529.         writeln(receive.data);
  530.         y:=WhereY;
  531.         if IPXlistenForPacket(receive.ecb)<>0 then
  532.           begin
  533.             writeln(#7,'ERROR TRYING TO receive A PACKET!');
  534.             halt(2);
  535.           end;
  536.  
  537.         window(1,24,80,25);
  538.         GotoXY(1,length(line)+1);
  539.  
  540.       end;
  541.  
  542.     if KeyPressed then
  543.       begin
  544.         k:=ReadKey;
  545.         case k of
  546.           #13 : if line<>'' then
  547.                   begin
  548.                     send.data:='<<'+handle+'>>'+line;
  549.  
  550.                     with send.ecb do
  551.                       for i:=1 to 6 do
  552.                         ImmedAddr[i]:=$ff;
  553.  
  554.                     repeat
  555.                     until send.ecb.inuse=0;
  556.  
  557.                     IPXsendPacket(send.ecb);
  558.                     line:='';
  559.                   end;
  560.           #8  : if length(line)>0 then
  561.                   line:=copy(line,1,length(line)-1);
  562.           #0  : k:=ReadKey;
  563.           #27 : done:=TRUE;
  564.         else
  565.           if length(line)<79 then
  566.             line:=line+k
  567.           else
  568.             begin
  569.               sound(1000);
  570.               delay(100);
  571.               noSound;
  572.             end;
  573.         end;
  574.  
  575.         window(1,24,80,25);
  576.         textBackground(Red);
  577.         textColor(Yellow);
  578.         GotoXY(1,1); clreol; write(line);
  579.       end;
  580.   until done;
  581. end;
  582.  
  583. begin
  584.   if IPXopenSocket(0,MYSOCKET)=0 then
  585.     begin
  586.       InitIPX;
  587.  
  588.       with send do
  589.         InitSendPacket(ecb,ipx,sizeof(String),MYSOCKET);
  590.       with receive do
  591.         InitReceivePacket(ecb,ipx,sizeof(String),MYSOCKET);
  592.  
  593.       Main;
  594.  
  595.       IPXcloseSocket(MYSOCKET);
  596.     end;
  597.  
  598.   TextColor(LightGray);
  599.   TextBackground(Black);
  600.   window(1,1,80,25);
  601.   clrScr;
  602. end.
  603. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  604. Daniel Parnell  -  Email to s921878@minyos.xx.rmit.oz.au - AMIGA 500&600 1 MEG
  605.  Second Year Applied Physics student at R.M.I.T. Melbourne Australia.   *:|()
  606.    People who drink petrol shouldn't smoke.  AMOS 1.36 with Compiler and 3D
  607.     Squaxx Dek Thargo from prog 579 - C64 Amiga Mac CCPM 6502 8086 - Forth 
  608.  
  609.  
  610.