home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 1992 August / info-mac-1992.iso / Source / Pascal / Chat / Chat 1.0.0 Source / Chat.p < prev    next >
Encoding:
Text File  |  1992-04-26  |  8.3 KB  |  351 lines  |  [TEXT/PJMM]

  1. {$I-}
  2. program Chat;
  3.  
  4. { This program was written by Peter N Lewis, Mar 1992 in THINK Pascal 4.0.1 }
  5. { You may use this source in your own free/shareware projects as long as you acknowledge me }
  6. { in your About box and documentation files.  You may include it in commercial products }
  7. { only if I explicitly allow it. }
  8.  
  9.     uses
  10.         TCPStuff, TCPConnections, MyTypes, MyLists, MyStripTelnetCodes;
  11.  
  12.     const
  13.         globalStrhResID = 128;
  14.  
  15.     type
  16.         strings = (noIndex, portIndex, irclogname, irclogtype, quitnowIndex, quitIndex, listIndex, {}
  17.             howdullIndex, startingupatIndex, welcomeIndex,{}
  18.             loggedinatIndex, youneedanameIndex, nameinuseIndex, welcome2index, hasenteredIndex, {}
  19.             closingdownIndex, closingdownatIndex, byebyeIndex, colonIndex, hasleftIndex);
  20.  
  21.     type
  22.         infoRecord = record
  23.                 cp: connectionIndex;
  24.                 state: (S_unconnected, S_GettingName, S_GettingPassword, S_Connected, S_Closed);
  25.                 buffer: str255;
  26.                 name: str31;
  27.                 wason: boolean;
  28.             end;
  29.         infoPtr = ^infoRecord;
  30.  
  31.     var
  32.         lh: listHead;
  33.         quitNow: boolean;
  34.         logrn: integer;
  35.         connected: integer;
  36.         port: integer;
  37.         dolog: boolean;
  38.  
  39.     function GetGlobalString (n: strings): str255;
  40.         var
  41.             s: str255;
  42.     begin
  43.         GetIndString(s, globalStrhResID, ord(n));
  44.         GetGlobalString := s;
  45.     end;
  46.  
  47.     procedure CreatePC;
  48.         var
  49.             p: infoPtr;
  50.             oe: OSErr;
  51.     begin
  52.         p := infoPtr(Newptr(SizeOf(infoRecord)));
  53.         p^.state := S_unconnected;
  54.         p^.wason := false;
  55.         oe := NewPassiveConnection(p^.cp, Minimum_TCPBUFFERSIZE, port, 0, 0, p);
  56.         AddTail(lh, p);
  57.     end;
  58.  
  59.     procedure DestroyPC (p: infoPtr);
  60.         var
  61.             item: listItem;
  62.             lp: infoPtr;
  63.     begin
  64.         if FindItem(lh, p, item) then begin
  65.             DisposPtr(ptr(p));
  66.             DeleteItem(item, p);
  67.         end;
  68.     end;
  69.  
  70.     function GetLine (tcpc: TCPConnectionPtr; value: longInt; var buffer: str255): boolean;
  71.         var
  72.             len: longInt;
  73.             gotlf: boolean;
  74.             i, j: integer;
  75.     begin
  76.         GetLine := false;
  77.         len := length(buffer);
  78. {$PUSH}
  79. {$R-}
  80.         if TCPReceiveUpTo(tcpc, 10, 1, @buffer[1], SizeOf(buffer) - 1, len, gotlf) = noErr then begin
  81.             i := 1;
  82.             j := 1;
  83.             while (i <= len) do begin
  84.                 case buffer[i] of
  85.                     cr, lf: 
  86.                         i := i + 1;
  87.                     bs, del:  begin
  88.                         i := i + 1;
  89.                         if j > 1 then
  90.                             j := j - 1;
  91.                     end;
  92.                     otherwise begin
  93.                         buffer[j] := buffer[i];
  94.                         i := i + 1;
  95.                         j := j + 1;
  96.                     end;
  97.                 end;
  98.             end;
  99.             buffer[0] := chr(j - 1);
  100.             GetLine := gotlf;
  101.         end;
  102. {$POP}
  103.     end;
  104.  
  105.     procedure SendString (tcpc: TCPCOnnectionPtr; s: str255);
  106.         var
  107.             oe: OSErr;
  108.     begin
  109. {$PUSH}
  110. {$R-}
  111.         oe := TCPSendAsync(tcpc, @s[1], length(s), nil);
  112. {$POP}
  113.     end;
  114.  
  115.     procedure StartLog;
  116.         var
  117.             oe: OSErr;
  118.     begin
  119.         if dolog then begin
  120.             oe := HCreate(-1, 2, GetGlobalString(irclogname), GetGlobalString(irclogtype), 'TEXT');
  121.             oe := HOpen(-1, 2, GetGlobalString(irclogname), fsWrPerm, logrn);
  122.             oe := SetFPos(logrn, fsFromLEOF, 0);
  123.         end;
  124.     end;
  125.  
  126.     procedure StopLog;
  127.         var
  128.             oe: OSErr;
  129.     begin
  130.         if dolog then begin
  131.             oe := FSClose(logrn);
  132.         end;
  133.     end;
  134.  
  135.     procedure Log (s: str255);
  136.         var
  137.             count: longInt;
  138.             oe: OSErr;
  139.     begin
  140.         if dolog then begin
  141.             if s[length(s)] = lf then
  142.                 s := copy(s, 1, length(s) - 1);
  143.             count := length(s);
  144. {$PUSH}
  145. {$R-}
  146.             oe := FSWrite(logrn, count, @s[1]);
  147. {$POP}
  148.         end;
  149.     end;
  150.  
  151.     procedure SendExceptString (p: infoPtr; s: str255);
  152.         var
  153.             item: listItem;
  154.             lp: infoPtr;
  155.             tcpc: TCPConnectionPtr;
  156.     begin
  157.         Log(s);
  158.         ReturnHead(lh, item);
  159.         while not IsTail(item) do begin
  160.             Fetch(item, lp);
  161.             if (lp <> p) and (lp^.state = S_connected) then begin
  162.                 GetConnectionTCPC(lp^.cp, tcpc);
  163.                 SendString(tcpc, s);
  164.             end;
  165.             MoveToNext(item);
  166.         end;
  167.     end;
  168.  
  169.     function NameInUse (p: infoPtr): boolean;
  170.         var
  171.             item: listItem;
  172.             lp: infoPtr;
  173.             tcpc: TCPConnectionPtr;
  174.     begin
  175.         NameInUse := false;
  176.         ReturnHead(lh, item);
  177.         while not IsTail(item) do begin
  178.             Fetch(item, lp);
  179.             if (lp <> p) and (lp^.state = S_connected) then begin
  180.                 if IUEqualString(lp^.name, p^.name) = 0 then begin
  181.                     NameInUse := true;
  182.                     leave;
  183.                 end;
  184.             end;
  185.             MoveToNext(item);
  186.         end;
  187.     end;
  188.  
  189.     procedure SendExceptNames (tcpc: TCPCOnnectionPtr; p: infoPtr);
  190.         var
  191.             item: listItem;
  192.             lp: infoPtr;
  193.             first: boolean;
  194.             len: integer;
  195.     begin
  196.         first := true;
  197.         len := 0;
  198.         ReturnHead(lh, item);
  199.         while not IsTail(item) do begin
  200.             Fetch(item, lp);
  201.             if (lp <> p) and (lp^.state = S_connected) then begin
  202.                 if first then
  203.                     first := false
  204.                 else begin
  205.                     SendString(tcpc, ', ');
  206.                     len := len + 2;
  207.                 end;
  208.                 if len + length(lp^.name) > 75 then begin
  209.                     SendString(tcpc, concat(cr, lf));
  210.                     len := 0;
  211.                 end;
  212.                 SendString(tcpc, lp^.name);
  213.                 len := len + length(lp^.name);
  214.             end;
  215.             MoveToNext(item);
  216.         end;
  217.         if first then
  218.             SendString(tcpc, concat(GetGlobalString(howdullIndex), cr, lf))
  219.         else
  220.             SendString(tcpc, concat(cr, lf));
  221.     end;
  222.  
  223.     function GetTimeStr: str255;
  224.         var
  225.             st, sd: str255;
  226.             date: longInt;
  227.     begin
  228.         GetDateTime(date);
  229.         IUDateString(date, abbrevDate, sd);
  230.         IUTimeString(date, false, st);
  231.         GetTimeStr := concat(st, ', ', sd);
  232.     end;
  233.  
  234.     procedure WNE;
  235.         var
  236.             dummy: boolean;
  237.             er: eventRecord;
  238.     begin
  239.         dummy := WaitNextEvent(everyEvent, er, 15, nil);
  240.     end;
  241.  
  242.     function StackPtr: longInt;
  243.     inline
  244.         $2E8F;
  245.  
  246.     var
  247.         cer: connectionEventRecord;
  248.         p: infoPtr;
  249.         oe: OSErr;
  250.         dummylong: longInt;
  251. begin
  252.     SetApplLimit(ptr(StackPtr - 10000));
  253.     MaxApplZone;
  254.     MoreMasters;
  255.     StringToNum(GetGlobalString(portIndex), dummylong);
  256.     port := dummylong;
  257.     dolog := GetGlobalString(irclogname) <> '';
  258.     if InitConnections('') = noErr then begin
  259.         StartLog;
  260.         Log(concat(GetGlobalString(startingupatIndex), GetTimeStr, cr, lf));
  261.         StopLog;
  262.         CreateList(lh);
  263.         CreatePC;
  264.         CreatePC;
  265.         connected := 0;
  266.         while not quitNow do begin
  267.             WNE;
  268.             if GetConnectionEvent(any_connection, cer) then
  269.                 with cer do begin
  270.                     p := infoPtr(dataptr);
  271.                     with p^ do
  272.                         case event of
  273.                             C_Established:  begin
  274.                                 if connected = 0 then
  275.                                     StartLog;
  276.                                 connected := connected + 1;
  277.                                 state := S_GettingName;
  278.                                 buffer := '';
  279.                                 SendString(tcpc, GetGlobalString(welcomeIndex));
  280.                                 CreatePC;
  281.                             end;
  282.                             C_CharsAvailable:  begin
  283.                                 if GetLine(tcpc, value, buffer) then begin
  284.                                     StripTelnetCodes(buffer);
  285.                                     case state of
  286.                                         S_GettingName:  begin
  287.                                             Log(concat(buffer, GetGlobalString(loggedinatIndex), GetTimeStr, cr, lf));
  288.                                             name := buffer;
  289.                                             state := S_connected;
  290.                                             if buffer = '' then begin
  291.                                                 SendString(tcpc, concat(GetGlobalString(youneedanameIndex), cr, lf));
  292.                                                 state := S_Closed;
  293.                                                 CloseConnection(connection);
  294.                                             end
  295.                                             else if NameInUse(p) then begin
  296.                                                 SendString(tcpc, concat(GetGlobalString(nameinuseIndex), cr, lf));
  297.                                                 state := S_Closed;
  298.                                                 CloseConnection(connection);
  299.                                             end
  300.                                             else begin
  301.                                                 buffer := '';
  302.                                                 SendString(tcpc, GetGlobalString(welcome2index));
  303.                                                 SendExceptNames(tcpc, p);
  304.                                                 SendExceptString(p, concat(name, GetGlobalString(hasenteredIndex), cr, lf));
  305.                                                 wason := true;
  306.                                             end;
  307.                                         end;
  308.                                         S_GettingPassword:  begin
  309.                                         end;
  310.                                         S_Connected:  begin
  311.                                             if buffer = GetGlobalString(quitnowIndex) then begin
  312.                                                 quitNow := true;
  313.                                                 SendString(tcpc, concat(GetGlobalString(closingdownIndex), cr, lf));
  314.                                                 SendExceptString(p, concat(GetGlobalString(closingdownatIndex), GetTimeStr, cr, lf));
  315.                                             end
  316.                                             else if IUEqualString(buffer, GetGlobalString(quitIndex)) = 0 then begin
  317.                                                 SendString(tcpc, concat(GetGlobalString(byebyeIndex), cr, lf));
  318.                                                 state := S_Closed;
  319.                                                 CloseConnection(connection);
  320.                                             end
  321.                                             else if IUEqualString(buffer, GetGlobalString(listIndex)) = 0 then begin
  322.                                                 SendExceptNames(tcpc, p);
  323.                                             end
  324.                                             else
  325.                                                 SendExceptString(p, concat(name, GetGlobalString(colonIndex), buffer, cr, lf));
  326.                                             buffer := '';
  327.                                         end;
  328.                                         otherwise
  329.                                             ;
  330.                                     end;
  331.                                 end;
  332.                             end;
  333.                             C_Closing:  begin
  334.                                 state := S_Closed;
  335.                                 CloseConnection(connection);
  336.                             end;
  337.                             C_Closed:  begin
  338.                                 if wason then
  339.                                     SendExceptString(p, concat(name, GetGlobalString(hasleftIndex), cr, lf));
  340.                                 connected := connected - 1;
  341.                                 DestroyPC(p);
  342.                                 if connected = 0 then
  343.                                     StopLog;
  344.                             end;
  345.                         end;
  346.                 end;
  347.         end;
  348.         StopLog;
  349.         FinishEverything;
  350.     end;
  351. end.