WS_CON.C
上传用户:dansui
上传日期:2007-01-04
资源大小:71k
文件大小:40k
源码类别:

Ftp客户端

开发平台:

WINDOWS

  1. #include "ws_glob.h"
  2. #include "winftp.h"
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <stdlib.h>
  6. #include <ctype.h>
  7. #include <io.h>
  8. #include <fcntl.h>
  9. #include <sysstat.h>
  10. #include <time.h>
  11. // extern int errno;
  12. extern BOOL bAborted;   // timer routine may set this
  13. extern BOOL bDebugLog;  
  14. char szDbgLogFile[_MAX_PATH];
  15. //***********************************************************************
  16. //***********************************************************************
  17. int WriteDebugLog (int nCode, int nRetCode, LPSTR lpStr)
  18. {
  19.   FILE *fp;
  20.   FARPROC lpfnMsgProc;
  21.   int nRC;
  22.   
  23.   if (!bDebugLog) return 0;
  24.   if (lstrlen (szDbgLogFile)==0)
  25.   {
  26.     lstrcpy (szDlgPrompt,"Enter log file name:");
  27.     lstrcpy (szDlgEdit, "C:\WNFTPDBG.LOG");
  28.     lpfnMsgProc = MakeProcInstance ((FARPROC) WS_InputMsgProc, hInst);
  29.     nRC = DialogBox (hInst, (LPSTR) "DLG_INPUT", hWndMain, lpfnMsgProc);
  30.     FreeProcInstance (lpfnMsgProc);
  31.     if (nRC==IDCANCEL) return 0;
  32.     lstrcpy (szDbgLogFile, szDlgEdit);
  33.   }
  34.   fp = fopen (szDbgLogFile, "at");
  35.   switch (nCode)
  36.   {
  37.     case 0: fprintf (fp, "SEND: %sn", lpStr); break;
  38.     case 1: fprintf (fp, "RESULT: %4d  %3d  %-16s  %sn", nRetCode, iCode,
  39.                            (nRetCode==FTP_PRELIM)   ? "Prelim" :
  40.                            (nRetCode==FTP_COMPLETE) ? "Complete" : 
  41.                            (nRetCode==FTP_CONTINUE) ? "Continue" : 
  42.                            (nRetCode==FTP_RETRY)    ? "Retry" : 
  43.                            (nRetCode==FTP_ERROR)    ? "Error" : "Unknown", 
  44.                            lpStr); break;
  45.   }
  46.   fclose (fp);
  47.   return 0;
  48. }
  49. //***********************************************************************
  50. //  Print statistics on the transfer
  51. //***********************************************************************
  52. void PrintTransferStatus (LPSTR lpTyp, LONG lBytes, long nSecs)
  53. {
  54.   LONG lSecs = nSecs;
  55.   
  56.   if (lSecs==0) lSecs=1;
  57.   DoPrintf ("%sed %ld characters in %ld seconds (%ld bytes/sec)", lpTyp,
  58.         lBytes, (long) nSecs, (long) lBytes/lSecs);
  59. }
  60. static UINT nDirNum=0;
  61. //***********************************************************************
  62. //  Send in a Command line and return a code indicating type of reply
  63. // send a message on the control socket, read and display the resulting
  64. // message and return the result value
  65. //***********************************************************************
  66. int getreply (SOCKET ctrl_skt,LPSTR cmdstring, BOOL bForce)
  67. {
  68.   int iRetCode=0;
  69.   iCode=0;
  70.   if (strncmp (cmdstring,"PASS ",5)==0) DoAddLine ("PASS xxxxxx");
  71.   else DoAddLine (cmdstring);
  72.   if (ctrl_skt==INVALID_SOCKET)
  73.   {
  74.     DoAddLine ("Not connected");
  75.   }
  76.   else 
  77.   {
  78.     if (bDebugLog) WriteDebugLog (0, iRetCode, cmdstring);
  79.     switch (bForce)
  80.     {
  81.       case TRUE : if (ForcePacket (ctrl_skt,cmdstring)!=-1) iRetCode = ReadDisplayLine (ctrl_skt);
  82.       case FALSE: if (SendPacket (ctrl_skt,cmdstring)!=-1) iRetCode = ReadDisplayLine (ctrl_skt);
  83.     }
  84.     if (bDebugLog) WriteDebugLog (1, iRetCode, cmdstring);
  85.   }
  86.   return iRetCode;  // 0 - 5
  87. }
  88. //***********************************************************************
  89. //  Send in a Command line and return a code indicating type of reply
  90. //***********************************************************************
  91. int command (SOCKET ctrl_skt, char *fmt,...)
  92. {
  93.   va_list args;
  94.   char szBuf[90];
  95.   va_start (args, fmt);
  96.   vsprintf (szBuf, fmt, args);
  97.   va_end (args);
  98.   return getreply (ctrl_skt, szBuf, FALSE);
  99. }
  100. //***********************************************************************
  101. //  Send in a Command line and return a code indicating type of reply
  102. //***********************************************************************
  103. int ForceCommand (SOCKET ctrl_skt, char *fmt,...)
  104. {
  105.   va_list args;
  106.   char szBuf[90];
  107.   va_start (args, fmt);
  108.   vsprintf (szBuf, fmt, args);
  109.   va_end (args);
  110.   return getreply (ctrl_skt, szBuf, TRUE);
  111. }
  112. //***********************************************************************
  113. // return a string pointer to ON or OFF based on the flag
  114. //***********************************************************************
  115. char *onoff(BOOL flag)
  116. {
  117.   if (flag) return("ON"); else return("OFF");
  118. }
  119. //***********************************************************************
  120. // process CWD
  121. //***********************************************************************
  122. int DoCWD(SOCKET ctrl_skt,LPSTR path)
  123. {
  124.   char szPath[100];
  125.   
  126.   if (command (ctrl_skt,"CWD %s",path)==FTP_ERROR)
  127.   {
  128.     if (iCode==500) command (ctrl_skt,"XCWD %s",path);
  129.     else
  130.     {
  131.       lstrcpy (szPath, path);
  132.       ConvertTargetDir (szPath, 95);
  133.       command (ctrl_skt,"CWD %s", szPath);
  134.     }
  135.   }
  136.   return(iCode/100);
  137. }
  138. //***********************************************************************
  139. // process System Type
  140. //***********************************************************************
  141. int DoSystemCommand (SOCKET ctrl_skt)
  142. {
  143.   LPSTR lp;
  144.   char szBuf[100];
  145.   
  146.   if (command (ctrl_skt,"SYST")!=FTP_ERROR)
  147.   {
  148.     lstrcpy (szBuf, szMsgBuf);
  149.     strupr (szBuf);
  150.     if (strstr (szBuf, "UNIX") != NULL)         nHostType = HOST_UNIX;
  151.     else if (strstr (szBuf, "ULTRIX") != NULL)  nHostType = HOST_UNIX;
  152.     else if (strstr (szBuf, "MVS") != NULL)     nHostType = HOST_MVS;
  153.     else if (strstr (szBuf, "QVT") != NULL)     nHostType = HOST_QVT;
  154.     else if (strstr (szBuf, "NCSA") != NULL)    nHostType = HOST_NCSA;
  155.     else if (strstr (szBuf, "CHAMELEON")!=NULL) nHostType = HOST_CHAMELEON;
  156.     else if (strstr (szMsgBuf, "VMS") != NULL)
  157.     {
  158.       lp = strstr (szMsgBuf, "MultiNet");
  159.       nHostType = (lp!=NULL)? HOST_VMS_MULTINET : HOST_VMS_UCX;
  160.     }
  161.   }
  162.   return(iCode/100);
  163. }
  164. //***********************************************************************
  165. // proces PWD
  166. //***********************************************************************
  167. int DoPWD(SOCKET ctrl_skt)
  168. {
  169.   if (command(ctrl_skt,"PWD")==FTP_ERROR && iCode==500) 
  170.   {
  171.     command(ctrl_skt,"XPWD");
  172.   }
  173.   return(iCode/100);
  174. }
  175. //***********************************************************************
  176. // process MKD
  177. //***********************************************************************
  178. int DoMKD(SOCKET ctrl_skt,LPSTR pathname)
  179. {
  180.   char szPath[100];
  181.   
  182.   if (command (ctrl_skt,"MKD %s",pathname)==FTP_ERROR)
  183.   {
  184.     if (iCode==500) command (ctrl_skt,"XMKD %s",pathname);
  185.     else
  186.     {
  187.       lstrcpy (szPath, pathname);
  188.       ConvertTargetDir (szPath, 95);
  189.       command (ctrl_skt,"MKD %s", szPath);
  190.     }
  191.   }
  192.   return(iCode/100);
  193. }
  194. //***********************************************************************
  195. // process RMD
  196. //***********************************************************************
  197. int DoRMD(SOCKET ctrl_skt,LPSTR pathname)
  198. {
  199.   char szPath[100];
  200.   
  201.   if (command (ctrl_skt,"RMD %s",pathname)==FTP_ERROR)
  202.   {
  203.     if (iCode==500) command (ctrl_skt,"XRMD %s",pathname);
  204.     else
  205.     {
  206.       lstrcpy (szPath, pathname);
  207.       ConvertTargetDir (szPath, 95);
  208.       command (ctrl_skt,"RMD %s", szPath);
  209.     }
  210.   }
  211.   return(iCode/100);
  212. }
  213. //***********************************************************************
  214. // process DELE
  215. //***********************************************************************
  216. int DoDELE(SOCKET ctrl_skt,LPSTR pathname)
  217. {
  218.   command(ctrl_skt,"DELE %s",pathname);
  219.   return(iCode/100);
  220. }
  221. //***********************************************************************
  222. //  Send the Quit Command
  223. //***********************************************************************
  224. int DoDisconnect (SOCKET ctrl_skt)
  225. {
  226.   int nRC=-1;
  227.   if (ctrl_skt!=INVALID_SOCKET)
  228.   {
  229.     nRC=command (ctrl_skt, "quit");
  230.     shutdown (ctrl_skt, 2);
  231.   }
  232.   return nRC;
  233. }
  234. //***********************************************************************
  235. // process user command
  236. //***********************************************************************
  237. int DoQUOTE(SOCKET ctrl_skt,LPSTR string)
  238. {
  239.   if(strncmp(string,"LIST",4)==0 ||
  240.      strncmp(string,"NLST",4)==0)
  241.     DoDirList(ctrl_skt,string);
  242.   else
  243.     command(ctrl_skt,string);
  244.   return(iCode/100);
  245. }
  246. //***********************************************************************
  247. // process chmod
  248. //***********************************************************************
  249. int DoCHMOD(SOCKET ctrl_skt,LPSTR modes,LPSTR filename)
  250. {
  251.   return (command(ctrl_skt,"SITE CHMOD %s %s",modes,filename));
  252. }
  253. extern BOOL bHELP,bIs5000;
  254. LPSTR szAcctAttempt="Attempting to send Account Password...";
  255. //***********************************************************************
  256. // initial connection
  257. //***********************************************************************
  258. SOCKET DoConnect (LPSTR lpHost)
  259. {
  260.   int iLength,iRetCode;
  261.   int iFlag=1;
  262.   SOCKET ctrl_skt;
  263.   LPSTR lpSite;
  264.   if (bConnected) 
  265.   {
  266.     DoAddLine("Already connected!");
  267.     return (INVALID_SOCKET);
  268.   }
  269.   //***************************************************************
  270.   // if connecting through a Firewall Host, trick the connect code
  271.   // into connecting to the FireWall Host instead.
  272.   //***************************************************************
  273.   if (bFireWall) 
  274.   {
  275.     if (lstrlen (szFireWallHost)==0)
  276.     {
  277.       DoPrintf ("FireWall Host name not specified. Can not Connect.");
  278.       SetDebugWindowText (lpDebugWindow);
  279.       return INVALID_SOCKET;
  280.     }
  281.     lpHost = szFireWallHost;
  282.   }
  283.   bHELP=bIs5000=FALSE;
  284.   SetDebugWindowText ("WINFTP Connecting...");
  285.   lpSite = lpHost;
  286.   //***************************************************************
  287.   // let other routines know that we are busy
  288.   //***************************************************************
  289.   bCmdInProgress++;
  290.   //***************************************************************
  291.   // create a connected socket
  292.   //***************************************************************
  293.   if ((ctrl_skt=connectTCP (lpHost,"ftp"))==INVALID_SOCKET) 
  294.   {
  295.     DoPrintf ("Connection to %s failed", lpHost);
  296.     bCmdInProgress--;
  297.     SetDebugWindowText (lpDebugWindow);
  298.     return INVALID_SOCKET;
  299.   }
  300.   //***************************************************************
  301.   // get information about local end of the connection
  302.   //***************************************************************
  303.   iLength = sizeof (saCtrlAddr);
  304.   if (getsockname (ctrl_skt, (struct sockaddr *) &saCtrlAddr, &iLength)==SOCKET_ERROR)
  305.   {
  306.     ReportWSError ("getsockname", WSAGetLastError());
  307.     bCmdInProgress--;
  308.     DoClose (ctrl_skt);
  309.     SetDebugWindowText (lpDebugWindow);
  310.     return (INVALID_SOCKET);
  311.   }
  312.   //***************************************************************
  313.   // show remote end address
  314.   //***************************************************************
  315.   DoPrintf ("[%u] from %s port %u", ctrl_skt, inet_ntoa (saCtrlAddr.sin_addr), ntohs (saCtrlAddr.sin_port));
  316.   //***************************************************************
  317.   // get initial message from remote end
  318.   //***************************************************************
  319.   while ((iRetCode=ReadDisplayLine(ctrl_skt))==FTP_PRELIM)
  320.   {
  321.     if (strstr(szMsgBuf,"(EXOS")!=NULL) bIs5000=TRUE;
  322.   }
  323.   
  324.   //***************************************************************
  325.   // if it succeeded
  326.   //***************************************************************
  327.   if (iRetCode!=FTP_COMPLETE) 
  328.   {
  329.     DoPrintf ("Unknown open msg "%s" %u",szMsgBuf,iCode);
  330.     // allow other processes to work
  331.     bCmdInProgress--;
  332.     DoClose ((SOCKET) ctrl_skt);
  333.     SetDebugWindowText (lpDebugWindow);
  334.     return (INVALID_SOCKET);
  335.   }
  336.   if (setsockopt (ctrl_skt, SOL_SOCKET, SO_OOBINLINE, (LPSTR) &iFlag, sizeof (iFlag))==SOCKET_ERROR)
  337.   {
  338.     ReportWSError("setsockopt",WSAGetLastError());
  339.   }
  340.   //***************************************************************
  341.   // have to reset this so "command" will work
  342.   //***************************************************************
  343.   bCmdInProgress--;
  344.     
  345.   if (bFireWall)
  346.   {
  347.     if ((iRetCode=command(ctrl_skt,"USER %s", szFireWallUserID))==FTP_CONTINUE)
  348.     {
  349.       iRetCode = command (ctrl_skt, "PASS %s", szFireWallUserPass);
  350.     }
  351.     
  352.     if (iRetCode!=FTP_COMPLETE)
  353.     {
  354.       DoPrintf ("Failed to log in to Firewall Host %s", lpHost);
  355.       DoClose ((SOCKET) ctrl_skt);
  356.       return INVALID_SOCKET;
  357.     }
  358.       
  359.     //***************************************************************
  360.     //Okay, gets here if logged in to FireWall Host
  361.     //***************************************************************
  362.     wsprintf (szString, "site %s", lpSite);
  363.     if ((iRetCode=command (ctrl_skt, szString))==FTP_ERROR)
  364.     {
  365.       DoPrintf ("Could not connect to %s through FireWall Host", lpSite);
  366.       DoClose ((SOCKET) ctrl_skt);
  367.       bConnected=0;
  368.       return INVALID_SOCKET;
  369.     }
  370.     //***************************************************************
  371.     // if here, we did get through to remote host, so do regular login
  372.     //***************************************************************
  373.     bConnected=1;
  374.   }
  375.     
  376.   //***************************************************************
  377.   // send our userid
  378.   //***************************************************************
  379.   SetDebugWindowText ("WINFTP UserName");
  380.   if ((iRetCode=command (ctrl_skt, "USER %s", szUserID))==FTP_CONTINUE)
  381.   {
  382.     //***************************************************************
  383.     // if the remote system requires a password, send it.
  384.     //***************************************************************
  385.     SetDebugWindowText ("WINFTP Password");
  386.     iRetCode = command (ctrl_skt,"PASS %s",szPassWord);
  387.     //***************************************************************
  388.     //  If the system requires an account password
  389.     //***************************************************************
  390.     if (bAccount)
  391.     {
  392.       nAcctType = 3;
  393.       switch (nAcctType)
  394.       {
  395.         case 0: break;
  396.         case 1: if (iRetCode!=FTP_CONTINUE) break;
  397.         case 2: DoAddLine (szAcctAttempt);
  398.                 if ((iRetCode=command (ctrl_skt, "ACCOUNT"))==FTP_CONTINUE)
  399.                 {
  400.                   iRetCode = command (ctrl_skt, szAccountPass);
  401.                 } break;
  402.         case 3: if (iRetCode!=FTP_CONTINUE) break;
  403.         case 4: DoAddLine (szAcctAttempt);
  404.                 wsprintf (szString, "ACCT %s", szAccountPass);
  405.                 iRetCode=command (ctrl_skt, szString);
  406.                 break;
  407.       }
  408.     }
  409.   }
  410.   //***************************************************************
  411.   // if we are successfully logged on,.....
  412.   //***************************************************************
  413.   if (iRetCode!=FTP_COMPLETE)
  414.   {
  415.     DoPrintf ("Could not log on to remote host %s", lpSite);
  416.     DoClose ((SOCKET) ctrl_skt);
  417.     SetDebugWindowText (lpDebugWindow);
  418.     MessageBox (hWndMain, szMsgBuf+4, "Login Failed", MB_OK);
  419.     return INVALID_SOCKET;
  420.   }
  421.   
  422.   bConnected=1;
  423.   wsprintf (szString,"WINFTP: %s",szRemoteHost);
  424.   SetWindowText (hWndMain, szString);
  425.   SetDebugWindowText (lpDebugWindow);
  426.   return ctrl_skt;
  427. }
  428. //***********************************************************************
  429. //***********************************************************************
  430. int DoDirList (SOCKET ctrl_skt,LPSTR szCMD)
  431. {
  432.   int nRC,nBell;
  433.   
  434.   nBell=bBell; bBell=0;
  435.   if (lstrlen (szCurrentDir)>0) unlink (szCurrentDir);
  436.   wsprintf (szCurrentDir, szTmpDirFile, nDirNum++);
  437.   nRC = RetrieveFile (ctrl_skt, szCMD, szCurrentDir, TYPE_A);
  438.   bBell = nBell;
  439.   return nRC;
  440. }
  441. //***********************************************************************
  442. //***********************************************************************
  443. int SendFile(SOCKET ctrl_skt,LPSTR szCMD,LPSTR localfile,char stype)
  444. {
  445.   int iRetCode;
  446.   int iLength;
  447.   iCode=0;
  448.   // if we don't have a valid control socket, can't do anything
  449.   if(ctrl_skt==INVALID_SOCKET) 
  450.   {
  451.     DoAddLine("no ctrl_skt, ignored");
  452.     return(0);
  453.   }
  454.   // if we are doing something, don't try to do this
  455.   if (bCmdInProgress) 
  456.   {
  457.     DoAddLine("command in process, ignored");
  458.     return(0);
  459.   }
  460.   
  461.   // if the requested type is not the same as the default type
  462.   if (cType!=stype) 
  463.   {
  464.     if(stype==TYPE_L)
  465.       command(ctrl_skt,"TYPE L 8");
  466.     else
  467.       command(ctrl_skt,"TYPE %c",stype);
  468.     cType=stype;
  469.   }
  470.   
  471.   // create a listener socket, if it is successful
  472.   if ((listen_socket=GetFTPListenSocket (ctrl_skt))!=INVALID_SOCKET) 
  473.   {
  474.     // send command to see the result of this all
  475.     // read the control channel (should return 1xx if it worked)
  476.     iRetCode = command ((SOCKET) ctrl_skt, szCMD);
  477.     if (iRetCode==FTP_PRELIM) 
  478.     {
  479.       // wait for connection back to us on the listen socket
  480.       nTimerID = SetTimer (hWndMain, 10, uiTimeOut, NULL);
  481.       // get our data connection
  482.       iLength=sizeof (saSockAddr1);
  483.       data_socket = accept (listen_socket, (struct sockaddr far *)&saSockAddr1, (int far *)&iLength);
  484.       // turn off the timeout timer
  485.       KillTimer (hWndMain, 10);
  486.       nTimerID = -1;
  487.       // if it failed, we have to quit this
  488.       if (data_socket==INVALID_SOCKET) 
  489.       {
  490.         ReportWSError("accept",WSAGetLastError());
  491.         listen_socket = DoClose (listen_socket);
  492.         iRetCode = FTP_ERROR;
  493.       } 
  494.       else 
  495.       {
  496.         // we don't need the listener socket anymore
  497.         // inform user of the connection
  498.         listen_socket = DoClose (listen_socket);
  499.         DoPrintf ("[%u] accept from %s port %u", data_socket,
  500.            inet_ntoa (saSockAddr1.sin_addr), ntohs (saSockAddr1.sin_port));
  501.         // copy the file and close the socket
  502.         iRetCode = SendMass (data_socket, localfile, stype==TYPE_I);
  503.         data_socket = DoClose (data_socket);
  504.         // read the close control message (should return 2xx)
  505.         switch (iRetCode)
  506.         {
  507.           case FTP_ABORT: break; //ForcePacket (ctrl_skt, "ABOR"); break;
  508.           default       : iRetCode = ReadDisplayLine (ctrl_skt);
  509.         }
  510.       }
  511.     } 
  512.     else 
  513.     {
  514.       listen_socket = DoClose (listen_socket);
  515.       iRetCode=0;
  516.       if (bBell) MessageBeep (MB_ICONEXCLAMATION);
  517.     }
  518.   } 
  519.   else 
  520.   {
  521.     listen_socket = DoClose (listen_socket);
  522.     iRetCode=FTP_ERROR;
  523.     if (bBell) MessageBeep (MB_ICONEXCLAMATION);
  524.   }
  525.   return iRetCode;
  526. }
  527. //*****************************************************************************
  528. //*****************************************************************************
  529. void ExtractFileSize()
  530. {
  531.   char szBuf[100];
  532.   LONG nSiz=0;
  533.   LPSTR lp;
  534.   
  535.   lstrcpy (szBuf, szMsgBuf);
  536.   strupr (szBuf);
  537.   if ((lp=strstr (szBuf, " BYTES"))!=NULL)
  538.   {
  539.     *lp-- = '';
  540.     while (*lp==' ') lp--;
  541.     while (isdigit (*lp)) lp--;
  542.     if (*lp!='') lp++;
  543.     nSiz = atol (lp);
  544.     if (nSiz>0) 
  545.     {
  546.       CreateXferWindow();
  547.       SetTotalBytes (nSiz);
  548.     }
  549.   }
  550. }
  551. //*****************************************************************************
  552. //*****************************************************************************
  553. int RetrieveFile (SOCKET ctrl_skt, LPSTR szCMD, LPSTR localfile, char rtype)
  554. {
  555.   int iRetCode;
  556.   int iLength;
  557.   iCode=0;
  558.   //*************************************************************
  559.   // if we don't have a valid control socket, can't do anything
  560.   //*************************************************************
  561.   if(ctrl_skt==INVALID_SOCKET) 
  562.   {
  563.     DoAddLine("no ctrl_skt, ignored");
  564.     return(0);
  565.   }
  566.   //*************************************************************
  567.   // if we are doing something, don't try to do this
  568.   //*************************************************************
  569.   if(bCmdInProgress) 
  570.   {
  571.     DoAddLine("command in process, ignored");
  572.     return(0);
  573.   }
  574.   
  575.   //*************************************************************
  576.   // if the requested type is not the same as the default type
  577.   //*************************************************************
  578.   if (cType!=rtype) 
  579.   {
  580.     switch (rtype)
  581.     {
  582.       case TYPE_L: command(ctrl_skt,"TYPE L 8"); break;
  583.       default    : command(ctrl_skt,"TYPE %c",rtype);
  584.     }
  585.     cType=rtype;
  586.   }
  587.   //*************************************************************
  588.   // create a listener socket, if it is successful
  589.   //*************************************************************
  590.   if ((listen_socket=GetFTPListenSocket (ctrl_skt))!=INVALID_SOCKET) 
  591.   {
  592.     //*************************************************************
  593.     // send command to see the result of this all
  594.     // read the control channel (should return 1xx if it worked)
  595.     //*************************************************************
  596.     iRetCode = command ((SOCKET)ctrl_skt,szCMD);
  597.     if (iRetCode==FTP_PRELIM) 
  598.     {
  599.       // wait for connection back to us on the listen socket
  600.       ExtractFileSize();
  601.       iLength = sizeof (saSockAddr1);
  602.       nTimerID = SetTimer (hWndMain, 10, uiTimeOut, NULL);
  603.       // get our data connection
  604.       data_socket = accept (listen_socket, (struct sockaddr far *) &saSockAddr1,
  605.                          (int far *)&iLength);
  606.       // turn off the timeout timer
  607.       KillTimer (hWndMain, 10);
  608.       nTimerID = -1;
  609.       // if it failed, we have to quit this
  610.       if (data_socket==INVALID_SOCKET) 
  611.       {
  612.         ReportWSError ("accept",WSAGetLastError());
  613.         listen_socket = DoClose (listen_socket);
  614.         iRetCode=0;
  615.       } 
  616.       else 
  617.       {
  618.         // we don't need the listener socket anymore
  619.         listen_socket = DoClose (listen_socket);
  620.         // inform user of the connection
  621.         DoPrintf ("[%u] accept from %s port %u", data_socket,
  622.           inet_ntoa (saSockAddr1.sin_addr), ntohs (saSockAddr1.sin_port));
  623.         // copy the file
  624.         iRetCode = ReadMass (data_socket, localfile, rtype==TYPE_I);
  625.         // shut the data socket down
  626.         if (iRetCode!=FTP_ABORT)
  627.         {
  628.           //************************************************
  629.           // close the data socket
  630.           // read the close control message (should return 2xx)
  631.           //************************************************
  632.           if (shutdown (data_socket, 2)!=0) ReportWSError ("ShutDown", WSAGetLastError());
  633.           data_socket = DoClose (data_socket);
  634.           iRetCode = ReadDisplayLine (ctrl_skt);
  635.         }
  636.         else
  637.         {
  638.           //************************************************
  639.           //  Transfer was aborted, try to shut down gracefully
  640.           //************************************************
  641.           // ForcePacket (ctrl_skt, "ABOR");
  642.           shutdown (data_socket, 2);
  643.           data_socket = DoClose (data_socket);
  644.         }
  645.       }
  646.     } 
  647.     else 
  648.     {
  649.       listen_socket = DoClose (listen_socket);
  650.       iRetCode=0;
  651.       if (bBell) MessageBeep (MB_ICONEXCLAMATION);
  652.     }
  653.   } 
  654.   else 
  655.   {
  656.     listen_socket = DoClose (listen_socket);
  657.     iRetCode=0;
  658.     if (bBell) MessageBeep (MB_ICONEXCLAMATION);
  659.   }
  660.   return iRetCode;
  661. }
  662. //***********************************************************************
  663. // user close routine
  664. //***********************************************************************
  665. SOCKET DoClose(SOCKET sockfd)
  666. {
  667.   LINGER linger;
  668.   if (sockfd!=INVALID_SOCKET) 
  669.   {
  670.     if (WSAIsBlocking()) 
  671.     {
  672.       DoPrintf ("[%u] Cancelled blocking call", sockfd);
  673.       WSACancelBlockingCall();
  674.       bAborted=TRUE;
  675.     }
  676.     linger.l_onoff  = TRUE;
  677.     linger.l_linger = 0;
  678.     
  679.     // Patch to make Lanera Stack work
  680.     //setsockopt (sockfd, SOL_SOCKET, SO_LINGER, (LPSTR)&linger, sizeof (linger) );
  681.     if (closesocket (sockfd)==SOCKET_ERROR)
  682.       ReportWSError("CloseSocket", WSAGetLastError());
  683.     else 
  684.     {
  685.       DoPrintf("[%u] Socket closed.",sockfd);
  686.       sockfd=INVALID_SOCKET;
  687.     }
  688.   }
  689.   if (sockfd!=INVALID_SOCKET)
  690.     DoPrintf("[%u] Failed to close socket.", sockfd);
  691.   return (sockfd);
  692. }
  693. //***********************************************************************
  694. //***********************************************************************
  695. int SendPacket (SOCKET sockfd,LPSTR msg)
  696. {
  697.   int i, nRetCode;
  698.   if (sockfd==INVALID_SOCKET) return -1;
  699.   if ((bCmdInProgress)&&(lstrcmpi (msg, "quit")!=0))
  700.   {
  701.     DoAddLine ("Command already in progress, ignored New Cmd");
  702.     return -1;
  703.   }
  704.   bCmdInProgress++;
  705.   i=lstrlen (msg);
  706.   lstrcpy (szSendPkt, msg);
  707.   // append a CRLF to the end of outgoing messages
  708.   szSendPkt[i++]='r';
  709.   szSendPkt[i++]='n';
  710.   szSendPkt[i]=0;  
  711.   i = sendstr (sockfd, szSendPkt, i, &nRetCode);
  712.   bCmdInProgress--;
  713.   return i;
  714. }
  715. //***********************************************************************
  716. //***********************************************************************
  717. int ForcePacket (SOCKET sockfd, LPSTR msg)
  718. {
  719.   int i, nRetCode;
  720.   if (sockfd==INVALID_SOCKET) return -1;
  721.   bCmdInProgress++;
  722.   i=lstrlen (msg);
  723.   lstrcpy (szSendPkt, msg);
  724.   
  725.   // append a CRLF to the end of outgoing messages
  726.   if (szSendPkt[i-1]!='n') lstrcat (szSendPkt, "rn"), i += 2;  
  727.   i = sendstr (sockfd, szSendPkt, i, &nRetCode);
  728.   bCmdInProgress--;
  729.   return i;
  730. }
  731. int iMultiLine=0;
  732. //***********************************************************************
  733. // read a reply (may be multi line) and display in debug window
  734. //***********************************************************************
  735. int ReadDisplayLine (SOCKET sockfd)
  736. {
  737.   int iRetCode;
  738.   int iContinue;
  739.   char *s;
  740.   char c;
  741.   // can't do anything if we don't have a socket
  742.   if(sockfd==INVALID_SOCKET) return(0);
  743.   
  744.   // let other routine know that we are doing something right now.
  745.   // count the lines in the response
  746.   bCmdInProgress++;
  747.   iMultiLine++;
  748.   // initialize some variables, go read the line
  749.   do
  750.   {
  751.     iContinue=0;
  752.     iRetCode = ReadLine (sockfd);
  753.     //switch (iRetCode)
  754.     //{
  755.     //  case 257: ConvertSourceDir
  756.     //}
  757.     // if it wasn't a valid value or the 4th char was a hyphen
  758.     // then it is a continuation line
  759.     if (iRetCode<100 || iRetCode>599 || szMsgBuf[3]=='-') iContinue=1;
  760.     // send the line we read to our user/debug window
  761.     DoAddLine (szMsgBuf);
  762.     // if the timer killed it
  763.     if (bAborted) { iCode=iRetCode=421; iContinue=0; break; }
  764.   
  765.     // we only want to set the real return code in certain situations
  766.     if ((iMultiLine==1 || iCode==0) && iRetCode>99 && iRetCode<600)
  767.        iCode = iRetCode;
  768.     // allow for continuation lines
  769.   }
  770.   while ((iContinue==1) || (iCode>0 && iMultiLine>1 && iRetCode!=iCode));
  771.   // ReadDisplayLine (sockfd);    
  772.   
  773.   // count back down our multiline reponses
  774.   iMultiLine--;
  775.   
  776.   // allow other processes to run
  777.   bCmdInProgress--;
  778.   if (bAborted) return FTP_ABORT;
  779.   
  780.   //************************************************
  781.   // return only the first char of return code
  782.   //************************************************
  783.   if (iCode>99 && iCode<600) return (iCode/100);
  784.   else return 0;
  785.   UNREFERENCED_PARAMETER (c);  
  786.   UNREFERENCED_PARAMETER (s);  
  787. }
  788. //***********************************************************************
  789. // read a reply line back in from the sockfd and return the
  790. // value at the beginning of the first line.
  791. //***********************************************************************
  792. int ReadLine (SOCKET sockfd)
  793. {
  794.   LPSTR szBuf;
  795.   int nI;
  796.   int iNumBytes,iN1,iN2,iN3;
  797.   int iBytesRead;
  798.   int iRetCode;
  799.   int i;
  800.   char *s, szTrim[5] = " rn";
  801.   char c;
  802.   // can't do anything if we don't have a socket
  803.   if (sockfd==INVALID_SOCKET) return(0);
  804.   // let other routines know that we are doing something right now.
  805.   bCmdInProgress++;
  806.   // make sure we don't mistakenly think we timed out
  807.   KillTimer (hWndMain, 10); 
  808.   // bAborted=FALSE;
  809.   nTimerID = -1;
  810.   // zero our receive buffer
  811.   memset (szMsgBuf, 0, 4096);
  812.   // initialize some variables
  813.   szBuf=szMsgBuf; iBytesRead=0; iRetCode=0;
  814.   // set our timeout
  815.   nTimerID = SetTimer (hWndMain, 10, uiTimeOut, NULL);
  816.   
  817.   // this routine is a little better as it read 80 characters at a time
  818.   // (if it works:-)  Here we PEEK at what is available, find the LF etc...
  819.   iNumBytes=recv (sockfd, (LPSTR) szBuf, 82, MSG_PEEK);
  820.   while (iBytesRead<4000 && (iNumBytes>0))
  821.   {
  822.     // Trumpet WinSock Alpha 15 always returns the len (82) from a recv
  823.     // with MSG_PEEK.  I suppose this is an error??? The spec doesn't say
  824.     // that MSG_PEEK returns something different than normal.
  825.     
  826.     KillTimer (hWndMain, 10);
  827.     nTimerID = -1;
  828.     iN1 = iNumBytes;
  829.     // must terminate the string so strchr doesn't go wild.
  830.     szBuf[iNumBytes]='';
  831.     
  832.     // find a LF in the input if it exists
  833.     for (nI=0; nI<iNumBytes; nI++) 
  834.     {
  835.       if (szBuf[nI]==0 || szBuf[nI]==0x0a || (bIs5000 && (szBuf[nI]==0x0d))) 
  836.       {
  837.         iNumBytes=nI+1;
  838.         break;
  839.       }
  840.     }
  841.     iN2=iNumBytes;
  842.     // otherwise read up to the full length of what the first recv saw.
  843.     // Wonder what happens here if the second receive actually returns more
  844.     // characters than the first receive and there was a LF in the extra data?   
  845.     iNumBytes = recv (sockfd, (LPSTR) szBuf, iNumBytes, 0);
  846.     // again, terminate the string
  847.     szBuf[iNumBytes]=0;
  848.     DoPrintf ("[%u] readline %u - %u - %u %s", sockfd, iN1, iN2, iNumBytes, szBuf);
  849.     // bump the receive buffer pointer
  850.     szBuf+=iNumBytes;
  851.     // count the bytes that we have read so far
  852.     iBytesRead+=iNumBytes;
  853.     // if the last character read was a LF, then stop.  NOTE: this is not really
  854.     // in keeping with RFC 959 as the line MUST end with CRLF but I work with
  855.     // a system (UNISYS 5000) that only returns a LF and no CR at the end of lines.
  856.     if(*(szBuf-1)==0x0a || (bIs5000 && *(szBuf-1)==0x0d)) break;
  857.     // otherwise reset the timer and go read more characters
  858.     nTimerID = SetTimer (hWndMain, 10, uiTimeOut, NULL);
  859.     iNumBytes=recv (sockfd, (LPSTR) szBuf, 82, MSG_PEEK);
  860.   }
  861.   // if we are here, we have a line or an error or there was nothing to read
  862.   // in any case terminate what we have
  863.   KillTimer(hWndMain, 10);
  864.   nTimerID = -1;
  865.   *szBuf=0;
  866.   //*******************************************************
  867.   // find the retcode at the beginning of the line
  868.   //*******************************************************
  869.   if (iNumBytes!=SOCKET_ERROR)
  870.   {
  871.     c=szMsgBuf[3]; 
  872.     szMsgBuf[3]=0;
  873.     iRetCode = atoi (szMsgBuf); 
  874.     szMsgBuf[3]=c;
  875.   }
  876.   else
  877.   {
  878.     int nError = WSAGetLastError();
  879.     
  880.     switch (nError)
  881.     {
  882.       case WSAEINTR    : 
  883.       case WSAENETRESET:
  884.       case WSAESHUTDOWN:
  885.       case WSAENETDOWN :
  886.       case WSAECONNABORTED:
  887.       case WSAECONNRESET:
  888.       case WSAEINVAL   :
  889.       case WSAENOTSOCK : bAborted=TRUE; break;
  890.     }
  891.   }
  892.   //*******************************************************
  893.   // if the timer killed it or was somehow aborted
  894.   //*******************************************************
  895.   if (bAborted) iRetCode=421;
  896.   // strip trailing blanks, CR's and LF's
  897.   i = lstrlen (szMsgBuf) - 1;
  898.   while ((i>1) && (strchr (szTrim, szMsgBuf[i])!=NULL)) szMsgBuf[i--]=0, i;
  899.   
  900.   // unmark our progress
  901.   bCmdInProgress--;
  902.   return iRetCode;  
  903.   UNREFERENCED_PARAMETER (iN3);  
  904.   UNREFERENCED_PARAMETER (s);  
  905. }
  906. //***********************************************************************
  907. // based on WINTEL (ftp.c) and BSD (ftp.c)
  908. //***********************************************************************
  909. SOCKET GetFTPListenSocket(SOCKET ctrl_skt)
  910. {
  911.     SOCKET listen_skt;
  912.     int iLength;
  913.     int iRetCode;
  914.     char *a,*p;
  915.     int iFlag=1;
  916.     // create a data socket
  917.     if ((listen_skt=socket (AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)
  918.     {
  919.         ReportWSError ("socket create", WSAGetLastError());
  920.         return (INVALID_SOCKET);
  921.     }
  922.     // let system pick an unused port. we tell remote end with PORT cmd
  923.     DoPrintf("[%u] going to listen %s port %u",listen_skt,
  924.       inet_ntoa(saCtrlAddr.sin_addr),ntohs(saCtrlAddr.sin_port));
  925.     if(bSendPort) 
  926.     {
  927.       saCtrlAddr.sin_port=htons(0);
  928.       saCtrlAddr.sin_family=AF_INET;
  929.       saCtrlAddr.sin_addr.s_addr=0;
  930.     } 
  931.     else
  932.     {
  933.       // otherwise we attempt to reuse our ctrl_skt
  934.       if(setsockopt (listen_skt,SOL_SOCKET,SO_REUSEADDR,
  935.          (char *)&iFlag, sizeof(iFlag))==SOCKET_ERROR)
  936.       {
  937.         ReportWSError ("setsockopt",WSAGetLastError());
  938.         closesocket (listen_skt);
  939.         return (INVALID_SOCKET);
  940.       }
  941.     }
  942.     //  Bind name to socket
  943.     if ( bind((SOCKET)listen_skt,(LPSOCKADDR)&saCtrlAddr,
  944.              (int)sizeof(struct sockaddr))==SOCKET_ERROR)
  945.     {
  946.         ReportWSError("bind",WSAGetLastError());
  947.         closesocket(listen_skt);
  948.         return (INVALID_SOCKET);
  949.     }
  950.     // get the port name that we got for later transmission in PORT cmd
  951.     iLength = sizeof (saCtrlAddr);
  952.     if (getsockname (listen_skt, (struct sockaddr *) &saCtrlAddr, &iLength)<0)
  953.     {
  954.       ReportWSError ("getsockname", WSAGetLastError());
  955.       closesocket (listen_skt);
  956.       return (INVALID_SOCKET);
  957.     }
  958.     // invoke listener
  959.     if (listen (listen_skt,1)!=0)
  960.     {
  961.       ReportWSError ("listen", WSAGetLastError());
  962.        closesocket (listen_skt);
  963.       return (INVALID_SOCKET);
  964.     }
  965. // inform remote end about our port that we created.
  966.     if(bSendPort)
  967.     {
  968.       struct sockaddr_in saTmpAddr;
  969.       int iLength;
  970.       iLength = sizeof (saTmpAddr);
  971.       if (getsockname(ctrl_skt, (LPSOCKADDR) &saTmpAddr, &iLength)==SOCKET_ERROR)
  972.       {
  973.         ReportWSError("getsockname", WSAGetLastError());
  974.       }
  975.       a = (char *) &saTmpAddr.sin_addr;
  976.       p = (char *) &saCtrlAddr.sin_port;
  977. #define  UC(b)  (((int)b)&0xff)
  978.       if ((iRetCode=command(ctrl_skt,"PORT %d,%d,%d,%d,%d,%d",
  979.             UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
  980.             UC(p[0]), UC(p[1])))!=FTP_COMPLETE) 
  981.       {
  982.         DoPrintf("[%u] remote end didn't understand our port command.",listen_skt);
  983.         return(listen_skt);
  984.       }
  985.     }
  986.     DoPrintf("[%u] listener %s port %u",listen_skt,
  987.       inet_ntoa (saCtrlAddr.sin_addr), ntohs (saCtrlAddr.sin_port));
  988.     return (listen_skt);
  989. }
  990. #ifdef WIN32
  991. #define   OPENFIL(x) _lopen (x, OF_READ | OF_SHARE_DENY_NONE)   
  992. #else
  993. #define   OPENFIL(x) _lopen (x, READ)
  994. #endif
  995. //***********************************************************************
  996. // Return the size of the specified file
  997. //***********************************************************************
  998. LONG GetFileLength (LPSTR lpName, int iFileHandle)
  999. {
  1000. #ifdef WIN32
  1001.   WIN32_FIND_DATA wfDat;
  1002.   HANDLE hFile;
  1003.   LONG lSize;
  1004.   
  1005.   hFile=FindFirstFile (lpName, &wfDat);
  1006.   if (hFile==INVALID_HANDLE_VALUE) return (LONG) -1;
  1007.   FindClose (hFile);
  1008.   lSize = (wfDat.nFileSizeHigh << 32) + wfDat.nFileSizeLow;
  1009.   return lSize;
  1010. #else
  1011.   return  _filelength (iFileHandle);
  1012. #endif
  1013. }
  1014. //***********************************************************************
  1015. // send a file through the data socket
  1016. //***********************************************************************
  1017. int SendMass (SOCKET sockfd, LPSTR szFileName, BOOL binaryflag)
  1018. {
  1019.   int iNumBytes;
  1020.   int  iRetCode;
  1021.   int  iFileHandle;
  1022.   long lBytesWritten, lBytesToGo;
  1023.   time_t ttStart;
  1024.   time_t ttStop;
  1025.   // if we don't have a socket, return an error  
  1026.   if (sockfd==INVALID_SOCKET || !(bConnected)) return FTP_ERROR;
  1027.   
  1028.   // turn on a flag so other routines know we have a command in progress
  1029.   // initialize some vars
  1030.   bCmdInProgress++;
  1031.   lBytesWritten=0l; iRetCode=FTP_ERROR; 
  1032.   // Open the local file for transmit.
  1033.   if ((iFileHandle=OPENFIL (szFileName))== -1)
  1034.   {
  1035.     DoPrintf ("Could not open file %s (%u)", szFileName, errno);
  1036.     if (bBell) MessageBeep (MB_ICONEXCLAMATION);
  1037.   }
  1038.   else
  1039.   {
  1040.     // get the start time
  1041.     ttStart=time(NULL);
  1042.     iRetCode = FTP_COMPLETE;
  1043.     lBytesToGo=GetFileLength (szFileName, iFileHandle);
  1044.     SetTotalBytes (lBytesToGo);
  1045.     DoPrintf ("Transferring %ld bytes", (long) lBytesToGo);
  1046.     SetXferWindowText (szFileName); 
  1047.     // loop to send output to remote end
  1048.     
  1049.     
  1050.     while (((iNumBytes=_lread (iFileHandle, szMsgBuf, 512))>0)
  1051.            &&(iRetCode!=FTP_ERROR)&&(iRetCode!=FTP_ABORT)&&(!bAborted))
  1052.     {
  1053.       // count the characters that we have sent out
  1054.       lBytesWritten += (LONG) sendstr (sockfd, szMsgBuf, iNumBytes, &iRetCode);
  1055.       wsprintf (szString, "%lu", lBytesWritten);
  1056.       SendMessage (hTxtLBytes, WM_SETTEXT, 0, (LPARAM)(LPCSTR) szString);
  1057.       SetXmitBytes (lBytesWritten);
  1058.     }
  1059.     
  1060.     // if the output file is open, close it
  1061.     _lclose (iFileHandle);
  1062.     switch (iRetCode)
  1063.     {
  1064.       case FTP_ERROR: DoPrintf ("Error on Transfer, aborted"); break;
  1065.       case FTP_ABORT: DoPrintf ("Transfer aborted by User"); break;
  1066.       default       : // show the user how we did
  1067.                       // get the finish time
  1068.                       ttStop=time(NULL);
  1069.                       SendMessage (hTxtLBytes, WM_SETTEXT, 0, (LPARAM) NULL);
  1070.                       PrintTransferStatus ("Transmitt", lBytesWritten, (LONG) ttStop-ttStart);
  1071.                       iRetCode=FTP_COMPLETE;
  1072.                       if (bBell) MessageBeep(MB_OK);
  1073.     }
  1074.   }
  1075.   // turn off our command in progress flag
  1076.   bCmdInProgress--;
  1077.   return (iRetCode);
  1078. }
  1079. //***********************************************************************
  1080. // read information from the data socket into a file.  
  1081. //***********************************************************************
  1082. int ReadMass (SOCKET sockfd, LPSTR szFileName,BOOL binaryflag)
  1083. {
  1084.   int  iNumBytes;
  1085.   int  iRetCode;
  1086.   int  iFileHandle;
  1087.   long lBytesRead;
  1088.   time_t ttStart;
  1089.   time_t ttStop;
  1090.   // if we don't have a socket, return an error  
  1091.   // otherwise turn on a flag so other routines know about cmd in progress
  1092.   if(sockfd==INVALID_SOCKET || !(bConnected)) return 0;
  1093.   bCmdInProgress++;
  1094.   //************************************************
  1095.   // make sure we don't mistakenly think we timed out
  1096.   // initialize some vars
  1097.   //************************************************
  1098.   KillTimer (hWndMain, 10); bAborted=FALSE;
  1099.   nTimerID = -1;
  1100.   lBytesRead=0l; iRetCode=0; 
  1101.   //***********************************************************************
  1102.   // at the moment we are ignoring the fact that the local destination file
  1103.   // may not open correctly.
  1104.   //***********************************************************************
  1105.   if ((iFileHandle=_lcreat (szFileName,0))== -1)
  1106.   {
  1107.     DoPrintf ("Failed to create file %s (%u)", szFileName,errno);
  1108.     bCmdInProgress--;
  1109.     return FTP_ERROR;
  1110.   }
  1111.   //************************************************
  1112.   // get the start time
  1113.   //************************************************
  1114.   SetXferWindowText (szFileName); 
  1115.   ttStart = time (NULL);
  1116.   
  1117.   // loop to receive input from remote end
  1118.   iNumBytes = recv (sockfd, (LPSTR)szMsgBuf, 4000, 0);
  1119.   while (!bAborted && (iNumBytes>0) && (iNumBytes!=SOCKET_ERROR))
  1120.   {
  1121.     //************************************************
  1122.     // write what we received if the file is open
  1123.     // and count the characters that we received
  1124.     //************************************************
  1125.     _lwrite (iFileHandle, szMsgBuf, iNumBytes);
  1126.     lBytesRead += iNumBytes;
  1127.     SetXmitBytes (lBytesRead);
  1128.     wsprintf (szString, "%lu", lBytesRead);
  1129.     SendMessage (hTxtRBytes, WM_SETTEXT, 0, (LPARAM)(LPCSTR) szString);
  1130.     if (!bAborted) iNumBytes = recv (sockfd, (LPSTR) szMsgBuf, 4000, 0);
  1131.   }
  1132.   
  1133.   //************************************************
  1134.   // get the finish time
  1135.   // if the output file is open, close it
  1136.   //************************************************
  1137.   ttStop = time (NULL);
  1138.   if (iFileHandle != -1)  _lclose (iFileHandle);
  1139.   if (bAborted) _unlink (szFileName), DoPrintf ("Delete partially downloaded file"); 
  1140.   //************************************************
  1141.   // if we had a recv error, let us know about it
  1142.   //************************************************
  1143.   if (iNumBytes==SOCKET_ERROR)
  1144.   {
  1145.     ReportWSError ("Recv", iRetCode=WSAGetLastError());
  1146.     if (lBytesRead==0l)
  1147.     {
  1148.       if(bBell) MessageBeep (MB_ICONEXCLAMATION);
  1149.     }
  1150.   }
  1151.   else
  1152.   {
  1153.     //************************************************
  1154.     // show the user how we did
  1155.     // turn off our command in progress flag
  1156.     //************************************************
  1157.     SendMessage (hTxtRBytes, WM_SETTEXT, 0, (LPARAM) NULL);
  1158.     PrintTransferStatus ("Receiv", lBytesRead, (LONG) ttStop-ttStart);
  1159.     if (bBell) MessageBeep (MB_OK);
  1160.     iRetCode = (bAborted) ? FTP_ABORT : FTP_COMPLETE;
  1161.   }
  1162.   bCmdInProgress--;
  1163.   return iRetCode;
  1164. }