home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / MCC Utils / MCTCPComms.p < prev   
Encoding:
Text File  |  1994-05-04  |  25.8 KB  |  863 lines  |  [TEXT/PJMM]

  1. {This document is formated in monaco 9 pt                                          }
  2. {                                                                                  }
  3. {LEGAL STUFF                                                                       }
  4. {                                                                                  }
  5. {Copyright © 1994 by University of Melbourne. All Rights Reserved. This work is    }
  6. {provided "as is" and without any express or implied warranties, including,        }
  7. {without limitation, the implied warranties of merchantability and fitness         }
  8. {for a particular purpose.                                                         }
  9. {                                                                                  }
  10. {University of Melbourne is not responsible for the consequences of the use of this}
  11. {work, regardless of the cause. You may use this work in a public domain,          }
  12. {freeware, or shareware product with no restrictions, as long as you include       }
  13. {the following notice in your product's about box or splash screen:                }
  14. {  "Portions Copyright © 1994 by University of Melbourne".                         }
  15. {If you use more than 50 lines of this work, please credit the author also:        }
  16. {  "Portions by Michael Cutter"                                                    }
  17. {Public domain is defined as something that you release to the public, without     }
  18. {copyright and without restrictions on use. Freeware is a copyrighted work,        }
  19. {for which you charge no money. Shareware is a copyrighted work for which you      }
  20. {charge a fee if the user decides to keep it. If you intend to use this work       }
  21. {in a commercial product, please contact us.                                       }
  22. {                                                                                  }
  23. {                                                                                  }
  24. {OTHER STUFF                                                                       }
  25. {                                                                                  }
  26. {AUTHOR:                                                                           }
  27. { Michael Trevor Cutter                                                            }
  28. {                                                                                  }
  29. {CONTACT:                                                                          }
  30. {  Internet:                                                                       }
  31. {    mtc@arbld.unimelb.edu.au (Preferred)                                          }
  32. {  Snail Mail:                                                                     }
  33. {    Dept of Architecture & Building                                               }
  34. {    University of Melbourne                                                       }
  35. {    Parkville VIC 3052                                                            }
  36. {    AUSTRALIA                                                                     }
  37. {                                                                                  }
  38. {PERSONAL STUFF                                                                    }
  39. {  I'd really appreciate it if you'd let me know what you're using my code         }
  40. {  in, (send me email or a postcard). Please report any bugs or errors to me.      }
  41. {                                                                                  }
  42. {MODULE DESCRIPTION                                                                }
  43. {These functions provide a very simple interface to Peter N Lewis' fantastic TCP   }
  44. {libraries, which I hope are somewhere else on this disc. It's best used for       }
  45. {local - server transaction type connections, where you don't expect the connection}
  46. {to close suddenly on you or anything. Peter, I know you hate exit(), but I like   }
  47. {the way it neatens my code. I think it does, anyway :-)                           }
  48.  
  49. unit MCTCPComms;
  50. interface
  51.     uses
  52.         AppleTalk, Processes, PPCToolBox, EPPC, Notification, AppleEvents,{}
  53.         TCPTypes, TCPStuff, TCPConnections, MCHandlesAndStrs, MCCursor, MCConversions;
  54.  
  55. {check for MacTCP}
  56.     function MCIsMacTCPThere: boolean;
  57.  
  58. {initialize all globals used in the following procedures}
  59.     procedure MCTCPInitGlobals;
  60.  
  61. {returns a user readable error message as a str}
  62.     function MCTCPErrToString (err: OSErr;
  63.                                     var fatalerror: boolean): Str255; {sets fatal error to true if fatal}
  64.  
  65. {returns first 3 characters of string as a number - standard for codes for TCP communications}
  66.     function MCTCPCodeOfStr (str: str255): integer;
  67.  
  68. {Call this function before opening _any_ TCP connections, cause it will probably kill them}
  69.     function MCTCPGetMyIP: Str255;
  70.  
  71. {Call this function to get MacTCP going and ready to create connections}
  72.     function MCTCPStart: OSErr;
  73.  
  74. {Call this procedure to finish up using MacTCP}
  75.     procedure MCTCPStop;
  76.  
  77. {Call this function to check an address exists}
  78.     function MCTCPCheckAddress (ipaddress: Str255): OSErr;
  79.  
  80. {all timeouts are in seconds}
  81.  
  82. {Call this function to open a connection to a port - ip number should be of form:}
  83. {'xxx.xxx.xxx.xxx'}
  84. {timeout is in seconds. Use timeout = 0 to use default maximum, and use timeout < 0}
  85. {to wait forever}
  86.     function MCTCPOpenConnection (ipnumber: Str255;
  87.                                     portNo: integer;
  88.                                     var connIndx: connectionIndex;
  89.                                     timeout: longint;
  90.                                     dowaitnextevent: Boolean): OSErr;
  91.  
  92. {call this function to wait for a connection on the given port number, from the given ipnumber}
  93.     function MCTCPOpenPassiveConxn (ipnumber: Str255;
  94.                                     portNo: integer;
  95.                                     var connIndx: connectionIndex;
  96.                                     timeout: longint;
  97.                                     dowaitnextevent: Boolean): OSErr;
  98.  
  99. {Call this procedure to close a connection }
  100.     procedure MCTCPCloseConnection (var connIndx: connectionIndex);
  101.  
  102. {Call this function to send a line stored as a hndl}
  103.     function MCTCPSendHndlLine (connIndx: connectionIndex;
  104.                                     hmsg: Handle;
  105.                                     dontaddlinefeed: Boolean): OSErr;
  106.  
  107. {Call this function to send a line as a string}
  108.     function MCTCPSendStrLine (connectionID: connectionIndex;
  109.                                     msg: Str255;
  110.                                     dontaddlinefeed: Boolean): OSErr;
  111.  
  112. {not normally called by outside proc, but I put it in the interface because I was lazy :-)}
  113.     procedure CallProgBarProc (dlog: DialogPtr;
  114.                                     value: longint;
  115.                                     p: ProcPtr);
  116.     inline
  117.         $205F, $4E90;
  118.  
  119. {Call this function to receive a line as a handle}
  120. {timeout is in seconds. Use timeout = 0 to use default maximum, and use timeout < 0}
  121. { to wait forever}
  122.     function MCTCPRcvHndlLine (connIndx: connectionIndex;
  123.                                     var hmsg: Handle;
  124.                                     timeout: longint;
  125.                                     dowaitnextevent: Boolean;
  126.                                     handleaeevents: Boolean;
  127.                                     callbackproc: ProcPtr;
  128.                                     progdlog: DialogPtr): OSErr;
  129.  
  130. {Call this function to receive a line as a string}
  131. {timeout is in seconds. Use timeout = 0 to use default maximum, and use timeout < 0}
  132. { to wait forever}
  133.     function MCTCPRcvStrLine (connectionID: connectionIndex;
  134.                                     var msg: Str255;
  135.                                     timeout: longint;
  136.                                     dowaitnextevent: Boolean;
  137.                                     handleaeevents: Boolean;
  138.                                     callbackproc: ProcPtr;
  139.                                     progdlog: DialogPtr): OSErr;
  140.  
  141. implementation
  142.     const
  143.         MAX_WAIT_FOR_SERVER = 60; {maximum number of seconds to wait for server if timedout = 0}
  144.         MAX_PASSIVE_WAIT = 60 * 60 * 24 * 365;{a year should be enough}
  145.  
  146.         LineFeedCode = $0A;
  147.         ReturnCode = $0D;
  148.  
  149.     const
  150.         ipfailedtoopen = 2;
  151.         iptimedoutonopen = -23900; {defined by mtc, not apple}
  152.         ipOpenProtErr = -23030;
  153.         ipCloseProtErr = -23031;
  154.         ipBadWDSErr = -23034;
  155.         icmpEchoTimeoutErr = -23035;
  156.  
  157.     var
  158.         gMCTCPStarted: Boolean;
  159.         gMCTCPStopped: Boolean;
  160.  
  161.     function MCIsMacTCPThere: boolean;
  162.         var
  163.             myerr: OSErr;
  164.             myfeature: longint;
  165.             myBit: integer;
  166.     begin
  167.         myerr := Gestalt('mtcp', myFeature);
  168.         if myErr = noErr then    {because it can't be a valid selector unless MacTCP is actually }
  169. {installed anyway}
  170.             begin
  171.                 MCIsMacTCPThere := true
  172.             end
  173.         else
  174.             MCIsMacTCPThere := false;
  175.     end;
  176.  
  177.     procedure MCTCPInitGlobals;
  178.     begin
  179.         gMCTCPStarted := false;
  180.         gMCTCPStopped := false;
  181.     end;
  182.  
  183.     function MCTCPErrToString;
  184.     begin
  185.         fatalerror := false;
  186.         case err of
  187.             noErr: 
  188.                 MCTCPErrToString := '';
  189.  
  190.  
  191. {specially defined errors}
  192.  
  193. {2}
  194.             ipfailedtoopen: 
  195.                 begin
  196.                     MCTCPErrToString := 'The server is not available.';
  197.                     fatalerror := true;
  198.                 end;
  199.  
  200. {-23900}
  201.             iptimedoutonopen: 
  202.                 begin
  203.                     MCTCPErrToString := 'The server does not respond to connection request.';
  204.                     fatalerror := true;
  205.                 end;
  206.  
  207.  
  208. {standard errors}
  209.  
  210. {-23000}
  211.             ipBadLapErr: 
  212.                 begin
  213.                     MCTCPErrToString := 'TCP Bad network configuration.';
  214.                     fatalerror := true;
  215.                 end;
  216. {-23001}
  217.             ipBadCnfgErr: 
  218.                 begin
  219.                     MCTCPErrToString := 'TCP Bad IP configuration error.';
  220.                     fatalerror := true;
  221.                 end;
  222. {-23002}
  223.             ipNoCnfgErr: 
  224.                 begin
  225.                     MCTCPErrToString := 'TCP Missing IP or LAP configuration error.';
  226.                     fatalerror := true;
  227.                 end;
  228. {-23003}
  229.             ipLoadErr: 
  230.                 begin
  231.                     MCTCPErrToString := 'MacTCP is not, or could not be loaded.';
  232.                     fatalerror := true;
  233.                 end;
  234. {-23004}
  235.             ipBadAddr: 
  236.                 begin
  237.                     MCTCPErrToString := 'TCP Could not find the requested server.';
  238.                     fatalerror := true;
  239.                 end;
  240. {-23005}
  241.             connectionClosing: 
  242.                 MCTCPErrToString := 'TCP Connection is closing.';
  243. {-23006}
  244.             invalidLength: 
  245.                 MCTCPErrToString := 'TCP Invalid length.';
  246. {-23007}
  247.             connectionExists: 
  248.                 MCTCPErrToString := 'TCP Request conflicts with existing connection.';
  249. {-23008}
  250.             connectionDoesntExist: 
  251.                 MCTCPErrToString := 'TCP Connection does not exist. ';
  252. {-23009}
  253.             insufficientResources: 
  254.                 MCTCPErrToString := 'TCP Insufficient resources to perform request . ';
  255. {-23010}
  256.             invalidStreamPtr: 
  257.                 MCTCPErrToString := 'TCP Invalid stream.';
  258. {-23011}
  259.             streamAlreadyOpen: 
  260.                 MCTCPErrToString := 'TCP Stream already open.';
  261. {-23012}
  262.             connectionTerminated: 
  263.                 MCTCPErrToString := 'TCP Connection terminated unexpectedly.';
  264. {-23013}
  265.             invalidBufPtr: 
  266.                 MCTCPErrToString := 'TCP Invalid BuffPtr.';
  267. {-23014}
  268.             invalidRDS: 
  269.                 MCTCPErrToString := 'TCP Invalid RDS.';
  270. {-23015}
  271.             openFailed: 
  272.                 MCTCPErrToString := 'TCP Open connection failed.';
  273. {-23016}
  274.             commandTimeout: 
  275.                 MCTCPErrToString := 'TCP Server failed to respond to command.';
  276. {-23017}
  277.             duplicateSocket: 
  278.                 MCTCPErrToString := 'TCP duplicate socket.';
  279. {-23030}
  280.             ipOpenProtErr: 
  281.                 MCTCPErrToString := 'TCP Can’t open new protocol , table full.';
  282. {-23031}
  283.             ipCloseProtErr: 
  284.                 MCTCPErrToString := 'TCP Can’t find protocol to close . ';
  285. {-23032}
  286.             ipDontFragErr: 
  287.                 MCTCPErrToString := 'TCP Packet too large to send w/o fragmenting.';
  288. {-23033}
  289.             ipDestDeadErr: 
  290.                 MCTCPErrToString := 'TCP Destination not responding.';
  291. {-23034}
  292.             ipBadWDSErr: 
  293.                 MCTCPErrToString := 'TCP Error in WDS format.';
  294. {-23035}
  295.             icmpEchoTimeoutErr: 
  296.                 MCTCPErrToString := 'TCP ICMP echo timed-out.';
  297. {-23036}
  298.             ipNoFragMemErr: 
  299.                 MCTCPErrToString := 'TCP No memory to send fragmented pkt.';
  300. {-23037}
  301.             ipRouteErr: 
  302.                 MCTCPErrToString := 'TCP Can’t route packet off - net.';
  303. {-23041}
  304.             nameSyntaxErr: 
  305.                 MCTCPErrToString := 'TCP Name syntax error.';
  306. {-23042}
  307.             cacheFault: 
  308.                 MCTCPErrToString := 'TCP Cache fault.';
  309. {-23043}
  310.             noResultProc: 
  311.                 MCTCPErrToString := 'TCP No result procedure.';
  312. {-23044}
  313.             noNameServer: 
  314.                 MCTCPErrToString := 'TCP No name server.';
  315. {-23045}
  316.             authNameErr: 
  317.                 MCTCPErrToString := 'TCP Name authorisation error.';
  318. {-23046}
  319.             noAnsErr: 
  320.                 MCTCPErrToString := 'TCP No answer error.';
  321. {-23047}
  322.             dnrErr: 
  323.                 MCTCPErrToString := 'TCP dnr error.';
  324. {-23048}
  325.             outOfMemory: 
  326.                 begin
  327.                     MCTCPErrToString := 'TCP Out of memory.';
  328.                     fatalerror := true;
  329.                 end;
  330.  
  331.             otherwise
  332.                 MCTCPErrToString := concat('unknown error:', MCNumToString(err));
  333.         end;
  334.     end;
  335.  
  336. {returns first 3 characters of string as a number - standard for codes for TCP communications}
  337.     function MCTCPCodeOfStr;
  338.         var
  339.             total: longint;
  340.     begin
  341.         delete(str, 4, length(str) - 3);
  342.         StringToNum(str, total);
  343.         MCTCPCodeOfStr := total;
  344.     end;
  345.  
  346.     function MCTCPGetMyIP;
  347.         var
  348.             myipstr: str255;
  349.             myip: longint;
  350.         procedure CatchOSErr (err: OSErr);
  351.         begin
  352.             if err <> noErr then
  353.                 begin
  354.                     MCTCPGetMyIP := '';
  355.                     exit(MCTCPGetMyIP);
  356.                 end;
  357.         end;
  358.     begin
  359.         {make sure that MacTCP is awake}
  360.         CatchOSErr(MCTCPStart);
  361.  
  362.         {get our IP address}
  363.         CatchOSErr(TCPGetMyIPAddr(myip));
  364.  
  365.         {find the string version of the ip number}
  366.         FindString(myip, myipstr);
  367.  
  368.         {close all connections}
  369.         MCTCPStop;
  370.  
  371.         MCTCPGetMyIP := myipstr;
  372.     end;
  373.  
  374.     function MCTCPStart;
  375.         var
  376.             err: OSErr;
  377.     begin
  378. {should modify to use Gestalt to check for MacTCP}
  379.         MCTCPStart := noErr;
  380.         if not MCIsMacTCPThere then
  381.             begin
  382.                 MCTCPStart := ipLoadErr;
  383.                 gMCTCPStarted := false;
  384.             end
  385.         else if not gMCTCPStarted then {don't start them again!}
  386.             begin
  387.                 err := InitConnections;
  388.                 if err <> noErr then
  389.                     MCTCPStart := err
  390.                 else
  391.                     begin
  392.                         gMCTCPStarted := true;
  393.                         gMCTCPStopped := false;
  394.                     end;
  395.             end; {otherwise is already started, so don't worry about it}
  396.     end;
  397.  
  398.     procedure MCTCPStop;
  399.     begin
  400.         if (not gMCTCPStopped) and (gMCTCPStarted) then {don't stop them again!}
  401.             begin
  402.                 FinishEverything;
  403.                 gMCTCPStopped := true;
  404.                 gMCTCPStarted := false;
  405.             end;
  406.     end;
  407.  
  408. {Call this function to check an address}
  409. {MCTCPStart should have already been called.}
  410.     function MCTCPCheckAddress (ipaddress: Str255): OSErr;
  411.         var
  412.             myconnIndx: connectionIndex;
  413.             conEvtRec: connectionEventRecord; { Event record for TCP events, similar to EventRecord }
  414.             myErr: OSErr;
  415.             gotResponse: Boolean;
  416.     begin
  417.         MCTCPCheckAddress := noErr;
  418.         if not gMCTCPStarted then
  419.             MCTCPCheckAddress := ipLoadErr
  420.         else
  421.             begin{-23003?}
  422.                 myconnIndx := 0;
  423.                 myErr := FindAddress(myconnIndx, ipaddress, nil);
  424.                 if myErr <> noErr then
  425.                     MCTCPCheckAddress := myErr
  426.                 else
  427.                     begin
  428.                         gotResponse := false;
  429.                         while not gotResponse do
  430.                             if GetConnectionEvent(any_connection, conEvtRec) then {look for an event on the connection, no mask}
  431.                                 begin { Get the next TCP event }
  432.  
  433.                                     case conEvtRec.event of    {case the event of}
  434.                                         C_Found: 
  435.                                             begin
  436.                                                 MCTCPCheckAddress := noErr;
  437.                                                 gotResponse := true;
  438.                                             end;
  439.  
  440.                                         C_SearchFailed:     {couldn't find the address!}
  441.                                             begin
  442.                                                 MCTCPCheckAddress := -23004;{bad address}
  443.                                                 gotResponse := true;
  444.                                             end;
  445.                                         otherwise
  446.                                             ;
  447.                                     end;
  448.                                 end;
  449.                     end;
  450.             end;
  451.     end;
  452.  
  453.     function MCTCPOpenConnection;
  454. {MCTCPStart should have already been called}
  455.         var
  456.             myip: longint; {just to make sure MacTCP is awake, and has allocated us an IP number}
  457.             conEvtRec: connectionEventRecord; { Event record for TCP events, similar to EventRecord }
  458.             connectionOpened: Boolean;
  459.             starttime, endtime: longint;
  460.             ignoreResult: Boolean;
  461.             event: EventRecord;
  462.  
  463.         procedure CatchOSErr (err: OSErr);
  464.         begin
  465.             if err <> noerr then
  466.                 begin
  467.                     MCTCPOpenConnection := err;
  468.                     if connectionOpened then
  469.                         CloseConnection(conEvtRec.connection); { Close our side of the connection }
  470.                     exit(MCTCPOpenConnection);
  471.                 end;
  472.         end;
  473.  
  474.     begin
  475.         connectionOpened := false;
  476.         MCTCPOpenConnection := noErr;
  477.         if not gMCTCPStarted then
  478.             CatchOSErr(ipLoadErr);{-23003?}
  479.  
  480.         connIndx := 0;
  481.  
  482.         CatchOSErr(FindAddress(connIndx, ipnumber, nil));
  483.  
  484.         {get our IP address}
  485.         CatchOSerr(TCPGetMyIPAddr(myip));
  486.  
  487. {enter loop to wait for the found event, and for the connection response from the server}
  488. {use negative time out if wait forever}
  489.         if timeout = 0 then
  490.             timeout := MAX_WAIT_FOR_SERVER;
  491.         if timeout > 0 then
  492.             begin
  493.                 starttime := TickCount;
  494.                 endtime := starttime + timeout * 60;
  495.             end;
  496.         while not connectionOpened do
  497.             begin
  498.                 MCNextAnimCursor;
  499.                 if dowaitnextevent then
  500.                     ignoreResult := WaitNextEvent(everyEvent, event, 60, nil);
  501.                 if timeout > 0 then
  502.                     if (TickCount > endtime) then
  503.                         CatchOSErr(iptimedoutonopen);
  504.                 if GetConnectionEvent(any_connection, conEvtRec) then {look for an event on the connection, no mask}
  505.                     begin { Get the next TCP event }
  506.  
  507.                         case conEvtRec.event of    {case the event of}
  508.                             C_Found: 
  509.                                 begin
  510.                                     CatchOSErr(NewActiveConnection(connIndx, Default_TCPBUFFERSIZE, conEvtRec.value, portNo, nil));
  511.                                 end;
  512.  
  513.                             C_SearchFailed:     {couldn't find the address!}
  514.                                 begin
  515.                                     CatchOSErr(-23004);{bad address}
  516.                                 end;
  517.  
  518.                             C_Established:     { Happens once per succesful connection establishment }
  519.                                 begin
  520.                                     connectionOpened := true;
  521.                                 end;
  522.  
  523.                             C_FailedToOpen: 
  524.                                 begin
  525.                                     CatchOSErr(conEvtRec.value);
  526.                                 end;
  527.  
  528.                             C_Closing: 
  529.                                 begin
  530.                             { Gets called when the connection starts closing down - shouldn't happen in this loop}
  531.                                     CloseConnection(conEvtRec.connection); { Close our side of the connection }
  532.                                 end;
  533.  
  534.                             C_Closed: 
  535.                                 begin
  536.                                     CatchOSErr(-23012); {connection terminated unexpectedly}
  537.                                 end;
  538.                             otherwise
  539.                                 ;
  540.                         end;
  541.                     end;{iff}
  542.             end;{while}
  543.     end;
  544.  
  545. {this function exits as soon as it finds the server and tries to connect to it. You should immediately go into}
  546. {a wait if the function succeeds, checking for open connection events. Don't forget to make sure there is a }
  547. {WaitNextEvent in the waiting loop. Also, don't forget to allow for quit events.}
  548.     function MCTCPOpenPassiveConxn (ipnumber: Str255;
  549.                                     portNo: integer;
  550.                                     var connIndx: connectionIndex;
  551.                                     timeout: longint;
  552.                                     dowaitnextevent: Boolean): OSErr;
  553. {MCTCPStart must have already been called}
  554.         var
  555.             myip: longint; {just to make sure MacTCP is awake, and has allocated us an IP number}
  556.             conEvtRec: connectionEventRecord; { Event record for TCP events, similar to EventRecord }
  557.             connectionOpened: Boolean;
  558.             starttime, endtime: longint;
  559.             ignoreResult: Boolean;
  560.             event: EventRecord;
  561.  
  562.         procedure CatchOSErr (err: OSErr);
  563.         begin
  564.             if err <> noerr then
  565.                 begin
  566.                     MCTCPOpenPassiveConxn := err;
  567.                     if connectionOpened then
  568.                         CloseConnection(conEvtRec.connection); { Close our side of the connection }
  569.                     exit(MCTCPOpenPassiveConxn);
  570.                 end;
  571.         end;
  572.  
  573.     begin
  574.         connectionOpened := false;
  575.         MCTCPOpenPassiveConxn := noErr;
  576.         if not gMCTCPStarted then
  577.             CatchOSErr(ipLoadErr);{-23003?}
  578.  
  579.         connIndx := 0;
  580.  
  581.         {get our IP address}
  582.         CatchOSerr(TCPGetMyIPAddr(myip));
  583.  
  584.         if ipnumber <> '' then
  585.             CatchOSErr(FindAddress(connIndx, ipnumber, nil)) {find the server address}
  586.         else
  587.             begin {just open one, and do it. Don't have to worry about finding the address}
  588.                 CatchOSErr(NewPassiveConnection(connIndx, Default_TCPBUFFERSIZE, portNo, 0, 0, nil));
  589.                 exit(MCTCPOpenPassiveConxn);
  590.             end;
  591. {enter loop to wait for the found event, and for the connection response from the server}
  592. {use negative time out if wait forever}
  593.         if timeout = 0 then
  594.             timeout := MAX_PASSIVE_WAIT;
  595.         if timeout > 0 then
  596.             begin
  597.                 starttime := TickCount;
  598.                 endtime := starttime + timeout * 60;
  599.             end;
  600.         while not connectionOpened do
  601.             begin
  602.                 MCNextAnimCursor;
  603.                 if dowaitnextevent then
  604.                     ignoreResult := WaitNextEvent(everyEvent, event, 60, nil);
  605.                 if timeout > 0 then
  606.                     if (TickCount > endtime) then
  607.                         CatchOSErr(iptimedoutonopen);
  608.                 if GetConnectionEvent(any_connection, conEvtRec) then {look for an event on the connection, no mask}
  609.                     begin { Get the next TCP event }
  610.                         case conEvtRec.event of    {case the event of}
  611.                             C_Found: 
  612.                                 begin
  613.                                     CatchOSErr(NewPassiveConnection(connIndx, Default_TCPBUFFERSIZE, portNo, conEvtRec.value, 0, nil));
  614.                                     connectionOpened := true;
  615.                                 end;
  616.  
  617.                             C_SearchFailed:     {couldn't find the address!}
  618.                                 begin
  619.                                     CatchOSErr(-23004);{bad address}
  620.                                 end;
  621.  
  622.                             C_Closing: 
  623.                                 begin
  624.                             { Gets called when the connection starts closing down - shouldn't happen in this loop}
  625.                                     CloseConnection(conEvtRec.connection); { Close our side of the connection }
  626.                                 end;
  627.  
  628.                             C_Closed: 
  629.                                 begin
  630.                                     CatchOSErr(-23012); {connection terminated unexpectedly}
  631.                                 end;
  632.                             otherwise
  633.                                 ;
  634.                         end;
  635.                     end;{iff}
  636.             end;{while}
  637.     end;
  638.  
  639.  
  640. {close the connection specified}
  641.  
  642.     procedure MCTCPCloseConnection;
  643.         var
  644.             myip: longint; {just to make sure MacTCP is awake, and has allocated us an IP number}
  645.             closedConnection: Boolean;
  646.             conEvtRec: connectionEventRecord; { Event record for TCP events, similar to EventRecord }
  647.     begin
  648.         closedConnection := false;
  649.         CloseConnection(connIndx); { Close our side of the connection }
  650.         while not closedConnection do
  651.             begin
  652.                 MCNextAnimCursor;
  653.                 if GetConnectionEvent(connIndx, conEvtRec) then {look for an event on the connection, no mask}
  654.                     begin { Get the next TCP event }
  655.  
  656.                         case conEvtRec.event of    {case the event of}
  657.                             C_Closing: 
  658.                                 begin
  659.                                     CloseConnection(conEvtRec.connection); { Close our side of the connection }
  660.                                     closedConnection := true;
  661.                                 end;
  662.  
  663.                             C_Closed: 
  664.                                 begin
  665.                                     closedConnection := true;
  666.                                 end;
  667.                             otherwise
  668.                                 ;
  669.                         end;
  670.                     end;{iff}
  671.             end;{while}
  672.     end;
  673.  
  674. {does not dispose handle of message}
  675.     function MCTCPSendHndlLine;
  676.         var
  677.             tcpc: TCPConnectionPtr;
  678.             hlen: longint;
  679.             p: Ptr;
  680.         procedure CatchOSErr (err: OsErr);
  681.         begin
  682.             if err <> noErr then
  683.                 begin
  684.                     MCTCPSendHndlLine := err;
  685.                     exit(MCTCPSendHndlLine);
  686.                 end;
  687.         end;
  688.     begin
  689.         MCTCPSendHndlLine := noErr;
  690.         if hmsg = nil then
  691.             CatchOSErr(nilHandleErr);
  692.  
  693. {append line feed to handle if not already there}
  694.         hlock(hmsg);
  695.         hlen := GetHandleSize(hmsg);
  696.         if not dontaddlinefeed then
  697.             begin
  698.                 p := Pointer(ord4(hmsg^) + hlen - 1);
  699.                 if p^ <> LineFeedCode then
  700.                     begin
  701.                         CatchOSErr(MCAppendStrToHndl(chr(LineFeedCode), hmsg));  { add linefeed just in case }
  702.                         hlen := hlen + 1;
  703.                     end;
  704.             end;
  705. {get connection pointer and send it}
  706.         GetConnectionTCPC(connIndx, tcpc);
  707.         if tcpc <> nil then
  708.             CatchOSErr(TCPSend(tcpc, hmsg^, hlen, true))
  709.         else
  710.             SysBeep(1);
  711.         hunlock(hmsg);
  712.     end;
  713.  
  714.     function MCTCPSendStrLine;
  715.         var
  716.             myh: Handle;
  717.             err: OSErr;
  718.     begin
  719.         MCTCPSendStrLine := noErr;
  720.         myh := nil;
  721.         if msg = '' then
  722.             msg := chr($0D);
  723.         err := MCAppendStrToHndl(msg, myh);
  724.         if (err = noErr) and (myh <> nil) then
  725.             begin
  726.                 MCTCPSendStrLine := MCTCPSendHndlLine(connectionID, myh, dontaddlinefeed);
  727.                 DisposeHandle(myh);
  728.             end
  729.         else
  730.             MCTCPSendStrLine := err;
  731.     end;
  732.  
  733.     function MCTCPRcvHndlLine;
  734.         var
  735.             gotlinefeed: boolean;
  736.             feed: boolean;
  737.             str: Str255;
  738.             count: longint;
  739.             conEvtRec: connectionEventRecord; { Event record for TCP events, similar to EventRecord }
  740.             starttime, endtime, lasttime: longint; {last time is last time the call back was called - every second}
  741.             ignoreResult: Boolean;
  742.             event: EventRecord;
  743.             myErr: OSErr;
  744.         procedure CatchOSErr (err: OSErr);
  745.         begin
  746.             if err <> noErr then
  747.                 begin
  748.                     MCTCPRcvHndlLine := err;
  749.                     hmsg := nil;
  750.                     exit(MCTCPRcvHndlLine);
  751.                 end;
  752.         end;
  753.     begin
  754.         MCTCPRcvHndlLine := noErr;
  755.         gotlinefeed := false;
  756.         hmsg := nil;
  757.         if timeout = 0 then
  758.             timeout := MAX_WAIT_FOR_SERVER;
  759.         if timeout > 0 then
  760.             begin
  761.                 starttime := TickCount;
  762.                 endtime := starttime + timeout * 60;
  763.             end;
  764.         if callbackproc <> nil then
  765.             lasttime := TickCount;
  766.         while not gotlinefeed do
  767.             begin
  768.                 MCNextAnimCursor;
  769.                 if timeout > 0 then
  770.                     begin
  771.                         if (TickCount > endtime) then
  772.                             begin
  773.                                 if (callbackproc <> nil) and (progdlog <> nil) then
  774.                                     CallProgBarProc(progdlog, timeout, callbackproc); {finish the bar}
  775.                                 CatchOSErr(commandTimeout);
  776.                             end
  777.                         else if (((TickCount - lasttime) div 60) > 1) then
  778.                             begin
  779.                                 if (callbackproc <> nil) and (progdlog <> nil) then
  780.                                     CallProgBarProc(progdlog, ((lasttime - starttime) div 60 + 1), callbackproc);
  781.                                 lasttime := TickCount;
  782.                             end;
  783.                     end;
  784.                 if dowaitnextevent then
  785.                     begin
  786.                         ignoreResult := WaitNextEvent(everyEvent, event, 60, nil);
  787.                         if handleaeevents then
  788.                             if event.what = kHighLevelEvent then
  789.                                 begin
  790.                                     myErr := AEProcessAppleEvent(event);
  791.                                     if (myErr <> noErr) and (myErr <> -1708) then {allow for undefined received apple events}
  792.                                         begin
  793.                                             CatchOsErr(myErr);
  794.                                         end;
  795.                                 end;
  796.                     end;
  797.  
  798.                 if GetConnectionEvent(connIndx, conEvtRec) then {look for an event on the connection, no mask}
  799.                     begin { Get the next TCP event }
  800.                         case conEvtRec.event of    {case the event of}
  801.                             C_Closing: 
  802.                                 begin
  803.                             { Gets called when the connection starts closing down - shouldn't happen in this loop}
  804.                                     CloseConnection(conEvtRec.connection); { Close our side of the connection }
  805.                                 end;
  806.  
  807.                             C_Closed: 
  808.                                 begin
  809.                                     CatchOSErr(-23012); {connection terminated unexpectedly}
  810.                                 end;
  811.  
  812.                             C_CharsAvailable:     {something waiting to be read! All right :-)}
  813.                                 begin
  814.                                     count := 0;
  815.                                     str := '';
  816.                                     CatchOSErr(TCPReceiveUpTo(conEvtRec.tcpc, LineFeedCode, 60, @str[1], 255, count, gotlinefeed));
  817.  
  818.                                 { Recieve characters up to a line feed }
  819.                                     if (count > 0) & (str[count] = chr(LineFeedCode)) then { strip off linefeed }
  820.                                         count := count - 1;
  821.                                     if (count > 0) & (str[count] = chr(ReturnCode)) then { strip off cr }
  822.                                         count := count - 1;
  823.                                     MCSetStrLen(str, count);
  824.  
  825.                                 {append the string to the handle}
  826.                                     if str <> '' then
  827.                                         CatchOSErr(MCAppendStrToHndl(str, hmsg));
  828.  
  829.                                 { if we got a linefeed, return the handle, otherwise go round again and wait for more characters }
  830.                                 end;
  831.                             otherwise
  832.                                 ;
  833.                         end; {case}
  834.                     end;{iff}
  835.             end;{while}
  836.         if (callbackproc <> nil) and (progdlog <> nil) then
  837.             CallProgBarProc(progdlog, timeout, callbackproc); {finish the bar}
  838.     end;
  839.  
  840.     function MCTCPRcvStrLine;
  841.         var
  842.             myh: Handle;
  843.             hlen: longint;
  844.             err: OSErr;
  845.     begin
  846.         MCTCPRcvStrLine := noErr;
  847.         err := MCTCPRcvHndlLine(connectionID, myh, timeout, dowaitnextevent, handleaeevents, callbackproc, progdlog);
  848.         if err = noErr then
  849.             begin
  850.                 hlen := GetHandleSize(myh);
  851.                 if hlen > 255 then
  852.                     hlen := 255;
  853.                 MCSetStrLen(msg, hlen);
  854.                 hlock(myh);
  855.                 BlockMove(myh^, @msg[1], hlen);
  856.                 hunlock(myh);
  857.                 DisposeHandle(myh);{toss the handle}
  858.             end
  859.         else
  860.             MCTCPRcvStrLine := err;
  861.     end;
  862.  
  863. end.