home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / TCPIP.CPP < prev    next >
C/C++ Source or Header  |  1998-05-12  |  16KB  |  577 lines

  1.  
  2. // LoraBBS Version 2.99 Free Edition
  3. // Copyright (C) 1987-98 Marco Maccaferri
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #if defined(__OS2__) && defined(__BORLANDC__)
  20. #define _System      _pascal
  21. #endif
  22.  
  23. #include "_ldefs.h"
  24. #include "combase.h"
  25.  
  26. #if defined(__OS2__)
  27. VOID WaitThread (PVOID Args)
  28. {
  29.    FILE *fp;
  30.    int i, s, namelen;
  31.    struct sockaddr_in client, sock;
  32.    struct hostent *host;
  33.    class TTcpip *Tcp = (class TTcpip *)Args;
  34.  
  35.    Tcp->Accepted = 0;
  36.  
  37.    namelen = sizeof (client);
  38.    if ((s = accept (Tcp->LSock, (struct sockaddr *)&client, &namelen)) > 0) {
  39.       sprintf (Tcp->ClientIP, "%ld.%ld.%ld.%ld", (client.sin_addr.s_addr & 0xFFL), (client.sin_addr.s_addr & 0xFF00L) >> 8, (client.sin_addr.s_addr & 0xFF0000L) >> 16, (client.sin_addr.s_addr & 0xFF000000L) >> 24);
  40. #if defined(__OS2__) || defined(__DOS__)
  41.       if ((host = gethostbyaddr ((char *)&client.sin_addr.s_addr, sizeof (client.sin_addr.s_addr), AF_INET)) != NULL)
  42.          strcpy (Tcp->ClientName, host->h_name);
  43.       else
  44. #endif
  45.          strcpy (Tcp->ClientName, Tcp->ClientIP);
  46.       Tcp->Accepted = (USHORT)s;
  47.       i = 1;
  48. #if defined(__OS2__) || defined(__DOS__) || defined(__LINUX__)
  49.       ioctl (Tcp->Accepted, FIONBIO, (char *)&i, sizeof (int));
  50. #elif defined(__NT__)
  51.       ioctlsocket (Tcp->Accepted, FIONBIO, (unsigned long *)&i);
  52. #endif
  53.  
  54.       namelen = sizeof (struct sockaddr_in);
  55.       getsockname (Tcp->Accepted, (struct sockaddr *)&sock, &namelen);
  56.       Tcp->HostID = (sock.sin_addr.s_addr & 0xFF000000L) >> 24;
  57.       Tcp->HostID |= (sock.sin_addr.s_addr & 0x00FF0000L) >> 8;
  58.       Tcp->HostID |= (sock.sin_addr.s_addr & 0x0000FF00L) << 8;
  59.       Tcp->HostID |= (sock.sin_addr.s_addr & 0x000000FFL) << 24;
  60.       if ((fp = fopen ("sock.log", "wt")) != NULL) {
  61.          fprintf (fp, "HOSTID %ld,%ld,%ld,%ld", (Tcp->HostID & 0xFF000000L) >> 24, (Tcp->HostID & 0xFF0000L) >> 16, (Tcp->HostID & 0xFF00L) >> 8, (Tcp->HostID & 0xFFL));
  62.          fclose (fp);
  63.       }
  64.    }
  65.  
  66.    _endthread ();
  67. }
  68. #endif
  69.  
  70. TTcpip::TTcpip (void)
  71. {
  72.    EndRun = FALSE;
  73.    fCarrierDown = FALSE;
  74.    TxBytes = RxBytes = RxPosition = 0;
  75.    LSock = Sock = 0;
  76. }
  77.  
  78. TTcpip::~TTcpip (void)
  79. {
  80.    ClosePort ();
  81. }
  82.  
  83. VOID TTcpip::BufferByte (UCHAR byte)
  84. {
  85.    TxBuffer[TxBytes++] = byte;
  86.    if (TxBytes >= TSIZE)
  87.       UnbufferBytes ();
  88. }
  89.  
  90. VOID TTcpip::BufferBytes (UCHAR *bytes, USHORT len)
  91. {
  92.    USHORT ToCopy;
  93.  
  94.    if (len > 0 && EndRun == FALSE)
  95.       do {
  96.          ToCopy = len;
  97.          if (ToCopy > TSIZE - TxBytes)
  98.             ToCopy = (USHORT)(TSIZE - TxBytes);
  99.          memcpy (&TxBuffer[TxBytes], bytes, ToCopy);
  100.          bytes += ToCopy;
  101.          TxBytes += ToCopy;
  102.          len -= ToCopy;
  103.          if (TxBytes >= TSIZE)
  104.             UnbufferBytes ();
  105.       } while (len > 0 && EndRun == FALSE && Carrier () == TRUE);
  106. }
  107.  
  108. USHORT TTcpip::BytesReady (VOID)
  109. {
  110.    int i;
  111.    USHORT RetVal = FALSE;
  112.  
  113.    if (Sock != 0 && fCarrierDown == FALSE && EndRun == FALSE) {
  114.       if (RxBytes != 0)
  115.          RetVal = TRUE;
  116.       else {
  117.          if ((i = recv (Sock, (char *)RxBuffer, sizeof (RxBuffer), 0)) == 0)
  118.             fCarrierDown = TRUE;
  119.          else if (i == -1) {
  120.             RxBytes = 0;
  121. #if defined(__OS2__)
  122.             if (sock_errno () != SOCEWOULDBLOCK)
  123. #elif defined(__NT__)
  124.             if (WSAGetLastError () != WSAEWOULDBLOCK)
  125. #elif defined(__LINUX__)
  126.             if (errno != EWOULDBLOCK)
  127. #endif
  128.                fCarrierDown = TRUE;
  129.          }
  130.          else {
  131.             RxBytes = (USHORT)i;
  132.             RxPosition = 0;
  133.             RetVal = TRUE;
  134.          }
  135.       }
  136.    }
  137.  
  138. #if defined(__OS2__)
  139.    if (RetVal == FALSE)
  140.       DosSleep (1L);
  141. #elif defined(__NT__)
  142.    if (RetVal == FALSE)
  143.       Sleep (1L);
  144. #endif
  145.  
  146.    return (RetVal);
  147. }
  148.  
  149. USHORT TTcpip::Carrier (VOID)
  150. {
  151.    return ((fCarrierDown == TRUE) ? FALSE : TRUE);
  152. }
  153.  
  154. VOID TTcpip::ClearInbound (VOID)
  155. {
  156.    RxBytes = 0;
  157. }
  158.  
  159. VOID TTcpip::ClearOutbound (VOID)
  160. {
  161. }
  162.  
  163. VOID TTcpip::ClosePort (VOID)
  164. {
  165.    if (Sock != 0) {
  166. #if defined(__NT__)
  167.       closesocket (Sock);
  168. #elif defined(__OS2__)
  169.       soclose (Sock);
  170. #elif defined(__DOS__) || defined(__LINUX__)
  171.       close (Sock);
  172. #endif
  173.       Sock = 0;
  174.    }
  175.    if (LSock != 0) {
  176. #if defined(__NT__)
  177.       closesocket (LSock);
  178. #elif defined(__OS2__)
  179.       soclose (LSock);
  180. #elif defined(__DOS__) || defined(__LINUX__)
  181.       close (LSock);
  182. #endif
  183.       LSock = 0;
  184.    }
  185. }
  186.  
  187. USHORT TTcpip::ConnectServer (PSZ pszServer, USHORT usPort)
  188. {
  189.    int i, namelen;
  190.    USHORT RetVal = FALSE, Port;
  191.    struct hostent *hostnm;
  192.    struct sockaddr_in server, sock;
  193. #if defined(__NT__)
  194.    WSADATA wsaData;
  195. #endif
  196.  
  197. #if defined(__OS2__)
  198.    if (sock_init () == 0) {
  199. #elif defined(__DOS__)
  200.    if (vec_search () != 0) {
  201. #elif defined(__NT__)
  202.    if (WSAStartup (MAKEWORD(1, 1), &wsaData) == 0) {
  203. #endif
  204.  
  205.       Port = usPort;
  206.       server.sin_family = AF_INET;
  207.       server.sin_port = htons (Port);
  208. #if defined(__OS2__) || defined(__NT__) || defined(__LINUX__)
  209. #if !defined(__LINUX__)
  210.       if (isdigit (pszServer[0]))
  211.          server.sin_addr.s_addr = inet_addr (pszServer);
  212.       else {
  213. #endif
  214.          if ((hostnm = gethostbyname (pszServer)) == NULL) {
  215.             fCarrierDown = TRUE;
  216.             return (FALSE);
  217.          }
  218.          server.sin_addr.s_addr = *((unsigned long *)hostnm->h_addr);
  219. #if !defined(__LINUX__)
  220.       }
  221. #endif
  222. #elif defined(__DOS__)
  223.       hostnm = gethostbyname (pszServer);
  224.       bcopy(hostnm->h_addr, &server.sin_addr, hostnm->h_length);
  225. #endif
  226.  
  227.       if ((Sock = socket (AF_INET, SOCK_STREAM, 0)) >= 0) {
  228.          if (connect (Sock, (struct sockaddr *)&server, sizeof (server)) >= 0) {
  229.             i = 1;
  230. #if defined(__OS2__) || defined(__DOS__) || defined(__LINUX__)
  231.             ioctl (Sock, FIONBIO, (char *)&i, sizeof (int));
  232. #elif defined(__NT__)
  233.             ioctlsocket (Sock, FIONBIO, (unsigned long *)&i);
  234. #endif
  235.  
  236.             namelen = sizeof (struct sockaddr_in);
  237.             getsockname (Sock, (struct sockaddr *)&sock, &namelen);
  238.             HostID = (sock.sin_addr.s_addr & 0xFF000000L) >> 24;
  239.             HostID |= (sock.sin_addr.s_addr & 0x00FF0000L) >> 8;
  240.             HostID |= (sock.sin_addr.s_addr & 0x0000FF00L) << 8;
  241.             HostID |= (sock.sin_addr.s_addr & 0x000000FFL) << 24;
  242.  
  243.             RetVal = TRUE;
  244.          }
  245.      }
  246. #if !defined(__LINUX__)
  247.    }
  248. #endif
  249.  
  250.    if (RetVal == FALSE)
  251.       fCarrierDown = TRUE;
  252.  
  253.    return (RetVal);
  254. }
  255.  
  256. USHORT TTcpip::Initialize (USHORT usPort, USHORT usSocket, USHORT usProtocol)
  257. {
  258.    int i, socktype = SOCK_STREAM;
  259.    USHORT RetVal = FALSE;
  260.    struct sockaddr_in server;
  261. #if defined(__NT__)
  262.    int addrSize;
  263.    char sHostName[64];
  264.    struct hostent *pHostEnt;
  265.    WSADATA wsaData;
  266. #endif
  267.  
  268. #if defined(__OS2__)
  269.    if (sock_init () == 0) {
  270. #elif defined(__DOS__)
  271.    if (vec_search () != 0) {
  272. #elif defined(__NT__)
  273.    if (WSAStartup (MAKEWORD(1, 1), &wsaData) == 0) {
  274. #endif
  275.  
  276. #if defined(__OS2__)
  277.       HostID = gethostid ();
  278. #elif defined(__LINUX__)
  279.       HostID = (gethostid () & 0x00FF0000L) << 8;
  280.       HostID |= (gethostid () & 0xFF000000L) >> 8;
  281.       HostID |= (gethostid () & 0x000000FFL) << 8;
  282.       HostID |= (gethostid () & 0x0000FF00L) >> 8;
  283. #elif defined(__NT__)
  284.       gethostname (sHostName, sizeof (sHostName));
  285.       pHostEnt = gethostbyname (sHostName);
  286.       HostID = *(unsigned long *)pHostEnt->h_addr;
  287. #else
  288.       HostID = 0x7F000001L;
  289. #endif
  290.       sprintf (HostIP, "%ld.%ld.%ld.%ld", (HostID & 0xFF000000L) >> 24, (HostID & 0xFF0000L) >> 16, (HostID & 0xFF00L) >> 8, (HostID & 0xFFL));
  291.  
  292.       if (usSocket == 0) {
  293.          if (usProtocol == IPPROTO_UDP)
  294.             socktype = SOCK_DGRAM;
  295.          if ((LSock = socket (AF_INET, socktype, usProtocol)) >= 0) {
  296.             server.sin_family = AF_INET;
  297.             server.sin_port = htons (usPort);
  298.             server.sin_addr.s_addr = INADDR_ANY;
  299.             if (bind (LSock, (struct sockaddr *)&server, sizeof (server)) >= 0) {
  300. #if defined(__NT__)
  301.                sprintf (ClientIP, "%ld.%ld.%ld.%ld", (server.sin_addr.s_addr & 0xFFL), (server.sin_addr.s_addr & 0xFF00L) >> 8, (server.sin_addr.s_addr & 0xFF0000L) >> 16, (server.sin_addr.s_addr & 0xFF000000L) >> 24);
  302.                addrSize = sizeof (struct sockaddr);
  303.                getsockname (LSock, (struct sockaddr *)&server, &addrSize);
  304. #endif
  305.                i = 1;
  306. #if defined(__DOS__)
  307.                ioctl (LSock, FIONBIO, (char *)&i, sizeof (int));
  308. #elif defined(__NT__)
  309.                ioctlsocket (LSock, FIONBIO, (unsigned long *)&i);
  310. #elif defined(__OS2__)
  311.                if (usProtocol == IPPROTO_UDP)
  312.                   ioctl (LSock, FIONBIO, (char *)&i, sizeof (int));
  313. #endif
  314.                if (usProtocol == IPPROTO_TCP) {
  315.                   if (listen (LSock, 1) >= 0) {
  316.                      Sock = 0;
  317. #if defined(__OS2__)
  318.                      Accepted = 0;
  319.                      _beginthread (WaitThread, NULL, 32767, (PVOID)this);
  320. #endif
  321.                      RetVal = TRUE;
  322.                   }
  323.                }
  324.                else
  325.                   RetVal = TRUE;
  326.             }
  327.          }
  328.       }
  329.       else {
  330.          Sock = usSocket;
  331.          i = 1;
  332. #if defined(__OS2__) || defined(__DOS__)
  333.          ioctl (Sock, FIONBIO, (char *)&i, sizeof (int));
  334. #elif defined(__NT__)
  335.          ioctlsocket (Sock, FIONBIO, (unsigned long *)&i);
  336. #endif
  337.          RetVal = TRUE;
  338.       }
  339. #if !defined(__LINUX__)
  340.    }
  341. #endif
  342.  
  343.    return (RetVal);
  344. }
  345.  
  346. UCHAR TTcpip::ReadByte (VOID)
  347. {
  348.    int i;
  349.    short c = 0;
  350.  
  351.    if (Sock != 0) {
  352.       while (RxBytes == 0 && EndRun == FALSE && fCarrierDown == FALSE) {
  353.          if ((i = recv (Sock, (char *)RxBuffer, sizeof (RxBuffer), 0)) == 0)
  354.             fCarrierDown = TRUE;
  355.          else if (i == -1) {
  356.             RxBytes = 0;
  357. #if defined(__OS2__)
  358.             if (sock_errno () != SOCEWOULDBLOCK)
  359. #elif defined(__NT__)
  360.             if (WSAGetLastError () != WSAEWOULDBLOCK)
  361. #elif defined(__LINUX__)
  362.             if (errno != EWOULDBLOCK)
  363. #endif
  364.                fCarrierDown = TRUE;
  365.          }
  366.          else {
  367.             RxBytes = (USHORT)i;
  368.             RxPosition = 0;
  369.          }
  370.       }
  371.  
  372.       if (EndRun == FALSE && fCarrierDown == FALSE) {
  373.          c = RxBuffer[RxPosition++];
  374.          RxBytes--;
  375.       }
  376.    }
  377.  
  378.    return ((UCHAR)c);
  379. }
  380.  
  381. USHORT TTcpip::ReadBytes (UCHAR *bytes, USHORT len)
  382. {
  383.    int i;
  384.    USHORT Max;
  385.  
  386.    if (Sock != 0) {
  387.       while (RxBytes == 0 && EndRun == FALSE && fCarrierDown == FALSE) {
  388.          if ((i = recv (Sock, (char *)RxBuffer, sizeof (RxBuffer), 0)) == 0)
  389.             fCarrierDown = TRUE;
  390.          else if (i == -1) {
  391.             RxBytes = 0;
  392. #if defined(__OS2__)
  393.             if (sock_errno () != SOCEWOULDBLOCK)
  394. #elif defined(__NT__)
  395.             if (WSAGetLastError () != WSAEWOULDBLOCK)
  396. #elif defined(__LINUX__)
  397.             if (errno != EWOULDBLOCK)
  398. #endif
  399.                fCarrierDown = TRUE;
  400.          }
  401.          else {
  402.             RxBytes = (USHORT)i;
  403.             RxPosition = 0;
  404.          }
  405.       }
  406.  
  407.       if (EndRun == FALSE && fCarrierDown == FALSE) {
  408.          if ((Max = len) > RxBytes)
  409.             Max = RxBytes;
  410.          memcpy (bytes, &RxBuffer[RxPosition], Max);
  411.          RxBytes -= Max;
  412.          RxPosition += Max;
  413.       }
  414.    }
  415.  
  416.    return (Max);
  417. }
  418.  
  419. USHORT TTcpip::PeekPacket (PVOID lpBuffer, USHORT usSize)
  420. {
  421.    int namelen = sizeof (udp_client);
  422.    if (recvfrom (LSock, (char *)lpBuffer, usSize, MSG_PEEK, (struct sockaddr *)&udp_client, &namelen) > 0)
  423.       return (TRUE);
  424.  
  425.    return (FALSE);
  426. }
  427.  
  428. USHORT TTcpip::GetPacket (PVOID lpBuffer, USHORT usSize)
  429. {
  430.    int namelen = sizeof (udp_client);
  431.    return ((USHORT)recvfrom (LSock, (char *)lpBuffer, usSize, 0, (struct sockaddr *)&udp_client, &namelen));
  432. }
  433.  
  434. USHORT TTcpip::SendPacket (PVOID lpBuffer, USHORT usSize)
  435. {
  436.    return ((USHORT)sendto (LSock, (char *)lpBuffer, usSize, 0, (struct sockaddr *)&udp_client, sizeof (udp_client)));
  437. }
  438.  
  439. USHORT TTcpip::WaitClient (VOID)
  440. {
  441. #if defined(__OS2__)
  442.    if (Accepted != 0 && Sock == 0)
  443.       Sock = Accepted;
  444.    else if (Sock != 0 && Accepted != 0) {
  445.       Sock = Accepted = 0;
  446.       _beginthread (WaitThread, NULL, 32767, (PVOID)this);
  447.    }
  448. #else
  449.    int i, s, namelen;
  450.    struct sockaddr_in client;
  451.    struct hostent *host;
  452.  
  453.    Sock = 0;
  454.  
  455.    namelen = sizeof (client);
  456.    if ((s = accept (LSock, (struct sockaddr *)&client, &namelen)) > 0) {
  457.       Sock = (USHORT)s;
  458.       sprintf (ClientIP, "%ld.%ld.%ld.%ld", (client.sin_addr.s_addr & 0xFFL), (client.sin_addr.s_addr & 0xFF00L) >> 8, (client.sin_addr.s_addr & 0xFF0000L) >> 16, (client.sin_addr.s_addr & 0xFF000000L) >> 24);
  459. #if defined(__OS2__) || defined(__DOS__)
  460.       if ((host = gethostbyaddr ((char *)&client.sin_addr.s_addr, sizeof (client.sin_addr.s_addr), AF_INET)) != NULL)
  461.          strcpy (ClientName, host->h_name);
  462.       else
  463. #endif
  464.          strcpy (ClientName, ClientIP);
  465.       i = 1;
  466. #if defined(__OS2__) || defined(__DOS__) || defined(__LINUX__)
  467.       ioctl (Sock, FIONBIO, (char *)&i, sizeof (int));
  468. #elif defined(__NT__)
  469.       ioctlsocket (Sock, FIONBIO, (unsigned long *)&i);
  470. #endif
  471.    }
  472. #endif
  473.  
  474. #if defined(__OS2__)
  475.    DosSleep (1L);
  476. #endif
  477.  
  478.    return ((USHORT)Sock);
  479. }
  480.  
  481. VOID TTcpip::SendByte (UCHAR byte)
  482. {
  483.    if (Sock != 0 && fCarrierDown == FALSE && EndRun == FALSE)
  484.       send (Sock, (char *)&byte, 1, 0);
  485. }
  486.  
  487. VOID TTcpip::SendBytes (UCHAR *bytes, USHORT len)
  488. {
  489.    int i;
  490.  
  491.    if (Sock != 0 && fCarrierDown == FALSE && EndRun == FALSE) {
  492.       do {
  493.          if ((i = send (Sock, (char *)bytes, len, 0)) > 0) {
  494.             len -= (USHORT)i;
  495.             bytes += i;
  496.          }
  497.          else if (i < 0) {
  498. #if defined(__OS2__)
  499.             if (sock_errno () != SOCEWOULDBLOCK && sock_errno () != SOCENOBUFS)
  500. #elif defined(__NT__)
  501.             if (WSAGetLastError () != WSAEWOULDBLOCK && WSAGetLastError () != WSAENOBUFS)
  502. #elif defined(__LINUX__)
  503.             if (errno != EWOULDBLOCK && errno != ENOBUFS)
  504. #endif
  505.                fCarrierDown = TRUE;
  506.          }
  507.       } while (len > 0 && EndRun == FALSE && Carrier () == TRUE);
  508.    }
  509. }
  510.  
  511. VOID TTcpip::UnbufferBytes (VOID)
  512. {
  513.    int i, Written;
  514.    UCHAR *p;
  515.  
  516.    while (Sock != 0 && fCarrierDown == FALSE && EndRun == FALSE && TxBytes > 0) {
  517.       i = 0;
  518. #if defined(__OS2__) || defined(__DOS__) || defined(__LINUX__)
  519.       ioctl (Sock, FIONBIO, (char *)&i, sizeof (int));
  520. #elif defined(__NT__)
  521.       ioctlsocket (Sock, FIONBIO, (unsigned long *)&i);
  522. #endif
  523.  
  524.       p = TxBuffer;
  525.       do {
  526.          if ((Written = send (Sock, (char *)p, TxBytes, 0)) > 0) {
  527.             p += Written;
  528.             TxBytes -= (USHORT)Written;
  529.          }
  530.          else if (Written < 0) {
  531. #if defined(__OS2__)
  532.             if (sock_errno () != SOCEWOULDBLOCK && sock_errno () != SOCENOBUFS)
  533. #elif defined(__NT__)
  534.             if (WSAGetLastError () != WSAEWOULDBLOCK && WSAGetLastError () != WSAENOBUFS)
  535. #elif defined(__LINUX__)
  536.             if (errno != EWOULDBLOCK && errno != ENOBUFS)
  537. #endif
  538.                fCarrierDown = TRUE;
  539.          }
  540.       } while (TxBytes > 0 && EndRun == FALSE && Carrier () == TRUE);
  541.  
  542.       i = 1;
  543. #if defined(__OS2__) || defined(__DOS__) || defined(__LINUX__)
  544.       ioctl (Sock, FIONBIO, (char *)&i, sizeof (int));
  545. #elif defined(__NT__)
  546.       ioctlsocket (Sock, FIONBIO, (unsigned long *)&i);
  547. #endif
  548.    }
  549. }
  550.  
  551. VOID TTcpip::SetName (PSZ name)
  552. {
  553.    name = name;
  554. }
  555.  
  556. VOID TTcpip::SetCity (PSZ name)
  557. {
  558.    name = name;
  559. }
  560.  
  561. VOID TTcpip::SetLevel (PSZ level)
  562. {
  563.    level = level;
  564. }
  565.  
  566. VOID TTcpip::SetTimeLeft (ULONG seconds)
  567. {
  568.    seconds = seconds;
  569. }
  570.  
  571. VOID TTcpip::SetTime (ULONG seconds)
  572. {
  573.    seconds = seconds;
  574. }
  575.  
  576.  
  577.