home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 15 / CD_ASCQ_15_070894.iso / vrac / wsftp2.zip / WS_CON.C < prev    next >
C/C++ Source or Header  |  1994-06-03  |  30KB  |  944 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.  
  40.  // lgk timer messages do not work for use because we have mult. threads
  41.  // so create a timer proc.
  42.  
  43.  extern BOOLEAN check_busy();
  44.  extern void set_busy();
  45.  
  46.  VOID CALLBACK mytimerproc(wind,msg,idevent,systime)
  47.  HWND wind;
  48.  UINT msg;
  49.  UINT idevent;
  50.  DWORD systime;
  51.  {
  52.        DoPrintf("Timer has Expired\n");
  53.       if(idevent ==10)
  54.         {
  55.         KillTimer(wind,10);
  56.         if(WSAIsBlocking())
  57.          {
  58.             // lgk if we are blocking in another thread here we need to kill
  59.             // it also
  60.            if (check_busy())
  61.             {
  62.              DoPrintf("Timer cancelled blocking call\n");    
  63.              bAborted=TRUE;
  64.              WSACancelBlockingCall();
  65.              TerminateThread(threadhandle,1);
  66.              set_busy(FALSE);
  67.             }
  68.          else
  69.          {
  70.           DoPrintf("Timer cancelled blocking call\n");    
  71.           bAborted=TRUE;
  72.           WSACancelBlockingCall();
  73.          }
  74.         }
  75.        }
  76. }
  77.  
  78. /*
  79. // send a message on the control socket, read and display the resulting
  80. // message and return the result value
  81. */
  82. int getreply(SOCKET ctrl_skt,LPSTR cmdstring)
  83. {
  84.   int iRetCode=0;
  85.  
  86.   iCode=0;
  87.   if(strncmp(cmdstring,"PASS ",5)==0)
  88.     DoAddLine("PASS xxxxxx");
  89.   else
  90.     DoAddLine(cmdstring);
  91.   if(ctrl_skt==INVALID_SOCKET) {
  92.     DoAddLine("Not connected");
  93.   } else {
  94.     if(SendPacket(ctrl_skt,cmdstring)!=-1)
  95.       iRetCode=ReadDisplayLine(ctrl_skt);
  96.   }
  97.   return(iRetCode);  // 0 - 5
  98. }
  99.  
  100. int command(SOCKET ctrl_skt, char *fmt,...)
  101. {
  102.    va_list args;
  103.    char szBuf[90];
  104.  //  int  iRetCode;
  105.  
  106.    va_start(args,fmt);
  107.    vsprintf(szBuf,fmt,args);
  108.    va_end(args);
  109.    return(getreply(ctrl_skt,szBuf));
  110. }
  111.  
  112. int qcommand(SOCKET ctrl_skt, char *fmt,...)
  113. {
  114.    va_list args;
  115.    char szBuf[90];
  116.  //  int  iRetCode;
  117.  
  118.    va_start(args,fmt);
  119.    vsprintf(szBuf,fmt,args);
  120.    va_end(args);
  121.    command(ctrl_skt,szBuf);
  122.    return iCode ;
  123. }
  124.  
  125. // return a string pointer to ON or OFF based on the flag
  126. char *onoff(BOOL flag)
  127. {
  128.   if(flag) return("ON"); else return("OFF");
  129. }
  130.  
  131. // process CWD
  132. int DoCWD(SOCKET ctrl_skt,LPSTR path)
  133. {
  134.   if(command(ctrl_skt,"CWD %s",path)==FTP_ERROR && iCode==500) {
  135.     command(ctrl_skt,"XCWD %s",path);
  136.   }
  137.   return(iCode/100);
  138. }
  139.  
  140. // proces PWD
  141. int DoPWD(SOCKET ctrl_skt)
  142. {
  143.   if(command(ctrl_skt,"PWD")==FTP_ERROR && iCode==500) {
  144.     command(ctrl_skt,"XPWD");
  145.   }
  146.   return(iCode/100);
  147. }
  148.  
  149. // process MKD
  150. int DoMKD(SOCKET ctrl_skt,LPSTR pathname)
  151. {
  152.   if(command(ctrl_skt,"MKD %s",pathname)==FTP_ERROR && iCode==500) {
  153.     command(ctrl_skt,"XMKD %s",pathname);
  154.   }
  155.   return(iCode/100);
  156. }
  157.  
  158. // process RMD
  159. int DoRMD(SOCKET ctrl_skt,LPSTR pathname)
  160. {
  161.   if(command(ctrl_skt,"RMD %s",pathname)==FTP_ERROR && iCode==500)
  162.     command(ctrl_skt,"XRMD %s",pathname);
  163.   return(iCode/100);
  164. }
  165.  
  166. // process DELE
  167. int DoDELE(SOCKET ctrl_skt,LPSTR pathname)
  168. {
  169.   command(ctrl_skt,"DELE %s",pathname);
  170.   return(iCode/100);
  171. }
  172.  
  173. // process user command
  174. int DoQUOTE(SOCKET ctrl_skt,LPSTR string)
  175. {
  176.   if(strncmp(string,"LIST",4)==0 ||
  177.      strncmp(string,"NLST",4)==0)
  178.     DoDirList(ctrl_skt,string);
  179.   else
  180.     command(ctrl_skt,string);
  181.   return(iCode/100);
  182. }
  183.  
  184. // process chmod
  185. int DoCHMOD(SOCKET ctrl_skt,LPSTR modes,LPSTR filename)
  186. {
  187.   return(command(ctrl_skt,"SITE CHMOD %s %s",modes,filename));
  188. }
  189.  
  190. extern BOOL bHELP;
  191.  
  192. // initial connection
  193. SOCKET DoConnect(LPSTR ftp_host)
  194. {
  195.   int iLength,iRetCode;
  196.   int iFlag=1;
  197.   char host[80] ;
  198.   SOCKET ctrl_skt;
  199.  
  200.   if(bConnected) {
  201.     DoAddLine("Already connected!");
  202.     return(INVALID_SOCKET);
  203.   }
  204.   // let other routines know that we are busy
  205.   bCmdInProgress++;
  206.  
  207. // DoPrintf("host name in doconnect is %s\n",ftp_host);
  208.   
  209.   bHELP=FALSE;
  210.  
  211.   if(use_gateway)
  212.     strcpy(host, szGateHost) ;
  213.   else
  214.     strcpy(host, ftp_host) ;
  215.  
  216.   // create a connected socket
  217.   if((ctrl_skt=connectTCP(host,"ftp"))==INVALID_SOCKET) {
  218.     //DoAddLine("connection failed");
  219.     DoPrintf("Connection to %s failed",host) ;
  220.     bCmdInProgress--;
  221.     return(INVALID_SOCKET);
  222.   }
  223.   // get information about local end of the connection
  224.   iLength = sizeof (saCtrlAddr);
  225.   if (getsockname(ctrl_skt,(struct sockaddr *)&saCtrlAddr, &iLength)
  226.       ==SOCKET_ERROR)
  227.   {
  228.     ReportWSError("getsockname",WSAGetLastError());
  229.     bCmdInProgress--;
  230.     DoClose(ctrl_skt);
  231.     return(INVALID_SOCKET);
  232.   }
  233.   // show remote end address
  234.   DoPrintf("[%u] from %s port %u",ctrl_skt,
  235.            inet_ntoa(saCtrlAddr.sin_addr),
  236.            ntohs(saCtrlAddr.sin_port));
  237.   // get initial message from remote end
  238.   // lgk need to set the global control_socket to ctrl_skt here since
  239.   // it will be returned but abort does not work unless it is set here
  240.   ctrl_socket = ctrl_skt;
  241.   
  242.   while((iRetCode=ReadDisplayLine(ctrl_skt))==FTP_PRELIM && !bAborted)  // 93.12.04
  243.     if(nHostType==HOST_TYPE_AUTO) {
  244.       if(strstr(szMsgBuf,"(EXOS")!=NULL)
  245.         nHostType=HOST_TYPE_U5000;
  246.     }
  247.   // if it succeeded
  248.   if(iRetCode==FTP_COMPLETE) {
  249.     if(nHostType==HOST_TYPE_AUTO) {
  250.       if(strstr(szMsgBuf,"(EXOS")!=NULL)
  251.         nHostType=HOST_TYPE_U5000;
  252.     }
  253.     if (setsockopt(ctrl_skt, SOL_SOCKET, SO_OOBINLINE,
  254.         (LPSTR)&iFlag, sizeof(iFlag))==SOCKET_ERROR)
  255.     {
  256.       ReportWSError("setsockopt",WSAGetLastError());
  257.     }
  258.     // have to reset this so "command" will work
  259.     bCmdInProgress--;
  260.  
  261.     if(use_gateway)
  262.       { // send our userid
  263.       if((iRetCode=command(ctrl_skt,"USER %s",szGateUserID))==FTP_CONTINUE)
  264.       { // if the remote system requires a password, send it.
  265.         iRetCode=command(ctrl_skt,"PASS %s",szGatePassWord);
  266.       }
  267.       if(iRetCode!=FTP_COMPLETE)
  268.       { // if we failed to successfully log on
  269.         DoAddLine("Gateway logon failure, so quitting");
  270.         DoClose((SOCKET)ctrl_skt);
  271.         return(INVALID_SOCKET);
  272.       }
  273.  
  274.       if((iRetCode=qcommand(ctrl_skt,"site %s",ftp_host))==FTP_ERROR)
  275.       {
  276.         DoAddLine("Connect to final destination failed, so quitting");
  277.         DoClose((SOCKET)ctrl_skt);
  278.         bConnected=0;
  279.         return(INVALID_SOCKET);
  280.       }
  281.       bConnected=1;
  282.      // lgk now that we are connected enable the close button and disable the
  283.      // open button
  284.      EnableWindow(hBtnClose,TRUE);
  285.      EnableWindow(hBtnConnect,FALSE);
  286.  
  287.     } // end of gateway connect
  288.  
  289.     // send our userid to the ftp_host
  290.     if((iRetCode=command(ctrl_skt,"USER %s",szUserID))==FTP_CONTINUE) // || 1)
  291.     {
  292.       while(szPassWord[0]==0) {
  293.         StdInputPassword(szPassWord,"Need a password:");
  294.       }
  295.       // if the remote system requires a password, send it.
  296.       if((iRetCode=command(ctrl_skt,"PASS %s",szPassWord))==FTP_CONTINUE)
  297.       {
  298.         // if the remote system requires an account, send it.
  299.         StdInput(NULL,"Need an account:");
  300.         iRetCode=command(ctrl_skt,"ACCT %s",szDlgEdit);
  301.       }
  302.     }
  303.     // if we are successfully logged on,.....
  304.     if(iRetCode!=FTP_COMPLETE) // || 0)
  305.     {
  306.       DoAddLine("logon failure, so quitting");
  307.       DoClose((SOCKET)ctrl_skt);
  308.       bConnected=0;
  309.       EnableWindow(hBtnClose,FALSE);
  310.       EnableWindow(hBtnConnect,TRUE);
  311.      return(INVALID_SOCKET);
  312.     }
  313.     bConnected=1;
  314.     EnableWindow(hBtnClose,TRUE);
  315.     EnableWindow(hBtnConnect,FALSE);
  316.  
  317.   } else {
  318.     DoPrintf("unk open msg \"%s\" %u",szMsgBuf,iCode);
  319.     // allow other processes to work
  320.     bCmdInProgress--;
  321.     DoClose((SOCKET)ctrl_skt);
  322.     bConnected = 0;
  323.     EnableWindow(hBtnClose,TRUE);
  324.     EnableWindow(hBtnConnect,FALSE);
  325.  
  326.     return(INVALID_SOCKET);
  327.   }
  328.   wsprintf(szString,"WS_FTP32 %s",szRemoteHost);
  329.   SetWindowText(hWndMain,szString);
  330.   return (ctrl_skt);
  331. }
  332.  
  333. int DoDirList(SOCKET ctrl_skt,LPSTR szCMD)
  334. {
  335.   int nRC,nBell;
  336.   nBell=bBell; bBell=0;
  337.   nRC=RetrieveFile(ctrl_skt,szCMD,szTmpFile,szTmpFile,TYPE_A);
  338.   bBell=nBell;
  339.   return(nRC);
  340. }
  341.  
  342. int SendFile(SOCKET ctrl_skt,LPSTR szCMD,LPSTR localfile,char stype)
  343. {
  344.   int iRetCode;
  345.   int iLength;
  346.  
  347.   iCode=0;
  348.   // if we don't have a valid control socket, can't do anything
  349.   if(ctrl_skt==INVALID_SOCKET) {
  350.     DoAddLine("no ctrl_skt, ignored");
  351.     return(0);
  352.   }
  353.   // if we are doing something, don't try to do this
  354.   if(bCmdInProgress) {
  355.     DoAddLine("command in process, ignored");
  356.     return(0);
  357.   }
  358.   // if the requested type is not the same as the default type
  359.   if(cType!=stype) {
  360.     if(stype==TYPE_L)
  361.       command(ctrl_skt,"TYPE L 8");
  362.     else
  363.       command(ctrl_skt,"TYPE %c",stype);
  364.     cType=stype;
  365.   }
  366.   // create a listener socket, if it is successful
  367.   if((listen_socket=GetFTPListenSocket(ctrl_skt))!=INVALID_SOCKET) {
  368.     // send command to see the result of this all
  369.     iRetCode=command((SOCKET)ctrl_skt,szCMD);
  370.     // read the control channel (should return 1xx if it worked)
  371.     if(iRetCode==FTP_PRELIM) {
  372.       // wait for connection back to us on the listen socket
  373.       SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  374.       // get our data connection
  375.       iLength=sizeof(saSockAddr1);
  376.       data_socket=accept(listen_socket,(struct sockaddr far *)&saSockAddr1,
  377.                          (int far *)&iLength);
  378.       // turn off the timeout timer
  379.       KillTimer(hWndMain,10);
  380.       // if it failed, we have to quit this
  381.       if(data_socket==INVALID_SOCKET) {
  382.         ReportWSError("accept",WSAGetLastError());
  383.         listen_socket=DoClose(listen_socket);
  384.         iRetCode=0;
  385.       } else {
  386.         // we don't need the listener socket anymore
  387.         listen_socket=DoClose(listen_socket);
  388.         // inform user of the connection
  389.         DoPrintf("[%u] accept from %s port %u", data_socket,
  390.           inet_ntoa(saSockAddr1.sin_addr),ntohs(saSockAddr1.sin_port));
  391.         // copy the file
  392.         iRetCode=SendMass(data_socket,localfile,stype==TYPE_I);
  393.         // close the socket
  394.         data_socket=DoClose(data_socket);
  395.         // read the close control message (should return 2xx)
  396.         iRetCode=ReadDisplayLine(ctrl_skt);
  397.       }
  398.     } else {
  399.       listen_socket=DoClose(listen_socket);
  400.       iRetCode=0;
  401.       if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  402.     }
  403.   } else {
  404.     listen_socket=DoClose(listen_socket);
  405.     iRetCode=0;
  406.     if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  407.   }
  408.   return(iRetCode);
  409. }
  410.  
  411. int RetrieveFile(SOCKET ctrl_skt,LPSTR szCMD,LPSTR localfile, LPSTR shortname,char rtype)
  412. {
  413.   int iRetCode;
  414.   int iLength;
  415.  
  416.   iCode=0;
  417.   iMultiLine = 0;
  418.   // if we don't have a valid control socket, can't do anything
  419.   if(ctrl_skt==INVALID_SOCKET) {
  420.     DoAddLine("no ctrl_skt, ignored");
  421.     return(0);
  422.   }
  423.   // if we are doing something, don't try to do this
  424.   if(bCmdInProgress) {
  425.     DoAddLine("command in process, ignored");
  426.     return(0);
  427.   }
  428.   // if the requested type is not the same as the default type
  429.   if(cType!=rtype) {
  430.     if(rtype==TYPE_L)
  431.       command(ctrl_skt,"TYPE L 8");
  432.     else
  433.       command(ctrl_skt,"TYPE %c",rtype);
  434.     cType=rtype;
  435.   }
  436.   // create a listener socket, if it is successful
  437.   if((listen_socket=GetFTPListenSocket(ctrl_skt))!=INVALID_SOCKET)
  438.      {
  439.     // send command to see the result of this all
  440.     iRetCode=command((SOCKET)ctrl_skt,szCMD);
  441.     // read the control channel (should return 1xx if it worked)
  442.     if(iRetCode==FTP_PRELIM) {
  443.       // wait for connection back to us on the listen socket
  444.       SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  445.       // get our data connection
  446.       iLength=sizeof(saSockAddr1);
  447.       data_socket=accept(listen_socket,(struct sockaddr far *)&saSockAddr1,
  448.                          (int far *)&iLength);
  449.     // lgk check for error case here
  450.     if (data_socket == INVALID_SOCKET)
  451.       {
  452.          ReportWSError("accept for retrieve",WSAGetLastError());
  453.          data_socket=DoClose(data_socket);
  454.          return 0;
  455.       }
  456.  
  457.       // turn off the timeout timer
  458.       KillTimer(hWndMain,10);
  459.       // if it failed, we have to quit this
  460.       if(data_socket==INVALID_SOCKET) {
  461.         ReportWSError("accept",WSAGetLastError());
  462.         listen_socket=DoClose(listen_socket);
  463.         iRetCode=0;
  464.       } else {
  465.         // we don't need the listener socket anymore
  466.         listen_socket=DoClose(listen_socket);
  467.         // inform user of the connection
  468.         DoPrintf("[%u] accept from %s port %u", data_socket,
  469.           inet_ntoa(saSockAddr1.sin_addr),ntohs(saSockAddr1.sin_port));
  470.         // copy the file
  471.         iRetCode=ReadMass(data_socket,localfile,shortname,rtype==TYPE_I);
  472.         // shut the data socket down
  473.         if(shutdown(data_socket,2)!=0)
  474.           ReportWSError("shutdown",WSAGetLastError());
  475.         // close the data socket
  476.         data_socket=DoClose(data_socket);
  477.         // read the close control message (should return 2xx)
  478.         iRetCode=ReadDisplayLine(ctrl_skt);
  479.       }
  480.     } else {
  481.       listen_socket=DoClose(listen_socket);
  482.       iRetCode=0;
  483.       if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  484.     }
  485.  
  486.   } else {
  487.     listen_socket=DoClose(listen_socket);
  488.     iRetCode=0;
  489.     if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  490.   }
  491.   return(iRetCode);
  492. }
  493.  
  494. // user close routine
  495. SOCKET DoClose(SOCKET sockfd)
  496. {
  497. LINGER ntlinger;
  498.  
  499.   if(sockfd!=INVALID_SOCKET) {
  500.     if(WSAIsBlocking())
  501.     {
  502.       DoPrintf("[%u] Cancelled blocking call",sockfd);
  503.       WSACancelBlockingCall();
  504.       bAborted=TRUE;
  505.     }
  506.  /* dont report error here since shutdown does not work on non data sockets
  507.     if(shutdown(sockfd,2)==SOCKET_ERROR)
  508.       ReportWSError("shutdown",WSAGetLastError());
  509.   */
  510. //  93.12.04 - so Lanera Winsock Works
  511.    ntlinger.l_onoff  = TRUE;
  512.     ntlinger.l_linger = 20;
  513.     setsockopt(sockfd,SOL_SOCKET,SO_LINGER,
  514.                 (LPSTR)&ntlinger,sizeof(ntlinger) );
  515.  
  516.     if(closesocket(sockfd)==SOCKET_ERROR)
  517.       ReportWSError("closesocket",WSAGetLastError());
  518.     else {
  519.             DoPrintf("[%u] Socket closed.",sockfd);
  520.             sockfd=INVALID_SOCKET;
  521.     }
  522.   }
  523.  
  524.   if(sockfd!=INVALID_SOCKET)
  525.     DoPrintf("%u Failed to close socket.",sockfd);
  526.  
  527.   return(sockfd);
  528. }
  529.  
  530. int SendPacket(SOCKET sockfd,LPSTR msg)
  531. {
  532.   int i;
  533.  
  534.   if(sockfd==INVALID_SOCKET) return(-1);
  535.   if(bCmdInProgress) {
  536.     DoAddLine("command in progress, ignored");
  537.     return (-1);
  538.   }
  539.   bCmdInProgress++;
  540.   i=strlen(msg);
  541.   strcpy(szSendPkt,msg);
  542.   // append a CRLF to the end of outgoing messages
  543.   szSendPkt[i++]='\r';
  544.   szSendPkt[i++]='\n';
  545.   szSendPkt[i]=0;  
  546.   i=sendstr(sockfd,szSendPkt,i);
  547.   bCmdInProgress--;
  548.   return (i);
  549. }
  550.  
  551. // read a reply (may be multi line) and display in debug window
  552. int ReadDisplayLine(SOCKET sockfd)
  553. {
  554.   int iRetCode;
  555.   int iContinue;
  556.  // char *s;
  557.  // char c;
  558.  
  559.   // can't do anything if we don't have a socket
  560.   if(sockfd==INVALID_SOCKET) return(0);
  561.   // let other routine know that we are doing something right now.
  562.   bCmdInProgress++;
  563.   // count the lines in the response
  564.   iMultiLine++;
  565.   // initialize some variables
  566.   iContinue=0;
  567.   // go read the line
  568.   iRetCode=ReadLine(sockfd);
  569.   // if it wasn't a valid value or the 4th char was a hyphen
  570.   // lgk check for error here and return if so
  571.   if (iRetCode == SOCKET_ERROR)
  572.     {
  573.      return  iRetCode;
  574.     }
  575.  
  576.   if(iRetCode<100 || iRetCode>599 || szMsgBuf[3]=='-')
  577.     // then it is a continuation line
  578.     iContinue=1;
  579.   // send the line we read to our user/debug window
  580.   DoAddLine((LPSTR)&szMsgBuf[0]);
  581.   //  DoPrintf("iRetCode=%u,  =%u",iRetCode,iContinue);
  582.   // if the timer killed it
  583.   if(bAborted) { iCode=iRetCode=421; iContinue=0; }
  584.   // we only want to set the real return code in certain situations
  585.   if((iMultiLine==1 || iCode==0) && iRetCode>99 && iRetCode<600)
  586.     iCode=iRetCode;
  587.   // handle continuation lines
  588.   if(iContinue==1 || (iCode>0 && iMultiLine>1 && iRetCode!=iCode))
  589.     ReadDisplayLine(sockfd);
  590.   // count back down our multiline reponses
  591.   iMultiLine--;
  592.   // allow other processes to run
  593.   bCmdInProgress--;
  594.   // return only the first char of return code
  595.   if(iCode>99 && iCode<600)
  596.     return (iCode/100);
  597.   else return 0;
  598. }
  599.  
  600. // read a reply line back in from the sockfd and return the
  601. // value at the beginning of the first line.
  602. int ReadLine(SOCKET sockfd)
  603. {
  604.   LPSTR szBuf;
  605.   int nIndex;
  606.   int iNumBytes,iN1,iN2; //.iN3;
  607.   int iBytesRead;
  608.   int iRetCode;
  609.   int i;
  610.  // char *s;
  611.   char c;
  612.  
  613.   // can't do anything if we don't have a socket
  614.   if(sockfd==INVALID_SOCKET) return(0);
  615.   // let other routines know that we are doing something right now.
  616.   bCmdInProgress++;
  617.   // make sure we don't mistakenly think we timed out
  618.   KillTimer(hWndMain,10); bAborted=FALSE;
  619.   // zero our receive buffer
  620.   memset(szMsgBuf,0,4096);
  621.   // initialize some variables
  622.   szBuf=szMsgBuf; iBytesRead=0; iRetCode=0;
  623.   // set our timeout
  624.   SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  625.   // this routine is a little better as it read 80 characters at a time
  626.   // (if it works:-)  Here we PEEK at what is available, find the LF etc...
  627.  
  628.  // lgk here we have a bug and it puts the system in an endless loop
  629.  // we don't check for a socket error but one happens fix this
  630.  iNumBytes=recv(sockfd,(LPSTR)szBuf,82,MSG_PEEK);
  631.  if (iNumBytes == SOCKET_ERROR)
  632.   {
  633.    ReportWSError("socket recv (peek)",WSAGetLastError());
  634.    return (SOCKET_ERROR);
  635.   }
  636.  
  637.   while(iBytesRead<4000 && (iNumBytes > 0))
  638.   {
  639.     // Trumpet WinSock Alpha 15 always returns the len (82) from a recv
  640.     // with MSG_PEEK.  I suppose this is an error??? The spec doesn't say
  641.     // that MSG_PEEK returns something different than normal.
  642.     KillTimer(hWndMain,10);
  643.     iN1=iNumBytes;
  644.     // must terminate the string so strchr doesn't go wild.
  645.     szBuf[iNumBytes]=0;
  646.     // find a LF in the input if it exists
  647.     //
  648.     for(nIndex=0;nIndex<iNumBytes;nIndex++)
  649.       if(szBuf[nIndex]==0 || szBuf[nIndex]==0x0a) {
  650.         iNumBytes=nIndex+1;
  651.         break;
  652.       }
  653.     // have to treat the UNISYS 5000 (EXOS driver) special.  It sends a
  654.     // line with a CR at end and no LF and then follows it up with a
  655.     // separate packet that has a CR/LF.  Usually this second packet is
  656.     // not there when we peek but is when we read (answers my question
  657.     // about the second receive containing new data!!... jaj 931024)
  658.     if(iNumBytes>80 && nHostType==HOST_TYPE_U5000)
  659.       for(nIndex=0;nIndex<iNumBytes;nIndex++)
  660.         if(szBuf[nIndex]==0x0d) {
  661.           iNumBytes=nIndex+2;
  662.           break;
  663.         }
  664.     iN2=iNumBytes;
  665.     // otherwise read up to the full length of what the first recv saw.
  666.     // Wonder what happens here if the second receive actually returns more
  667.     // characters than the first receive and there was a LF in the extra data?   
  668.     iNumBytes=recv(sockfd,(LPSTR)szBuf,iNumBytes,0);
  669.     // again, terminate the string
  670.     szBuf[iNumBytes]=0;
  671.     DoPrintf("[%u] readline %u - %u - %u %s",sockfd,iN1,iN2,iNumBytes,szBuf);
  672.     // bump the receive buffer pointer
  673.     szBuf+=iNumBytes;
  674.     // count the bytes that we have read so far
  675.     iBytesRead+=iNumBytes;
  676.     // if the last character read was a LF, then stop.
  677.     if(*(szBuf-1)==0x0a)
  678.       break;         // '\n') break;
  679.     // otherwise reset the timer and go read more characters
  680.     SetTimer(hWndMain,10,uiTimeOut*1000,(TIMERPROC)mytimerproc);
  681.   }
  682.   // if we are here, we have a line or an error or there was nothing to read
  683.   KillTimer(hWndMain,10);
  684.   // in any case terminate what we have
  685.   *szBuf=0;
  686.   // find the retcode at the beginning of the line
  687.   c=szMsgBuf[3]; szMsgBuf[3]=0; iRetCode=atoi(szMsgBuf); szMsgBuf[3]=c;
  688.   // if the timer killed it
  689.   if(bAborted) iRetCode=421;
  690.   // strip trailing blanks, CR's and LF's
  691.   while((i=strlen(szMsgBuf))>2 &&
  692.         (szMsgBuf[i-1]==0x0a || szMsgBuf[i-1]==0x0d || szMsgBuf[i-1]==' '))
  693.     szMsgBuf[i-1]=0;
  694.   // unmark our progress
  695.   bCmdInProgress--;
  696.  
  697.   return(iRetCode);
  698. }
  699.  
  700. // based on WINTEL (ftp.c) and BSD (ftp.c)
  701. SOCKET GetFTPListenSocket(SOCKET ctrl_skt)
  702. {
  703.     SOCKET listen_skt;
  704.     int iLength;
  705.     int iRetCode;
  706.     char *a,*p;
  707.     int iFlag=1;
  708.  
  709.     // create a data socket
  710.     if((listen_skt=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
  711.     {
  712.         ReportWSError("socket create",WSAGetLastError());
  713.         return (INVALID_SOCKET);
  714.     }
  715.     // let system pick an unused port. we tell remote end with PORT cmd
  716.     DoPrintf("[%u] going to listen %s port %u",listen_skt,
  717.       inet_ntoa(saCtrlAddr.sin_addr),ntohs(saCtrlAddr.sin_port));
  718.  
  719.     if(bSendPort) {
  720.       saCtrlAddr.sin_port=htons(0);
  721.       saCtrlAddr.sin_family=AF_INET;
  722.       saCtrlAddr.sin_addr.s_addr=0;
  723.     } else
  724.       // otherwise we attempt to reuse our ctrl_skt
  725.       if(setsockopt(listen_skt,SOL_SOCKET,SO_REUSEADDR,
  726.          (char *)&iFlag,sizeof(iFlag))==SOCKET_ERROR)
  727.       {
  728.         ReportWSError("setsockopt",WSAGetLastError());
  729.         closesocket(listen_skt);
  730.         return(INVALID_SOCKET);
  731.       }
  732.     //  Bind name to socket
  733.     if( bind((SOCKET)listen_skt,(LPSOCKADDR)&saCtrlAddr,
  734.              (int)sizeof(struct sockaddr))==SOCKET_ERROR)
  735.       {
  736.         ReportWSError("bind",WSAGetLastError());
  737.         closesocket(listen_skt);
  738.         return (INVALID_SOCKET);
  739.     }
  740.     // get the port name that we got for later transmission in PORT cmd
  741.     iLength=sizeof(saCtrlAddr);
  742.     if(getsockname(listen_skt,(struct sockaddr *)&saCtrlAddr,&iLength)<0)
  743.     {
  744.       ReportWSError("getsockname",WSAGetLastError());
  745.       closesocket(listen_skt);
  746.       return(INVALID_SOCKET);
  747.     }
  748.     // invoke listener
  749.     if(listen(listen_skt,1)!=0)
  750.     {
  751.       ReportWSError("listen",WSAGetLastError());
  752.        closesocket(listen_skt);
  753.       return(INVALID_SOCKET);
  754.     }
  755.  
  756. // inform remote end about our port that we created.
  757.     if(bSendPort)
  758.     {
  759.       struct sockaddr_in saTmpAddr;
  760.       int iLength;
  761.  
  762.       iLength = sizeof (saTmpAddr);
  763.       if (getsockname(ctrl_skt,(LPSOCKADDR)&saTmpAddr, &iLength)
  764.         ==SOCKET_ERROR)
  765.       {
  766.         ReportWSError("getsockname",WSAGetLastError());
  767.       }
  768.  
  769.       a = (char *)&saTmpAddr.sin_addr;
  770.       p = (char *)&saCtrlAddr.sin_port;
  771. #define  UC(b)  (((int)b)&0xff)
  772.       if((iRetCode=command(ctrl_skt,"PORT %d,%d,%d,%d,%d,%d",
  773.           UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
  774.           UC(p[0]), UC(p[1])))!=FTP_COMPLETE) {
  775.         DoPrintf("[%u] remote end didn't understand our port command.",listen_skt);
  776.         return(listen_skt);
  777.       }
  778.     }
  779.     DoPrintf("[%u] listener %s port %u",listen_skt,
  780.       inet_ntoa(saCtrlAddr.sin_addr),ntohs(saCtrlAddr.sin_port));
  781.     return(listen_skt);
  782. }
  783.  
  784. // send a file through the data socket
  785. int SendMass(SOCKET sockfd,LPSTR filename,BOOL binaryflag)
  786. {
  787.   int iNumBytes;
  788.   int  iRetCode;
  789.   int  iFileHandle;
  790.   long lBytesWritten;
  791.   time_t ttStart,ttStop,ttDiff;
  792.  
  793.   iRetCode=0;
  794.   // if we don't have a socket, return an error  
  795.   if(sockfd==INVALID_SOCKET || !(bConnected)) return 0;
  796.   // turn on a flag so other routines know we have a command in progress
  797.   bCmdInProgress++;
  798.   // initialize some vars
  799.   lBytesWritten=0l; iRetCode=0; 
  800.   // at the moment we are ignoring the fact that the local destination file
  801.   // may not open correctly.
  802.   if((iFileHandle=_lopen(filename,OF_READ))== -1) {
  803.     DoPrintf("failed to open file %s (%u)",filename,errno);
  804.     if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  805.   } else {
  806.     // get the start time
  807.     ttStart=time(NULL);
  808.     // loop to send output to remote end
  809.     while((iNumBytes=_lread(iFileHandle,szMsgBuf,512))>0)
  810.     {
  811.       // this forces binary mode at the moment
  812.       iRetCode=sendstr(sockfd,szMsgBuf,iNumBytes);
  813.       // count the characters that we received
  814.       lBytesWritten+=iNumBytes;
  815.  
  816.       wsprintf(szString,"%lu",lBytesWritten);
  817.       SendMessage(hTxtLBytes,WM_SETTEXT,0,(LPARAM)szString);
  818.     }
  819.     // get the finish time
  820.     ttStop=time(NULL);
  821.     // if the output file is open, close it
  822.     _lclose(iFileHandle);
  823.     // show the user how we did
  824.     SendMessage(hTxtLBytes,WM_SETTEXT,0,(LPARAM)NULL);
  825.     ttDiff=ttStop-ttStart;
  826.     if(ttDiff==0l) ttDiff=1l;
  827.     // lgk fix to convert bps to k/sec if bps > 1024
  828.  
  829.     if (lBytesWritten > 1024)
  830.       DoPrintf("%ld bytes transmitted in %.2f seconds, (%3.2fKbytes/sec), transfer %s",
  831.        lBytesWritten,(float)ttDiff,(float)lBytesWritten/1024.000/(float)ttDiff,
  832.       (iFileHandle==-1)?"failed":"succeeded");
  833.  
  834.        
  835.  else
  836.     DoPrintf("Transmitted %ld bytes in %ld secs, %ld bps, transfer %s",
  837.       lBytesWritten,(long)ttDiff,
  838.       lBytesWritten*8l/(long)(ttDiff),
  839.       (iFileHandle==-1)?"failed":"succeeded");
  840.  
  841.    iRetCode=TRUE;
  842.     if(bBell) MessageBeep(MB_ICONASTERISK);
  843.   }
  844.   // turn off our command in progress flag
  845.   bCmdInProgress--;
  846.  
  847.   return (iRetCode);
  848. }
  849.  
  850. // read information from the data socket into a file.  
  851. int ReadMass(SOCKET sockfd,LPSTR filename, LPSTR shortname, BOOL binaryflag)
  852. {
  853.   int  iNumBytes;
  854.   int  iRetCode;
  855.   int  iFileHandle;
  856.   long lBytesRead;
  857.   time_t ttStart,ttStop,ttDiff;
  858.  
  859.   // if we don't have a socket, return an error  
  860.   if(sockfd==INVALID_SOCKET || !(bConnected)) return 0;
  861.   // turn on a flag so other routines know we have a command in progress
  862.   bCmdInProgress++;
  863.   // make sure we don't mistakenly think we timed out
  864.   KillTimer(hWndMain,10); bAborted=FALSE;
  865.   // initialize some vars
  866.   lBytesRead=0l; iRetCode=0; 
  867.   // at the moment we are ignoring the fact that the local destination file
  868.   // may not open correctly.
  869.   if((iFileHandle=_lcreat(filename,0))== -1)
  870.     {
  871.      DoPrintf("failed to open file %s (%u)",filename,errno);
  872.      DoPrintf("Trying shorting name %s ",shortname);
  873.      if ((iFileHandle=_lcreat(shortname,0)) == -1)
  874.         DoPrintf("Still failed to open file %s (%u)",shortname,errno);
  875.      }
  876.     // here if the name was too long than may be an ntfs partition so try the shorter name
  877.  
  878.   // get the start time
  879.   ttStart=time(NULL);
  880.   // loop to receive input from remote end
  881.   while(!bAborted && (iNumBytes=recv(sockfd,(LPSTR)szMsgBuf,4000,0))>0)
  882.   {
  883.     // write what we received if the file is open
  884.     if(iFileHandle!= -1)
  885.       _lwrite(iFileHandle,szMsgBuf,iNumBytes);
  886.     // count the characters that we received
  887.     lBytesRead+=iNumBytes;
  888.     // update screen
  889.     wsprintf(szString,"%lu",lBytesRead);
  890.     SendMessage(hTxtRBytes,WM_SETTEXT,0,(LPARAM)szString);
  891.   }
  892.   // get the finish time
  893.   ttStop=time(NULL);
  894.   // if the output file is open, close it
  895.   if(iFileHandle != -1)  _lclose(iFileHandle);
  896.   // if we had a recv error, let us know about it
  897.   if(iNumBytes==SOCKET_ERROR)
  898.   {
  899.     ReportWSError("recv",WSAGetLastError());
  900.     if(lBytesRead==0l)
  901.     {
  902.       if(bBell) MessageBeep(MB_ICONEXCLAMATION);
  903.       bCmdInProgress--;
  904.       return(FALSE);
  905.     }
  906.   }
  907.   SendMessage(hTxtRBytes,WM_SETTEXT,0,(LPARAM)NULL);
  908.  
  909.   ttDiff=ttStop-ttStart;
  910.   if(ttDiff==0l) ttDiff=1l;
  911.   // show the user how we did
  912.    if (lBytesRead > 1024)
  913.      {
  914.        DoPrintf("%ld bytes received in %.2f seconds, (%3.2fKbytes/sec), transfer %s",
  915.        lBytesRead,(float)ttDiff,(float)lBytesRead/1024.000/(float)ttDiff,
  916.      (iFileHandle==-1 || bAborted)?"failed":"succeeded");
  917.         // lgk set global variable so that we know it succeeded so we will 
  918.      // close window
  919.      globalsucceed = TRUE;
  920.      if (iFileHandle == -1)
  921.        globalsucceed = FALSE;
  922.      }
  923.  
  924.    else 
  925.  
  926.   DoPrintf("Received %ld bytes in %ld secs, %ld bps, transfer %s",
  927.     lBytesRead,(long)ttDiff,
  928.     lBytesRead*8l/(long)ttDiff,
  929.     (iFileHandle==-1 || bAborted)?"failed":"succeeded");
  930.        // lgk set global variable so that we know it succeeded so we will 
  931.      // close window
  932.      globalsucceed = TRUE;
  933.      if (iFileHandle == -1)
  934.        globalsucceed = FALSE;
  935.  
  936.   // DoPrintf("Bell = %d \n",bBell);
  937.   if(bBell > 0) MessageBeep(MB_ICONASTERISK);
  938.   // turn off our command in progress flag
  939.   bCmdInProgress--;
  940.  
  941.   return (TRUE);
  942. }
  943.  
  944.