home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / winsock / wsftp32 / ws_con.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  33.5 KB  |  1,148 lines

  1. /***************************************************************************
  2.   Windows Sockets Client Application Support Module
  3.  
  4.   Written by:
  5.       John A. Junod             Internet: <junodj@gordon-emh2.army.mil>
  6.       267 Hillwood Street                 <zj8549@trotter.usma.edu>
  7.       Martinez, GA 30907      Compuserve: 72321,366 
  8.  
  9.   This program executable and all source code is released into the public
  10.   domain.  It would be nice (but is not required) to give me a little 
  11.   credit for any use of this code.  
  12.  
  13.   THE INFORMATION AND CODE PROVIDED IS PROVIDED AS IS WITHOUT WARRANTY 
  14.   OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  15.   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  16.   PURPOSE. IN NO EVENT SHALL JOHN A. JUNOD BE LIABLE FOR ANY DAMAGES 
  17.   WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS 
  18.   OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF JOHN A. JUNOD HAS BEEN 
  19.   ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  20.  
  21. *****************************************************************************/
  22.  
  23. #include "ws_glob.h"
  24. #include "ws_ftp.h"
  25. #include <stdio.h>
  26. #include <stdarg.h>
  27. #include <ctype.h>
  28. #include <io.h>
  29. #include <fcntl.h>
  30. #include <sys\stat.h>
  31. #include <time.h>
  32. #include <stdlib.h>  // atoi()
  33.  
  34. extern int errno;
  35. extern int nHostType;
  36. extern BOOL bAborted;   // timer routine may set this
  37. BOOLEAN globalsucceed = FALSE;
  38. int iMultiLine=0;
  39. extern volatile BOOLEAN aborttimerexpired;
  40.  
  41. // lgk new globals so we can close open files on an abort or close
  42. BOOLEAN sendingfile = FALSE;
  43. BOOLEAN receivingfile = FALSE;
  44. int sendingfilehandle = -1;
  45. int receivefilehandle = -1;
  46.  
  47.  // lgk timer messages do not work for use because we have mult. threads
  48.  // so create a timer proc.
  49.  
  50.  extern BOOLEAN check_busy();
  51.  extern void set_busy();
  52.  
  53.  void closefilesonabort(rwasopen,swasopen)
  54.    BOOLEAN *rwasopen;
  55.    BOOLEAN *swasopen;
  56.    
  57.    {
  58.          *rwasopen = FALSE;
  59.          *swasopen = FALSE;
  60.  
  61.     if (receivingfile)
  62.       {
  63.          *rwasopen = TRUE;
  64.          _lclose(receivefilehandle);
  65.          receivingfile = FALSE;
  66.          receivefilehandle = -1;
  67.       }
  68.     if (sendingfile)
  69.       {
  70.          *swasopen = TRUE;
  71.          _lclose(sendingfilehandle);
  72.          sendingfile = FALSE;
  73.          sendingfilehandle = -1;
  74.       }
  75.  
  76.    }
  77.  
  78.  
  79. // lgk new routine to wait for 550 message after closesocket
  80. DWORD waitfor550(SOCKET ctrl_skt)
  81. {
  82.  int iRetCode = 0;
  83.  BOOLEAN aborttimerexpired = FALSE;
  84.  
  85.   while((iRetCode != 550) && (aborttimerexpired == FALSE))
  86.   {
  87.    iRetCode = ReadDisplayLine(ctrl_skt);
  88.    // some servers return message 226 or ok so if we get 2 set it to 550
  89.    if (iRetCode = 2)
  90.      iRetCode = 550;
  91.  
  92.      DoPrintf("Got abort response = %d \n",iRetCode);
  93.   }     
  94.  
  95.   if (aborttimerexpired)
  96.     {   DoPrintf("Abort Timeout has Expired\n");
  97.         DoPrintf("Abort Failed... Recommend you close/reconnect\n");
  98.         set_busy(FALSE);
  99.         bCmdInProgress = 0;
  100.     }
  101.    
  102.   return 0;
  103.      
  104.  }
  105.  
  106.   
  107.  VOID CALLBACK mytimerproc(wind,msg,idevent,systime)
  108.  HWND wind;
  109.  UINT msg;
  110.  UINT idevent;
  111.  DWORD systime;
  112.  {
  113.        DoPrintf("Timer has Expired\n");
  114.       if(idevent ==10)
  115.         {
  116.         KillTimer(wind,10);
  117.         if(WSAIsBlocking())
  118.          {
  119.             // lgk if we are blocking in another thread here we need to kill
  120.             // it also
  121.            if (check_busy())
  122.             {
  123.              DoPrintf("Timer cancelled blocking call\n");    
  124.              bAborted=TRUE;
  125.              WSACancelBlockingCall();
  126.              TerminateThread(threadhandle,1);
  127.              set_busy(FALSE);
  128.             }
  129.          else
  130.          {
  131.           DoPrintf("Timer cancelled blocking call\n");    
  132.           bAborted=TRUE;
  133.           WSACancelBlockingCall();
  134.          }
  135.         }
  136.        }
  137. }
  138.  
  139.   
  140. /*
  141. // send a message on the control socket, read and display the resulting
  142. // message and return the result value
  143. */
  144. int getreply(SOCKET ctrl_skt,LPSTR cmdstring)
  145. {
  146.   int iRetCode=0;
  147.  
  148.   iCode=0;
  149.   if(strncmp(cmdstring,"PASS ",5)==0)
  150.     DoAddLine("PASS xxxxxx");
  151.   else
  152.     DoAddLine(cmdstring);
  153.   if(ctrl_skt==INVALID_SOCKET) {
  154.     DoAddLine("Not connected");
  155.   } else {
  156.     if(SendPacket(ctrl_skt,cmdstring)!=-1)
  157.       iRetCode=ReadDisplayLine(ctrl_skt);
  158.   }
  159.   return(iRetCode);  // 0 - 5
  160. }
  161.  
  162. int command(SOCKET ctrl_skt, char *fmt,...)
  163. {
  164.    va_list args;
  165.    char szBuf[90];
  166.  //  int  iRetCode;
  167.  
  168.    va_start(args,fmt);
  169.    vsprintf(szBuf,fmt,args);
  170.    va_end(args);
  171.    return(getreply(ctrl_skt,szBuf));
  172. }
  173.  
  174. int qcommand(SOCKET ctrl_skt, char *fmt,...)
  175. {
  176.    va_list args;
  177.    char szBuf[90];
  178.  //  int  iRetCode;
  179.  
  180.    va_start(args,fmt);
  181.    vsprintf(szBuf,fmt,args);
  182.    va_end(args);
  183.    command(ctrl_skt,szBuf);
  184.    return iCode ;
  185. }
  186.  
  187. // return a string pointer to ON or OFF based on the flag
  188. char *onoff(BOOL flag)
  189. {
  190.   if(flag) return("ON"); else return("OFF");
  191. }
  192.  
  193. // process CWD
  194. int DoCWD(SOCKET ctrl_skt,LPSTR path)
  195. {
  196.   if(command(ctrl_skt,"CWD %s",path)==FTP_ERROR && iCode==500) {
  197.     command(ctrl_skt,"XCWD %s",path);
  198.   }
  199.   return(iCode/100);
  200. }
  201.  
  202. // proces PWD
  203. int DoPWD(SOCKET ctrl_skt)
  204. {
  205.   if(command(ctrl_skt,"PWD")==FTP_ERROR && iCode==500) {
  206.     command(ctrl_skt,"XPWD");
  207.   }
  208.   return(iCode/100);
  209. }
  210.  
  211. // process MKD
  212. int DoMKD(SOCKET ctrl_skt,LPSTR pathname)
  213. {
  214.   if(command(ctrl_skt,"MKD %s",pathname)==FTP_ERROR && iCode==500) {
  215.     command(ctrl_skt,"XMKD %s",pathname);
  216.   }     
  217.   if (iCode != 550)
  218.   return(iCode/100);
  219.   else return iCode;
  220. }
  221.  
  222. // process RMD
  223. int DoRMD(SOCKET ctrl_skt,LPSTR pathname)
  224. {
  225.   if(command(ctrl_skt,"RMD %s",pathname)==FTP_ERROR && iCode==500)
  226.     command(ctrl_skt,"XRMD %s",pathname);
  227.   return(iCode/100);
  228. }
  229.  
  230. // process DELE
  231. int DoDELE(SOCKET ctrl_skt,LPSTR pathname)
  232. {
  233.   command(ctrl_skt,"DELE %s",pathname);
  234.   return(iCode/100);
  235. }
  236.  
  237. // process user command
  238. int DoQUOTE(SOCKET ctrl_skt,LPSTR string)
  239. {
  240.   if(strncmp(string,"LIST",4)==0 ||
  241.      strncmp(string,"NLST",4)==0)
  242.     DoDirList(ctrl_skt,string);
  243.   else
  244.     command(ctrl_skt,string);
  245.   return(iCode/100);
  246. }
  247.  
  248. // process chmod
  249. int DoCHMOD(SOCKET ctrl_skt,LPSTR modes,LPSTR filename)
  250. {
  251.   return(command(ctrl_skt,"SITE CHMOD %s %s",modes,filename));
  252. }
  253.  
  254. extern BOOL bHELP;
  255.  
  256. // initial connection
  257. volatile SOCKET DoConnect2(LPSTR ftp_host)
  258. {
  259.   int iLength,iRetCode;
  260.   int iFlag=1;
  261.   char host[80] ;
  262.   volatile SOCKET ctrl_skt;
  263.  
  264.   if(bConnected) {
  265.     DoAddLine("Already connected!");
  266.     return(INVALID_SOCKET);
  267.   }
  268.   // let other routines know that we are busy
  269.   bCmdInProgress++;
  270.  
  271. // DoPrintf("host name in doconnect is %s\n",ftp_host);
  272.   
  273.   bHELP=FALSE;
  274.  
  275.   if(use_gateway)
  276.     strcpy(host, szGateHost) ;
  277.   else
  278.     strcpy(host, ftp_host) ;
  279.  
  280.   // create a connected socket
  281.   if((ctrl_skt=connectTCP(host,"ftp"))==INVALID_SOCKET) {
  282.     //DoAddLine("connection failed");
  283.     DoPrintf("Connection to %s failed",host) ;
  284.     bCmdInProgress--;
  285.     return(INVALID_SOCKET);
  286.   }
  287.   // get information about local end of the connection
  288.   iLength = sizeof (saCtrlAddr);
  289.   if (getsockname(ctrl_skt,(struct sockaddr *)&saCtrlAddr, &iLength)
  290.       ==SOCKET_ERROR)
  291.   {
  292.     ReportWSError("getsockname",WSAGetLastError());
  293.     bCmdInProgress--;
  294.     DoClose(ctrl_skt);
  295.     return(INVALID_SOCKET);
  296.   }
  297.   // show remote end address
  298.   DoPrintf("[%u] from %s port %u",ctrl_skt,
  299.            inet_ntoa(saCtrlAddr.sin_addr),
  300.            ntohs(saCtrlAddr.sin_port));
  301.   // get initial message from remote end
  302.   // lgk need to set the global control_socket to ctrl_skt here since
  303.   // it will be returned but abort does not work unless it is set here
  304.   ctrl_socket = ctrl_skt;
  305.   iMultiLine = 0;
  306.   iCode = 0;
  307.   
  308.   while((iRetCode=ReadDisplayLine(ctrl_skt))==FTP_PRELIM && !bAborted)  // 93.12.04
  309.     if(nHostType==HOST_TYPE_AUTO) {
  310.       if(strstr(szMsgBuf,"(EXOS")!=NULL)
  311.         nHostType=HOST_TYPE_U5000;
  312.     }
  313.   // if it succeeded
  314.   if(iRetCode==FTP_COMPLETE) {
  315.     if(nHostType==HOST_TYPE_AUTO) {
  316.       if(strstr(szMsgBuf,"(EXOS")!=NULL)
  317.         nHostType=HOST_TYPE_U5000;
  318.     }
  319.     if (setsockopt(ctrl_skt, SOL_SOCKET, SO_OOBINLINE,
  320.         (LPSTR)&iFlag, sizeof(iFlag))==SOCKET_ERROR)
  321.     {
  322.       ReportWSError("setsockopt",WSAGetLastError());
  323.     }
  324.     // have to reset this so "command" will work
  325.     bCmdInProgress--;
  326.  
  327.     if(use_gateway)
  328.       { // send our userid
  329.       if((iRetCode=command(ctrl_skt,"USER %s",szGateUserID))==FTP_CONTINUE)
  330.       { // if the remote system requires a password, send it.
  331.         iRetCode=command(ctrl_skt,"PASS %s",szGatePassWord);
  332.       }
  333.       if(iRetCode!=FTP_COMPLETE)
  334.       { // if we failed to successfully log on
  335.         DoAddLine("Gateway logon failure, so quitting");
  336.         DoClose((SOCKET)ctrl_skt);
  337.         return(INVALID_SOCKET);
  338.       }
  339.  
  340.       if((iRetCode=qcommand(ctrl_skt,"site %s",ftp_host))==FTP_ERROR)
  341.       {
  342.         DoAddLine("Connect to final destination failed, so quitting");
  343.         DoClose((SOCKET)ctrl_skt);
  344.         bConnected=0;
  345.         return(INVALID_SOCKET);
  346.       }
  347.       bConnected=1;
  348.      // lgk now that we are connected enable the close button and disable the
  349.      // open button
  350.      EnableWindow(hBtnClose,TRUE);
  351.      EnableWindow(hBtnConnect,FALSE);
  352.  
  353.     } // end of gateway connect
  354.  
  355.     // send our userid to the ftp_host
  356.     if((iRetCode=command(ctrl_skt,"USER %s",szUserID))==FTP_CONTINUE) // || 1)
  357.     {
  358.       while(szPassWord[0]==0) {
  359.         StdInputPassword(szPassWord,"Need a password:");
  360.       }
  361.       // if the remote system requires a password, send it.
  362.       if((iRetCode=command(ctrl_skt,"PASS %s",szPassWord))==FTP_CONTINUE)
  363.       {
  364.         // if the remote system requires an account, send it.
  365.         StdInput(NULL,"Need an account:");
  366.         iRetCode=command(ctrl_skt,"ACCT %s",szDlgEdit);
  367.       }
  368.     }
  369.     // if we are successfully logged on,.....
  370.     if(iRetCode!=FTP_COMPLETE) // || 0)
  371.     {
  372.       DoAddLine("logon failure, so quitting");
  373.       DoClose((SOCKET)ctrl_skt);
  374.       bConnected=0;
  375.       EnableWindow(hBtnClose,FALSE);
  376.       EnableWindow(hBtnConnect,TRUE);
  377.      return(INVALID_SOCKET);
  378.     }
  379.     bConnected=1;
  380.     EnableWindow(hBtnClose,TRUE);
  381.     EnableWindow(hBtnConnect,FALSE);
  382.  
  383.   } else {
  384.     DoPrintf("unk open msg \"%s\" %u",szMsgBuf,iCode);
  385.     // allow other processes to work
  386.     bCmdInProgress--;
  387.     DoClose((SOCKET)ctrl_skt);
  388.     bConnected = 0;
  389.     EnableWindow(hBtnClose,TRUE);
  390.     EnableWindow(hBtnConnect,FALSE);
  391.  
  392.     return(INVALID_SOCKET);
  393.   }
  394.   wsprintf(szString,"WS_FTP32 %s",szRemoteHost);
  395.   SetWindowText(hWndMain,szString);
  396.   return (ctrl_skt);
  397. }
  398.  
  399. // lgk new connect routine that retires
  400.  
  401. // initial connection
  402. volatile SOCKET DoConnect(LPSTR ftp_host)
  403. {
  404.  
  405.  int tries = 0;
  406.  volatile SOCKET rval =  0;
  407.  BOOLEAN done = FALSE;
  408.  
  409.  while (done == FALSE)
  410.  
  411.  {
  412.     
  413.  rval=DoConnect2(ftp_host);
  414.  
  415.  if (rval == INVALID_SOCKET)
  416.    {
  417.     // we failed so check if we want to retry
  418.     if (uiRetries > tries)
  419.       {
  420.         DoPrintf("Connection failed...Retrying (%d of %d)",++tries,uiRetries);
  421.       }  
  422.     else done = TRUE;
  423.  
  424.    }
  425.  else done = TRUE;
  426.  
  427.  } // end of loop
  428.  
  429.  
  430.  if (rval != INVALID_SOCKET)
  431.     {
  432.      if (bBell == 1)   
  433.        MessageBeep(MB_ICONASTERISK);
  434.      }
  435.  else if (uiRetries > 0)
  436.     {
  437.      DoPrintf("All %d Retries failed...Connection to %s Failed.",uiRetries,ftp_host);
  438.      if (bBell == 1) 
  439.        MessageBeep(MB_ICONEXCLAMATION);
  440.     }
  441.  
  442.  return (rval);
  443.  
  444.  
  445. int DoDirList(SOCKET ctrl_skt,LPSTR szCMD)
  446. {
  447.   int nRC,nBell;
  448.   nBell=bBell; bBell=0;
  449.   nRC=RetrieveFile(ctrl_skt,szCMD,szTmpFile,szTmpFile,TYPE_A);
  450.   bBell=nBell;
  451.   return(nRC);
  452. }
  453.  
  454. int SendFile(SOCKET ctrl_skt,LPSTR szCMD,LPSTR localfile,char stype)
  455. {
  456.   int iRetCode;
  457.   int iLength;
  458.   int iFlag = 1;
  459.  
  460.   iCode=0;
  461.   // if we don't have a valid control socket, can't do anything
  462.   if(ctrl_skt==INVALID_SOCKET) {
  463.     DoAddLine("no ctrl_skt, ignored");
  464.     return(0);
  465.   }
  466.   // if we are doing something, don't try to do this
  467.   if(bCmdInProgress) {
  468.     DoAddLine("command in process, ignored");
  469.     return(0);
  470.   }
  471.   // if the requested type is not the same as the default type
  472.   if(cType!=stype) {
  473.     if(stype==TYPE_L)
  474.       command(ctrl_skt,"TYPE L 8");
  475.     else
  476.       command(ctrl_skt,"TYPE %c",stype);
  477.     cType=stype;
  478.   }
  479.   // create a listener socket, if it is successful
  480.   if((listen_socket=GetFTPListenSocket(ctrl_skt))!=INVALID_SOCKET)
  481.    {
  482.     // send command to see the result of this all
  483.     iRetCode=command((SOCKET)ctrl_skt,szCMD);
  484.     // read the control channel (should return 1xx if it worked)
  485.     if(iRetCode==FTP_PRELIM) {
  486.       // wait for connection back to us on the listen socket
  487.       SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  488.       // get our data connection
  489.       iLength=sizeof(saSockAddr1);
  490.       data_socket=accept(listen_socket,(struct sockaddr far *)&saSockAddr1,
  491.                          (int far *)&iLength);
  492.       
  493.       // turn off the timeout timer
  494.       KillTimer(hWndMain,10);
  495.       
  496.       // if it failed, we have to quit this
  497.       if(data_socket==INVALID_SOCKET) 
  498.        {
  499.         ReportWSError("accept",WSAGetLastError());
  500.         listen_socket=DoClose(listen_socket);
  501.         if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  502.          iRetCode=0;
  503.        } else 
  504.          {
  505.       // lgk set for reuse
  506.       if(setsockopt(data_socket,SOL_SOCKET,SO_REUSEADDR,
  507.          (char *)&iFlag,sizeof(iFlag))==SOCKET_ERROR)
  508.       {
  509.         ReportWSError("setsockopt",WSAGetLastError());
  510.         closesocket(data_socket);
  511.         if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  512.         iRetCode =0;
  513.       }
  514.          else
  515.       {
  516.         // we don't need the listener socket anymore
  517.         listen_socket=DoClose(listen_socket);
  518.         // inform user of the connection
  519.         DoPrintf("[%u] accept from %s port %u", data_socket,
  520.           inet_ntoa(saSockAddr1.sin_addr),ntohs(saSockAddr1.sin_port));
  521.         // copy the file
  522.         iRetCode=SendMass(data_socket,localfile,stype==TYPE_I);
  523.         // close the socket
  524.         data_socket=DoClose(data_socket);
  525.         // read the close control message (should return 2xx)
  526.         iRetCode=ReadDisplayLine(ctrl_skt);
  527.       } // ok setsock
  528.       }    // ok open
  529.     } else 
  530.      {
  531.       listen_socket=DoClose(listen_socket);
  532.       iRetCode=0;
  533.       if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  534.      }
  535.   } // get listen socket failed
  536.    else 
  537.    {
  538.     listen_socket=DoClose(listen_socket);
  539.     iRetCode=0;
  540.     if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  541.    }
  542.   return(iRetCode);
  543. }
  544.  
  545. int RetrieveFile(SOCKET ctrl_skt,LPSTR szCMD,LPSTR localfile, LPSTR shortname,char rtype)
  546. {
  547.   int iRetCode;
  548.   int iLength;
  549.   int iFlag = 1;
  550.  
  551.   iCode=0;
  552.   iMultiLine = 0;
  553.   // if we don't have a valid control socket, can't do anything
  554.   if(ctrl_skt==INVALID_SOCKET) {
  555.     DoAddLine("no ctrl_skt, ignored");
  556.     return(0);
  557.   }
  558.   // if we are doing something, don't try to do this
  559.   if(bCmdInProgress) {
  560.     DoAddLine("command in process, ignored");
  561.     return(0);
  562.   }
  563.   // if the requested type is not the same as the default type
  564.   if(cType!=rtype) {
  565.     if(rtype==TYPE_L)
  566.       command(ctrl_skt,"TYPE L 8");
  567.     else
  568.       command(ctrl_skt,"TYPE %c",rtype);
  569.     cType=rtype;
  570.   }
  571.   // create a listener socket, if it is successful
  572.   if((listen_socket=GetFTPListenSocket(ctrl_skt))!=INVALID_SOCKET)
  573.      {
  574.     // send command to see the result of this all
  575.     iRetCode=command((SOCKET)ctrl_skt,szCMD);
  576.     // read the control channel (should return 1xx if it worked)
  577.     if(iRetCode==FTP_PRELIM) {
  578.       // wait for connection back to us on the listen socket
  579.       SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  580.       // get our data connection
  581.       iLength=sizeof(saSockAddr1);
  582.       data_socket=accept(listen_socket,(struct sockaddr far *)&saSockAddr1,
  583.                          (int far *)&iLength);
  584.     // lgk check for error case here
  585.     if (data_socket == INVALID_SOCKET)
  586.       {
  587.          ReportWSError("accept for retrieve",WSAGetLastError());
  588.              data_socket=DoClose(data_socket);
  589.              return 0;
  590.       }
  591.        
  592.       if(setsockopt(data_socket,SOL_SOCKET,SO_REUSEADDR,
  593.          (char *)&iFlag,sizeof(iFlag))==SOCKET_ERROR)
  594.       {
  595.         ReportWSError("setsockopt",WSAGetLastError());
  596.         closesocket(data_socket);
  597.         return(INVALID_SOCKET);
  598.       }
  599.   
  600.       // turn off the timeout timer
  601.       KillTimer(hWndMain,10);
  602.       // if it failed, we have to quit this
  603.       if(data_socket==INVALID_SOCKET) {
  604.         ReportWSError("accept",WSAGetLastError());
  605.         listen_socket=DoClose(listen_socket);
  606.         iRetCode=0;
  607.       } else {
  608.         // we don't need the listener socket anymore
  609.         listen_socket=DoClose(listen_socket);
  610.         // inform user of the connection
  611.         DoPrintf("[%u] accept from %s port %u", data_socket,
  612.           inet_ntoa(saSockAddr1.sin_addr),ntohs(saSockAddr1.sin_port));
  613.         // copy the file
  614.         iRetCode=ReadMass(data_socket,localfile,shortname,rtype==TYPE_I);
  615.         // shut the data socket down
  616.         if(shutdown(data_socket,2)!=0)
  617.           ReportWSError("shutdown",WSAGetLastError());
  618.         // close the data socket
  619.         data_socket=DoClose(data_socket);
  620.         // read the close control message (should return 2xx)
  621.         iRetCode=ReadDisplayLine(ctrl_skt);
  622.       }
  623.     } else {
  624.       listen_socket=DoClose(listen_socket);
  625.       iRetCode=0;
  626.       if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  627.     }
  628.  
  629.   } else {
  630.     listen_socket=DoClose(listen_socket);
  631.     iRetCode=0;
  632.     if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  633.   }
  634.   return(iRetCode);
  635. }
  636.  
  637. // user close routine
  638. volatile SOCKET DoClose(SOCKET sockfd)
  639. {
  640. LINGER ntlinger;
  641.  
  642.   if(sockfd!=INVALID_SOCKET) {
  643.   if(WSAIsBlocking())
  644.     {      
  645.       DoPrintf("(%u) Cancelled blocking call",sockfd);
  646.       WSACancelBlockingCall();
  647.       bAborted=TRUE;
  648.  
  649.     }
  650.  // dont report error here since shutdown does not work on non data sockets
  651. //    if(shutdown(sockfd,2)==SOCKET_ERROR)
  652. //      ReportWSError("shutdown",WSAGetLastError());
  653.    
  654.    shutdown(sockfd,2);
  655.  
  656. //  93.12.04 - so Lanera Winsock Works
  657.    ntlinger.l_onoff  = (u_short)TRUE;
  658.     ntlinger.l_linger = (u_short)0;
  659.     setsockopt(sockfd,SOL_SOCKET,SO_LINGER,
  660.                 (LPSTR)&ntlinger,sizeof(ntlinger) );
  661.  
  662.     if(closesocket(sockfd)==SOCKET_ERROR)
  663.       ReportWSError("closesocket",WSAGetLastError());
  664.     else {
  665.             DoPrintf("[%u] Socket closed.",sockfd);
  666.             sockfd=INVALID_SOCKET;
  667.     }
  668.   }
  669.  
  670.   if(sockfd!=INVALID_SOCKET)
  671.     DoPrintf("%u Failed to close socket.",sockfd);
  672.  
  673.   return(sockfd);
  674. }
  675.  
  676. int SendPacket(SOCKET sockfd,LPSTR msg)
  677. {
  678.   int i;
  679.  
  680.   if(sockfd==INVALID_SOCKET) return(-1);
  681.   if(bCmdInProgress) {
  682.     DoAddLine("command in progress, ignored");
  683.     return (-1);
  684.   }
  685.   bCmdInProgress++;
  686.   i=strlen(msg);
  687.   strcpy(szSendPkt,msg);
  688.   // append a CRLF to the end of outgoing messages
  689.   szSendPkt[i++]='\r';
  690.   szSendPkt[i++]='\n';
  691.   szSendPkt[i]=0;  
  692.   i=sendstr(sockfd,szSendPkt,i);
  693.   bCmdInProgress--;
  694.   return (i);
  695. }
  696.  
  697. // read a reply (may be multi line) and display in debug window
  698. int ReadDisplayLine(SOCKET sockfd)
  699. {
  700.   int iRetCode;
  701.   int iContinue;
  702.  // char *s;
  703.  // char c;
  704.  
  705.   // can't do anything if we don't have a socket
  706.   if(sockfd==INVALID_SOCKET) return(0);
  707.   // let other routine know that we are doing something right now.
  708.   bCmdInProgress++;
  709.   // count the lines in the response
  710.   iMultiLine++;
  711.   // initialize some variables
  712.   iContinue=0;
  713.   // go read the line
  714.   iRetCode=ReadLine(sockfd);
  715.   // if it wasn't a valid value or the 4th char was a hyphen
  716.   // lgk check for error here and return if so
  717.   if (iRetCode == SOCKET_ERROR)
  718.     {
  719.      return  iRetCode;
  720.     }
  721.   // lgk bug here when iretcode == 0 does not mean continue
  722.  
  723.   if(((iRetCode<100) && (iRetCode > 0)) || iRetCode>599 || szMsgBuf[3]=='-')
  724.     // then it is a continuation line
  725.     iContinue=1;
  726.   // lgk do not add blank lines to the window
  727.   if (strlen(szMsgBuf) != 0)  
  728.   // send the line we read to our user/debug window
  729.       DoAddLine((LPSTR)&szMsgBuf[0]);
  730.  
  731.   //  DoPrintf("iRetCode=%u,  =%u",iRetCode,iContinue);
  732.   // if the timer killed it
  733.   if(bAborted) { iCode=iRetCode=421; iContinue=0; }
  734.   // we only want to set the real return code in certain situations
  735.   if((iMultiLine==1 || iCode==0) && iRetCode>99 && iRetCode<600)
  736.     iCode=iRetCode;
  737.   // handle continuation lines
  738.   // dont do this if we have a null line
  739.  
  740.   if(iContinue==1 || (iCode>0 && iMultiLine>1 && iRetCode!=iCode))
  741.     ReadDisplayLine(sockfd);
  742.   // count back down our multiline reponses
  743.   iMultiLine--;
  744.   // allow other processes to run
  745.   bCmdInProgress--;
  746.   // return only the first char of return code
  747.  // lgk special case here to return 550 not first char
  748.  if (iCode==550)
  749.    return iCode;
  750.  if(iCode>99 && iCode<600)
  751.     return (iCode/100);
  752.   else return 0;
  753. }
  754.  
  755. // read a reply line back in from the sockfd and return the
  756. // value at the beginning of the first line.
  757. int ReadLine(SOCKET sockfd)
  758. {
  759.   LPSTR szBuf;
  760.   int nIndex;
  761.   int iNumBytes,iN1,iN2; //.iN3;
  762.   int iBytesRead;
  763.   int iRetCode;
  764.   int i;
  765.  // char *s;
  766.   char c;
  767.  
  768.   // can't do anything if we don't have a socket
  769.   if(sockfd==INVALID_SOCKET) return(0);
  770.   // let other routines know that we are doing something right now.
  771.   bCmdInProgress++;
  772.   // make sure we don't mistakenly think we timed out
  773.   KillTimer(hWndMain,10); bAborted=FALSE;
  774.   // zero our receive buffer
  775.   memset(szMsgBuf,0,4096);
  776.   // initialize some variables
  777.   szBuf=szMsgBuf; iBytesRead=0; iRetCode=0;
  778.   // set our timeout
  779.   SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  780.   // this routine is a little better as it read 80 characters at a time
  781.   // (if it works:-)  Here we PEEK at what is available, find the LF etc...
  782.  
  783.  // lgk here we have a bug and it puts the system in an endless loop
  784.  // we don't check for a socket error but one happens fix this
  785.  iNumBytes=recv(sockfd,(LPSTR)szBuf,82,MSG_PEEK);
  786.  if (iNumBytes == SOCKET_ERROR)
  787.   {
  788.    ReportWSError("socket recv (peek)",WSAGetLastError());
  789.    return (SOCKET_ERROR);
  790.   }
  791.  
  792.   while(iBytesRead<4000 && (iNumBytes > 0))
  793.   {
  794.     // Trumpet WinSock Alpha 15 always returns the len (82) from a recv
  795.     // with MSG_PEEK.  I suppose this is an error??? The spec doesn't say
  796.     // that MSG_PEEK returns something different than normal.
  797.     KillTimer(hWndMain,10);
  798.     iN1=iNumBytes;
  799.     // must terminate the string so strchr doesn't go wild.
  800.     szBuf[iNumBytes]=0;
  801.     // find a LF in the input if it exists
  802.     //
  803.     for(nIndex=0;nIndex<iNumBytes;nIndex++)
  804.       if(szBuf[nIndex]==0 || szBuf[nIndex]==0x0a) {
  805.         iNumBytes=nIndex+1;
  806.         break;
  807.       }
  808.     // have to treat the UNISYS 5000 (EXOS driver) special.  It sends a
  809.     // line with a CR at end and no LF and then follows it up with a
  810.     // separate packet that has a CR/LF.  Usually this second packet is
  811.     // not there when we peek but is when we read (answers my question
  812.     // about the second receive containing new data!!... jaj 931024)
  813.     if(iNumBytes>80 && nHostType==HOST_TYPE_U5000)
  814.       for(nIndex=0;nIndex<iNumBytes;nIndex++)
  815.         if(szBuf[nIndex]==0x0d) {
  816.           iNumBytes=nIndex+2;
  817.           break;
  818.         }
  819.     iN2=iNumBytes;
  820.     // otherwise read up to the full length of what the first recv saw.
  821.     // Wonder what happens here if the second receive actually returns more
  822.     // characters than the first receive and there was a LF in the extra data?   
  823.     iNumBytes=recv(sockfd,(LPSTR)szBuf,iNumBytes,0);
  824.     // again, terminate the string
  825.     szBuf[iNumBytes]=0;
  826.     DoPrintf("[%u] readline %u - %u - %u %s",sockfd,iN1,iN2,iNumBytes,szBuf);
  827.     // bump the receive buffer pointer
  828.     szBuf+=iNumBytes;
  829.     // count the bytes that we have read so far
  830.     iBytesRead+=iNumBytes;
  831.     // if the last character read was a LF, then stop.
  832.     if(*(szBuf-1)==0x0a)
  833.       break;         // '\n') break;
  834.     // otherwise reset the timer and go read more characters
  835.     SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  836.   }
  837.   // if we are here, we have a line or an error or there was nothing to read
  838.   KillTimer(hWndMain,10);
  839.   // in any case terminate what we have
  840.   *szBuf=0;
  841.   // find the retcode at the beginning of the line
  842.   c=szMsgBuf[3]; szMsgBuf[3]=0; iRetCode=atoi(szMsgBuf); szMsgBuf[3]=c;
  843.   // if the timer killed it
  844.   if(bAborted) iRetCode=421;
  845.   // strip trailing blanks, CR's and LF's
  846.   while((i=strlen(szMsgBuf))>2 &&
  847.         (szMsgBuf[i-1]==0x0a || szMsgBuf[i-1]==0x0d || szMsgBuf[i-1]==' '))
  848.     szMsgBuf[i-1]=0;
  849.   // unmark our progress
  850.   bCmdInProgress--;
  851.  
  852.   return(iRetCode);
  853. }
  854.  
  855. // based on WINTEL (ftp.c) and BSD (ftp.c)
  856. volatile SOCKET GetFTPListenSocket(SOCKET ctrl_skt)
  857. {
  858.     SOCKET listen_skt;
  859.     int iLength;
  860.     int iRetCode;
  861.     char *a,*p;
  862.     int iFlag=1;
  863.  
  864.     // create a data socket
  865.     if((listen_skt=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
  866.     {
  867.         ReportWSError("socket create",WSAGetLastError());
  868.         return (INVALID_SOCKET);
  869.     }
  870.     // let system pick an unused port. we tell remote end with PORT cmd
  871.  
  872.     DoPrintf("[%u] going to listen %s port %u",listen_skt,
  873.       inet_ntoa(saCtrlAddr.sin_addr),ntohs(saCtrlAddr.sin_port));
  874.  
  875.     if(bSendPort) {
  876.       saCtrlAddr.sin_port=htons(0);
  877.       saCtrlAddr.sin_family=AF_INET;
  878.       saCtrlAddr.sin_addr.s_addr=0;
  879.     } else
  880.       // otherwise we attempt to reuse our ctrl_skt
  881.       if(setsockopt(listen_skt,SOL_SOCKET,SO_REUSEADDR,
  882.          (char *)&iFlag,sizeof(iFlag))==SOCKET_ERROR)
  883.       {
  884.         ReportWSError("setsockopt",WSAGetLastError());
  885.         closesocket(listen_skt);
  886.         return(INVALID_SOCKET);
  887.       }
  888.     //  Bind name to socket
  889.     if( bind((SOCKET)listen_skt,(LPSOCKADDR)&saCtrlAddr,
  890.              (int)sizeof(struct sockaddr))==SOCKET_ERROR)
  891.       {
  892.         ReportWSError("bind",WSAGetLastError());
  893.         closesocket(listen_skt);
  894.         return (INVALID_SOCKET);
  895.     }
  896.     // get the port name that we got for later transmission in PORT cmd
  897.     iLength=sizeof(saCtrlAddr);
  898.     if(getsockname(listen_skt,(struct sockaddr *)&saCtrlAddr,&iLength)<0)
  899.     {
  900.       ReportWSError("getsockname",WSAGetLastError());
  901.       closesocket(listen_skt);
  902.       return(INVALID_SOCKET);
  903.     }
  904.     // invoke listener
  905.     if(listen(listen_skt,1)!=0)
  906.     {
  907.       ReportWSError("listen",WSAGetLastError());
  908.        closesocket(listen_skt);
  909.       return(INVALID_SOCKET);
  910.     }
  911.  
  912. // inform remote end about our port that we created.
  913.     if(bSendPort)
  914.     {
  915.       struct sockaddr_in saTmpAddr;
  916.       int iLength;
  917.  
  918.       iLength = sizeof (saTmpAddr);
  919.       if (getsockname(ctrl_skt,(LPSOCKADDR)&saTmpAddr, &iLength)
  920.         ==SOCKET_ERROR)
  921.       {
  922.         ReportWSError("getsockname",WSAGetLastError());
  923.       }
  924.  
  925.       a = (char *)&saTmpAddr.sin_addr;
  926.       p = (char *)&saCtrlAddr.sin_port;
  927. #define  UC(b)  (((int)b)&0xff)
  928.       if((iRetCode=command(ctrl_skt,"PORT %d,%d,%d,%d,%d,%d",
  929.           UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
  930.           UC(p[0]), UC(p[1])))!=FTP_COMPLETE) {
  931.         DoPrintf("[%u] remote end didn't understand our port command.",listen_skt);
  932.         return(listen_skt);
  933.       }
  934.     }
  935.     DoPrintf("[%u] listener %s port %u",listen_skt,
  936.       inet_ntoa(saCtrlAddr.sin_addr),ntohs(saCtrlAddr.sin_port));
  937.     return(listen_skt);
  938. }
  939.  
  940. // send a file through the data socket
  941. int SendMass(SOCKET sockfd,LPSTR filename,BOOL binaryflag)
  942. {
  943.   int iNumBytes;
  944.   int  iRetCode;
  945.   int  iFileHandle;
  946.   long lBytesWritten;
  947.   time_t ttStart,ttStop,ttDiff;
  948.  
  949.  
  950.  
  951.   iRetCode=0;
  952.   // if we don't have a socket, return an error  
  953.   if(sockfd==INVALID_SOCKET || !(bConnected)) return 0;
  954.   // turn on a flag so other routines know we have a command in progress
  955.   bCmdInProgress++;
  956.   // initialize some vars
  957.   lBytesWritten=0l; iRetCode=0; 
  958.   // at the moment we are ignoring the fact that the local destination file
  959.   // may not open correctly.
  960.   if((iFileHandle=_lopen(filename,OF_READ))== -1) {
  961.     DoPrintf("failed to open file %s (%u)",filename,errno);
  962.     if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  963.   } else {
  964.     sendingfilehandle = iFileHandle;
  965.     sendingfile = TRUE;
  966.     // get the start time
  967.     ttStart=time(NULL);
  968.     // loop to send output to remote end
  969.     while((iNumBytes=_lread(iFileHandle,szMsgBuf,512))>0)
  970.     {
  971.       // this forces binary mode at the moment
  972.       iRetCode=sendstr(sockfd,szMsgBuf,iNumBytes);
  973.       // count the characters that we received
  974.       lBytesWritten+=iNumBytes;
  975.  
  976.       wsprintf(szString,"%lu",lBytesWritten);
  977.       SendMessage(hTxtLBytes,WM_SETTEXT,0,(LPARAM)szString);
  978.     }
  979.     // get the finish time
  980.     ttStop=time(NULL);
  981.     // if the output file is open, close it
  982.     _lclose(iFileHandle);
  983.     sendingfile = FALSE;
  984.     sendingfilehandle = -1;
  985.  
  986.     // show the user how we did
  987.     SendMessage(hTxtLBytes,WM_SETTEXT,0,(LPARAM)NULL);
  988.     ttDiff=ttStop-ttStart;
  989.     if(ttDiff==0l) ttDiff=1l;
  990.     // lgk fix to convert bps to k/sec if bps > 1024
  991.  
  992.     if (lBytesWritten > 1024)
  993.       {
  994.        DoPrintf("%ld bytes transmitted in %.2f seconds, (%3.2fKbytes/sec), transfer %s",
  995.        lBytesWritten,(float)ttDiff,(float)lBytesWritten/1024.000/(float)ttDiff,
  996.       (iFileHandle==-1)?"failed":"succeeded");
  997.     if (iFileHandle != -1)
  998.       {
  999.        totalbytestransfered = totalbytestransfered + lBytesWritten;
  1000.        totaltimefortransfer = totaltimefortransfer + ttDiff;
  1001.        ++totalfilestransfered;
  1002.       }
  1003.       }
  1004.  else
  1005.     {
  1006.       DoPrintf("Transmitted %ld bytes in %ld secs, %ld bps, transfer %s",
  1007.       lBytesWritten,(long)ttDiff,
  1008.       lBytesWritten*8l/(long)(ttDiff),
  1009.       (iFileHandle==-1)?"failed":"succeeded");
  1010.     if (iFileHandle != -1)
  1011.       {
  1012.        totalbytestransfered = totalbytestransfered + lBytesWritten;
  1013.        totaltimefortransfer = totaltimefortransfer + ttDiff;
  1014.        ++totalfilestransfered;
  1015.       }
  1016.    }
  1017.    iRetCode=TRUE;
  1018.     if(bBell) MessageBeep(MB_ICONASTERISK);
  1019.   }
  1020.   // turn off our command in progress flag
  1021.   bCmdInProgress--;
  1022.  
  1023.   return (iRetCode);
  1024. }
  1025.  
  1026. // read information from the data socket into a file.  
  1027. int ReadMass(SOCKET sockfd,LPSTR filename, LPSTR shortname, BOOL binaryflag)
  1028. {
  1029.   int  iNumBytes;
  1030.   int  iRetCode;
  1031.   int  iFileHandle;
  1032.   long lBytesRead;
  1033.   time_t ttStart,ttStop,ttDiff;
  1034.  
  1035.   // if we don't have a socket, return an error  
  1036.   if(sockfd==INVALID_SOCKET || !(bConnected)) return 0;
  1037.   // turn on a flag so other routines know we have a command in progress
  1038.   bCmdInProgress++;
  1039.   // make sure we don't mistakenly think we timed out
  1040.   KillTimer(hWndMain,10); bAborted=FALSE;
  1041.   // initialize some vars
  1042.   lBytesRead=0l; iRetCode=0; 
  1043.   // at the moment we are ignoring the fact that the local destination file
  1044.   // may not open correctly.
  1045.   if((iFileHandle=_lcreat(filename,0))== -1)
  1046.     {
  1047.      DoPrintf("failed to open file %s (%u)",filename,errno);
  1048.      DoPrintf("Trying shorting name %s ",shortname);
  1049.      if ((iFileHandle=_lcreat(shortname,0)) == -1)
  1050.         DoPrintf("Still failed to open file %s (%u)",shortname,errno);
  1051.      }
  1052.     // here if the name was too long than may be an ntfs partition so try the shorter name
  1053.  
  1054.     receivefilehandle = iFileHandle;
  1055.     receivingfile = TRUE;
  1056.  
  1057.   // get the start time
  1058.   ttStart=time(NULL);
  1059.   // loop to receive input from remote end
  1060.   while(!bAborted && (iNumBytes=recv(sockfd,(LPSTR)szMsgBuf,4000,0))>0)
  1061.   {
  1062.     // write what we received if the file is open
  1063.     if(iFileHandle!= -1)
  1064.       _lwrite(iFileHandle,szMsgBuf,iNumBytes);
  1065.     // count the characters that we received
  1066.     lBytesRead+=iNumBytes;
  1067.     // update screen
  1068.     wsprintf(szString,"%lu",lBytesRead);
  1069.     SendMessage(hTxtRBytes,WM_SETTEXT,0,(LPARAM)szString);
  1070.   }
  1071.   // get the finish time
  1072.   ttStop=time(NULL);
  1073.   // if the output file is open, close it
  1074.   if(iFileHandle != -1)
  1075.    {
  1076.      _lclose(iFileHandle);
  1077.     receivingfile = FALSE;
  1078.     receivefilehandle = -1;
  1079.    }
  1080.    
  1081.   // if we had a recv error, let us know about it
  1082.   if(iNumBytes==SOCKET_ERROR)
  1083.   {
  1084.     ReportWSError("recv",WSAGetLastError());
  1085.     if(lBytesRead==0l)
  1086.     {
  1087.       if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  1088.       bCmdInProgress--;
  1089.       return(FALSE);
  1090.     }
  1091.   }
  1092.   SendMessage(hTxtRBytes,WM_SETTEXT,0,(LPARAM)NULL);
  1093.  
  1094.   ttDiff=ttStop-ttStart;
  1095.   if(ttDiff==0l) ttDiff=1l;
  1096.   // show the user how we did
  1097.    if (lBytesRead > 1024)
  1098.      {
  1099.        DoPrintf("%ld bytes received in %.2f seconds, (%3.2fKbytes/sec), transfer %s",
  1100.        lBytesRead,(float)ttDiff,(float)lBytesRead/1024.000/(float)ttDiff,
  1101.      (iFileHandle==-1 || bAborted)?"failed":"succeeded");
  1102.  
  1103.     if (iFileHandle != -1)
  1104.       {
  1105.        totalbytestransfered = totalbytestransfered + lBytesRead;
  1106.        totaltimefortransfer = totaltimefortransfer + ttDiff;
  1107.        ++totalfilestransfered;
  1108.       }
  1109.  
  1110.         // lgk set global variable so that we know it succeeded so we will 
  1111.      // close window
  1112.      globalsucceed = TRUE;
  1113.      if (iFileHandle == -1)
  1114.        globalsucceed = FALSE;
  1115.      }
  1116.  
  1117.    else 
  1118.        {
  1119.   DoPrintf("Received %ld bytes in %ld secs, %ld bps, transfer %s",
  1120.     lBytesRead,(long)ttDiff,
  1121.     lBytesRead*8l/(long)ttDiff,
  1122.     (iFileHandle==-1 || bAborted)?"failed":"succeeded");
  1123.  
  1124.  
  1125.     if (iFileHandle != -1)
  1126.       {
  1127.        totalbytestransfered = totalbytestransfered + lBytesRead;
  1128.        totaltimefortransfer = totaltimefortransfer + ttDiff;
  1129.        ++totalfilestransfered;
  1130.       }
  1131.         }
  1132.  
  1133.        // lgk set global variable so that we know it succeeded so we will 
  1134.      // close window
  1135.      globalsucceed = TRUE;
  1136.      if (iFileHandle == -1)
  1137.        globalsucceed = FALSE;
  1138.  
  1139.    // DoPrintf("Bell = %d \n",bBell);
  1140.   if(bBell > 0) MessageBeep(MB_ICONASTERISK);
  1141.   // turn off our command in progress flag
  1142.   bCmdInProgress--;
  1143.  
  1144.   return (TRUE);
  1145. }
  1146.  
  1147.