AC_FTP.C
上传用户:tjfeida
上传日期:2013-03-10
资源大小:1917k
文件大小:26k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. /*---------------------------------------------------------------------
  2.  *
  3.  *  Program: AC_FTP.EXE Asynch Ftp Client (TCP)
  4.  *
  5.  *  filename: ac_ftp.c
  6.  *
  7.  *  copyright by Bob Quinn, 1995
  8.  *   
  9.  *  Description:
  10.  *    Client application that uses "file transfer protocol" (ftp)
  11.  *    service as described by RFC 959.  This application demonstrates
  12.  *    bulk data transfer techniques, and reading variable length records 
  13.  *    from a byte stream (TCP socket).  The user interface is minimized
  14.  *    in order to emphasize the network code.
  15.  *
  16.  *  This software is not subject to any  export  provision  of
  17.  *  the  United  States  Department  of  Commerce,  and may be
  18.  *  exported to any country or planet.
  19.  *
  20.  *  Permission is granted to anyone to use this  software  for any  
  21.  *  purpose  on  any computer system, and to alter it and redistribute 
  22.  *  it freely, subject to the following  restrictions:
  23.  *
  24.  *  1. The author is not responsible for the consequences of
  25.  *     use of this software, no matter how awful, even if they
  26.  *     arise from flaws in it.
  27.  *
  28.  *  2. The origin of this software must not be misrepresented,
  29.  *     either by explicit claim or by omission.  Since few users
  30.  *     ever read sources, credits must appear in the documentation.
  31.  *
  32.  *  3. Altered versions must be plainly marked as such, and
  33.  *     must not be misrepresented as being the original software.
  34.  *     Since few users ever read sources, credits must appear in
  35.  *     the documentation.
  36.  *
  37.  *  4. This notice may not be removed or altered.
  38.  *  
  39.  ---------------------------------------------------------------------*/
  40. #define STRICT
  41. #include "..wsa_xtra.h"
  42. #include <windows.h>
  43. #include <windowsx.h>
  44. #include <string.h>    /* for _fmemcpy() & _fmemset() */
  45. #include <winsock.h>
  46. #include "resource.h"
  47. #include <time.h>
  48. #include <stdio.h>
  49. #include <direct.h>    /* for getcwd() */
  50. #include "..winsockx.h"
  51. #include "ac_ftp.h"
  52. /* Ftp commmand strings (indexed by our command macro values) */
  53. LPSTR aszFtpCmd[] = {
  54.   "",    "CWD", "DELE", "PASS","PORT","RETR","STOR",
  55.   "TYPE","USER","ABOR","LIST","PWD",  "QUIT"
  56. };
  57. char szAppName[] = "AC_FTP";
  58. BOOL nAppState=NOT_CONNECTED;    /* Application State */
  59.                                    
  60. BOOL bToNul  =FALSE;             /* Get to NUL device file */
  61. BOOL bFromNul=FALSE;             /* Put from NUL device file */
  62. BOOL bIOBeep =FALSE;             /* Beep on FD_READ, FD_WRITE */
  63. BOOL bDebug  =FALSE;             /* Debug output to WinDebug */
  64. BOOL bReAsync=TRUE;              /* Call WSAAsyncSelect after accept() */
  65. BOOL bLogFile=TRUE;              /* Write Cmds and Replies to logfile */
  66. SOCKET hCtrlSock=INVALID_SOCKET; /* Ftp control socket */
  67. SOCKET hLstnSock=INVALID_SOCKET; /* Listening data socket */
  68. SOCKET hDataSock=INVALID_SOCKET; /* Connected data socket */
  69. char szHost[MAXHOSTNAME]={0};    /* Remote host name or address */
  70. char szUser[MAXUSERNAME]={0};    /* User ID */
  71. char szPWrd[MAXPASSWORD]={0};    /* User password */
  72. SOCKADDR_IN stCLclName;          /* Control socket name (local client) */
  73. SOCKADDR_IN stCRmtName;          /*                     (remote server) */
  74. SOCKADDR_IN stDLclName;          /* Data socket name (local client)*/          
  75. SOCKADDR_IN stDRmtName;          /*                  (remote server) */
  76.                               
  77. char achInBuf  [INPUT_SIZE];     /* Network input data buffer */
  78. char achOutBuf [INPUT_SIZE];     /* Network output buffer */
  79. char szFtpRply [RPLY_SIZE]={0};  /* Ftp reply (input) buffer */
  80. char szDataFile[MAXFILENAME]={0};/* Filename */
  81. char szFtpCmd  [CMD_SIZE]={0};   /* Ftp command buffer */
  82. char achRplyBuf[BUF_SIZE];       /* Reply display buffer */
  83. /* first one (index=0) is awaiting a reply
  84.  * second (index=1) is next to be sent, etcetera */ 
  85. FTPCMD astFtpCmd[MAX_CMDS];      /* Ftp command queue */
  86. int nQLen;                       /* Number of entries in Ftp cmd queue */
  87.  
  88. int nFtpRplyCode;                /* Ftp reply code from server */
  89. int iNextRply;                   /* Index to next reply string */
  90. int iLastRply;
  91. HFILE hDataFile=HFILE_ERROR;     /* File handle for open data file */
  92. LONG lStartTime;                 /* Start time for data transfer */
  93. LONG lByteCount;
  94. char szLogFile[] = "ac_ftp.log"; /* Ftp command and reply log file */
  95. HFILE hLogFile=HFILE_ERROR;
  96. /*--------------------------------------------------------------------
  97.  *  Function: WinMain()
  98.  *
  99.  *  Description: 
  100.  *     initialize WinSock and open main dialog box
  101.  *
  102.  */
  103. int WINAPI WinMain
  104.   (HINSTANCE hInstance,
  105.    HINSTANCE hPrevInstance,
  106.    LPSTR  lpszCmdLine,
  107.    int    nCmdShow)
  108. {
  109.     MSG msg;
  110.     int nRet;
  111.     lpszCmdLine   = lpszCmdLine;   /* avoid warning */
  112.     hPrevInstance = hPrevInstance;
  113.     nCmdShow      = nCmdShow;
  114.                       
  115.     hInst = hInstance; /* save instance handle */
  116.                                                                 
  117.     /*-------------initialize WinSock DLL------------*/
  118.     nRet = WSAStartup(WSA_VERSION, &stWSAData);
  119.     /* WSAStartup() returns error value if failed (0 on success) */
  120.     if (nRet != 0) {    
  121.       WSAperror(nRet, "WSAStartup()", hInst);
  122.       /* No sense continuing if we can't use WinSock */
  123.     } else {
  124.           
  125.       DialogBox (hInst, MAKEINTRESOURCE(AC_FTP), NULL, Dlg_Main);
  126.     
  127.       /*---------------release WinSock DLL--------------*/
  128.       nRet = WSACleanup();
  129.       if (nRet == SOCKET_ERROR)
  130.         WSAperror(WSAGetLastError(), "WSACleanup()", hInst);
  131.     }    
  132.         
  133.     return msg.wParam;
  134. } /* end WinMain() */
  135. /*--------------------------------------------------------------------
  136.  * Function: Dlg_Main()
  137.  *
  138.  * Description: Do all the message processing for the main dialog box
  139.  */
  140. BOOL CALLBACK Dlg_Main 
  141.   (HWND hDlg,
  142.    UINT msg,
  143.    UINT wParam,
  144.    LPARAM lParam)
  145. {                      
  146.     int nAddrSize = sizeof(SOCKADDR);
  147.     WORD WSAEvent, WSAErr;
  148.     SOCKET hSock;
  149.     BOOL bOk, bRet = FALSE;
  150.     int  nRet;
  151.     LONG lRet;
  152.    
  153.     switch (msg) {
  154.       case WSA_ASYNC+1:
  155.         /*------------------------------------------------- 
  156.          * Data socket async notification message handlers 
  157.          *-------------------------------------------------*/ 
  158.         hSock = (SOCKET)wParam;                 /* socket */
  159.         WSAEvent = WSAGETSELECTEVENT (lParam);  /* extract event */
  160.         WSAErr   = WSAGETSELECTERROR (lParam);  /* extract error */
  161.         /* if error, display to user (listen socket should not have
  162.          *  an error, but some WinSocks incorrectly post it) */
  163.         if ((WSAErr) && (hSock == hDataSock))  {
  164.           int i,j;
  165.           for (i=0, j=WSAEvent; j; i++, j>>=1); /* convert bit to index */
  166.             WSAperror(WSAErr,aszWSAEvent[i], hInst);
  167.           /* fall-through to call reenabling function for this event */
  168.         }
  169.         switch (WSAEvent) {
  170.           case FD_READ:
  171.             if (bIOBeep)
  172.               MessageBeep(0xFFFF);
  173.             if (hDataSock != INVALID_SOCKET) {
  174.               /* Receive file data or directory list */
  175.               RecvData(hDataSock, hDataFile, achInBuf, INPUT_SIZE);
  176.             }
  177.             break;
  178.           case FD_ACCEPT:
  179.             if (hLstnSock != INVALID_SOCKET) {
  180.               /* Accept the incoming data connection request */
  181.               hDataSock = 
  182.                 AcceptDataConn(hLstnSock, &stDRmtName);
  183.               nAppState |= DATACONNECTED;
  184.               /* Close the Listening Socket */
  185.               closesocket(hLstnSock);
  186.               hLstnSock = INVALID_SOCKET;
  187.               lStartTime = GetTickCount();
  188.               /* Data transfer should begin with FD_WRITE or FD_READ.  We 
  189.                * fall through to jumpstart sends since FD_WRITE is not 
  190.                * always implemented correctly */
  191.             }
  192.           case FD_WRITE:
  193.              /* Send file data */
  194.             if (astFtpCmd[0].nFtpCmd == STOR) {
  195.               lRet = SendData(&hDataSock, hDataFile, MTU_SIZE);
  196.             }
  197.             break;
  198.           case FD_CLOSE:                    /* Data connection closed */
  199.             if (hSock == hDataSock) {
  200.               /* Read any remaining data into buffer and close connection */  
  201.               CloseFtpConn(&hDataSock, 
  202.                 (astFtpCmd[0].nFtpCmd != STOR) ? achInBuf : (LPSTR)0, 
  203.                 INPUT_SIZE, hDlg);
  204.               EndData ();
  205.             }
  206.             break;
  207.           default:
  208.              break;
  209.         } /* end switch(WSAEvent) */
  210.         break;
  211.         
  212.       case WSA_ASYNC: 
  213.         /*----------------------------------------------------- 
  214.          * Control socket async notification message handlers 
  215.          *-----------------------------------------------------*/ 
  216.         WSAEvent = WSAGETSELECTEVENT (lParam);  /* extract event */
  217.         WSAErr   = WSAGETSELECTERROR (lParam);  /* extract error */
  218.         if (WSAErr) { /* if error, display to user */
  219.           int i,j;
  220.           for (i=0, j=WSAEvent; j; i++, j>>=1); /* convert bit to index */
  221.           WSAperror(WSAErr,aszWSAEvent[i], hInst);
  222.           /* fall-through to call reenabling function for this event */
  223.         }
  224.         hSock = (SOCKET)wParam;                  
  225.         switch (WSAEvent) {
  226.           case FD_READ:
  227.              if (!iNextRply) {
  228.                 /* Receive reply from server */
  229.                 iLastRply = RecvFtpRply(hCtrlSock, szFtpRply, RPLY_SIZE);
  230.              }
  231.             if (iLastRply && (iLastRply != SOCKET_ERROR)) {
  232.                 /* Display the reply Message */
  233.                 GetDlgItemText (hWinMain, IDC_REPLY, achRplyBuf, 
  234.                   RPLY_SIZE-strlen(szFtpRply));
  235.                 wsprintf (achTempBuf, "%s%s", szFtpRply, achRplyBuf);
  236.                 SetDlgItemText (hWinMain, IDC_REPLY, achTempBuf);
  237.         /* Save index to next reply (if there is one) */
  238.                 nRet = strlen(szFtpRply);
  239.                 if (iLastRply > nRet+2) {
  240.                   iNextRply = nRet+3;
  241.                   /* Adjust if reply only had LF (no CR) */
  242.                   if (szFtpRply[nRet+2])
  243.                     iNextRply = nRet+2;
  244.                 }
  245.              }
  246.             /* Figure out what to do with reply based on last command */
  247.             ProcessFtpRply (szFtpRply, RPLY_SIZE);
  248.             break;
  249.           case FD_WRITE:
  250.             /* Send command to server */
  251.             if (astFtpCmd[1].nFtpCmd)
  252.               SendFtpCmd();
  253.             break;
  254.           case FD_CONNECT:
  255.             /* Control connected at TCP level */
  256.             nAppState = CTRLCONNECTED;
  257.             wsprintf(achTempBuf, "Server: %s", szHost);
  258.             SetDlgItemText (hDlg, IDC_SERVER, achTempBuf);
  259.             SetDlgItemText (hDlg, IDC_STATUS, "Status: connected");
  260.             break;
  261.           case FD_CLOSE:
  262.             if (nAppState & CTRLCONNECTED) {
  263.               nAppState = NOT_CONNECTED;        /* Reset app state */
  264.               AbortFtpCmd();
  265.               if (hCtrlSock != INVALID_SOCKET)  /* Close control socket */
  266.                 CloseFtpConn(&hCtrlSock, (PSTR)0, 0, hDlg);
  267.               SetDlgItemText (hDlg, IDC_SERVER, "Server: none");
  268.               SetDlgItemText (hDlg, IDC_STATUS, "Status: not connected");
  269.             }
  270.             break;
  271.           default:
  272.              break;
  273.         } /* end switch(WSAEvent) */
  274.         break;
  275.       case WM_COMMAND:
  276.         switch (wParam) {
  277.           case IDC_CONNECT:
  278.              /* If we already have a socket open, tell user to close it */
  279.              if (nAppState & CTRLCONNECTED) {
  280.                  MessageBox (hDlg,"Close the active connection first",
  281.                     "Can't Connect", MB_OK | MB_ICONASTERISK);
  282.              } else {
  283.              
  284.                /* Prompt user for server and login user information */
  285.                bOk = DialogBox (hInst, MAKEINTRESOURCE(IDD_SERVER),
  286.                       hDlg, Dlg_Login);
  287.     
  288.                if (bOk) {
  289.                  /* Check the destination address and resolve if necessary */
  290.                  stCRmtName.sin_addr.s_addr = GetAddr(szHost);
  291.                  if (stCRmtName.sin_addr.s_addr == INADDR_ANY) {
  292.                
  293.                    /* Tell user to enter a host */
  294.                    wsprintf(achTempBuf, 
  295.                      "Sorry, server %s is invalid.  Try again", szHost);
  296.                    MessageBox (hDlg, achTempBuf,
  297.                      "Can't connect!", MB_OK | MB_ICONASTERISK);
  298.                  } else {
  299.                  
  300.                    /* Initiate connect attempt to server */
  301.                    hCtrlSock = 
  302.                      InitCtrlConn(&stCRmtName, hDlg, WSA_ASYNC);
  303.                  }
  304.                }
  305.              }
  306.              break;
  307.                      
  308.            case IDC_CLOSE:
  309.              if (nAppState & CTRLCONNECTED) {
  310.                /* Set application state so nothing else is processed */
  311.                nAppState = NOT_CONNECTED;
  312.                
  313.                /* If we're listening, stop now */
  314.                if (hLstnSock != INVALID_SOCKET) {
  315.                  closesocket(hLstnSock);
  316.                  hLstnSock = INVALID_SOCKET;
  317.                }
  318.                /* If there is a data connection, then abort it */
  319.                if (hDataSock != INVALID_SOCKET)
  320.                  QueueFtpCmd (ABOR, 0);
  321.                /* Quit the control connection */
  322.                if (hCtrlSock != INVALID_SOCKET)
  323.                  QueueFtpCmd (QUIT, 0);
  324.                SetDlgItemText (hDlg, IDC_SERVER, "Server: none");
  325.                SetDlgItemText (hDlg, IDC_STATUS, "Status: not connected");
  326.              }
  327.              break;
  328.                      
  329.            case IDC_RETR:
  330.              /* Prompt for name of remote file to get */
  331.              if (nAppState & CTRLCONNECTED) {
  332.                bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME),
  333.                  hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
  334.                  
  335.                if (bOk && szDataFile[0]) {
  336.                  if (!bToNul) {
  337.                    /* If user provided a filename open same name here for write.
  338.                     *  Truncate the filename to 8 chars plus 3, if necessary */
  339.                    hDataFile = CreateLclFile (szDataFile);
  340.                  }
  341.                  if (hDataFile != HFILE_ERROR || bToNul) {
  342.                    /* Tell the Server where to connect back to us */
  343.                    hLstnSock =
  344.                      InitDataConn(&stDLclName, hDlg, WSA_ASYNC+1);
  345.                    if (hLstnSock != INVALID_SOCKET) {
  346.                       /* Queue PORT, TYPE and RETR cmds */
  347.                      if (QueueFtpCmd(PORT, 0)) {
  348.                        if (QueueFtpCmd (TYPE, "I"))  
  349.                          QueueFtpCmd(RETR, szDataFile);
  350.                      }
  351.                    }
  352.                  }
  353.                }
  354.              } else
  355.                not_connected();
  356.              break;
  357.             
  358.            case IDC_STOR:
  359.              /* Prompt for name of local file to send */
  360.              if (nAppState & CTRLCONNECTED) {
  361.                bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME),
  362.                  hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
  363.                                                                    
  364.                if (bOk && szDataFile[0]) {
  365.                  if (!bFromNul) {
  366.                    /* If user provided filename, try to open same name locally */
  367.                    hDataFile = _lopen(szDataFile, 0);
  368.                    if (hDataFile == HFILE_ERROR) {
  369.                      wsprintf(achTempBuf, "Unable to open file: %s", szDataFile);
  370.                      MessageBox (hWinMain, (LPSTR)achTempBuf,"File Error",  
  371.                        MB_OK | MB_ICONASTERISK);
  372.                    }
  373.                  }
  374.                  if (hDataFile != HFILE_ERROR || bFromNul) {
  375.                    /* Tell the Server where to connect back to us */
  376.                    hLstnSock =
  377.                      InitDataConn(&stDLclName, hDlg, WSA_ASYNC+1);
  378.                    if (hLstnSock != INVALID_SOCKET) {
  379.                      /* Queue PORT, TYPE and STOR cmds */
  380.                      if (QueueFtpCmd (PORT, 0)) {
  381.                        if (QueueFtpCmd (TYPE, "I"))
  382.                          QueueFtpCmd (STOR, szDataFile);
  383.                      }                     
  384.                    }
  385.                  }
  386.                }
  387.              } else
  388.                not_connected();
  389.              break;
  390.              
  391.            case IDC_ABOR:
  392.              if (hCtrlSock != INVALID_SOCKET)
  393.                /* Abort the pending ftp command */
  394.                QueueFtpCmd (ABOR, 0);
  395.              break;
  396.              
  397.            case IDC_LCWD:
  398.              /* Prompt for directory name, and move to it on local system. */
  399.              bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME), 
  400.                      hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
  401.              
  402.              if (bOk && szDataFile[0]) {
  403.                if (!(_chdir (szDataFile))) {
  404.                  getcwd (szDataFile, MAXFILENAME-1);
  405.                  SetDlgItemText (hDlg, IDC_LPWD, szDataFile);
  406.                }
  407.              }
  408.              break;
  409.              
  410.            case IDC_LDEL:
  411.              /* Prompt for filename, and delete it from local system */
  412.              bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME), 
  413.                      hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
  414.              if (bOk && szDataFile[0]) {
  415.                /* If user provided filename, then delete it */
  416.                remove (szDataFile);
  417.              }
  418.              break;
  419.              
  420.            case IDC_LDIR:
  421.              /* Get local file directory, and display in notepad */
  422.              if (GetLclDir(szTempFile)) {
  423.                wsprintf (achTempBuf, "notepad %s", szTempFile);
  424.                WinExec (achTempBuf, SW_SHOW);
  425.              }             
  426.              break;
  427.         
  428.            case IDC_RCWD:
  429.              /* Prompt for directory name, and move to it on remote system. */
  430.              if (nAppState & CTRLCONNECTED) {
  431.                szDataFile[0] = 0;
  432.                bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME), 
  433.                  hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
  434.              
  435.                if (bOk && szDataFile[0]) {
  436.                  QueueFtpCmd (CWD, szDataFile);
  437.                }
  438.              } else
  439.                not_connected();
  440.              break;
  441.              
  442.            case IDC_RDEL:
  443.              /* Prompt for filename, and delete it from remote system */
  444.              if (nAppState & CTRLCONNECTED) {
  445.                szDataFile[0] = 0;
  446.                bOk = DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_FILENAME), 
  447.                  hDlg, Dlg_File, (LONG)(LPSTR)szDataFile);
  448.              
  449.                if (bOk && szDataFile[0]) {
  450.                  /* If user provided a filename, send command to delete it */
  451.                  QueueFtpCmd (DELE, szDataFile);
  452.                }
  453.              } else
  454.                not_connected();
  455.              break;
  456.                                                    
  457.            case IDC_RDIR:
  458.              /* Get remote file directory, and display in notepad file */
  459.              if (nAppState & CTRLCONNECTED) {
  460.                hDataFile = CreateLclFile (szTempFile);
  461.                if (hDataFile != HFILE_ERROR) {
  462.                  /* Prepare to receive the incoming connection from server */
  463.                  hLstnSock =
  464.                    InitDataConn(&stDLclName, hDlg, WSA_ASYNC+1);
  465.                  if (hLstnSock != INVALID_SOCKET) {
  466.                    if (QueueFtpCmd (PORT, 0))          /* Queue PORT, TYPE and LIST cmds */
  467.                      if (QueueFtpCmd (TYPE, "A"))
  468.                        QueueFtpCmd (LIST, 0);
  469.                  }
  470.                }
  471.              } else 
  472.                not_connected();
  473.              break;
  474.              
  475.            case IDC_OPTIONS:
  476.              DialogBox (hInst, MAKEINTRESOURCE(IDD_OPTIONS), 
  477.                  hDlg, Dlg_Options);
  478.              break;
  479.              
  480.            case IDABOUT:
  481.              DialogBox (hInst, MAKEINTRESOURCE(IDD_ABOUT), hDlg, Dlg_About);
  482.              break;
  483.        case WM_DESTROY:
  484.            case IDC_EXIT:
  485.              SendMessage (hDlg, WM_COMMAND, IDC_CLOSE, 0L);
  486.              if (hLogFile != HFILE_ERROR) 
  487.                _lclose(hLogFile);
  488.              EndDialog(hDlg, msg);
  489.              bRet = TRUE;
  490.              break;
  491.                        
  492.            default:
  493.               break;
  494.          } /* end case WM_COMMAND: */
  495.          break;
  496.            
  497.       case WM_INITDIALOG:
  498.         hWinMain = hDlg; /* save our main window handle */
  499.         
  500.         /* Assign an icon to dialog box */
  501. #ifdef WIN32
  502.         SetClassLong (hDlg, GCL_HICON, (LONG)        
  503.           LoadIcon((HINSTANCE) GetWindowLong(hDlg, GWL_HINSTANCE),
  504.           __TEXT("AC_FTP")));
  505. #else
  506.         SetClassWord(hDlg,GCW_HICON,(WORD)LoadIcon(hInst,MAKEINTRESOURCE(AC_FTP)));
  507. #endif
  508.         /* Initialize FTP command structure array */
  509.         memset (astFtpCmd, 0, (sizeof(struct stFtpCmd))*MAX_CMDS);
  510.         
  511.         /* Display current working directory */
  512.         getcwd (szDataFile, MAXFILENAME-1);
  513.         SetDlgItemText (hDlg, IDC_LPWD, szDataFile);
  514.         
  515.         /* Open logfile, if logging enabled */
  516.         if (bLogFile) {
  517.           hLogFile = _lcreat (szLogFile, 0);
  518.           if (hLogFile == HFILE_ERROR) { 
  519.             MessageBox (hWinMain, "Unable to open logfile",
  520.               "File Error", MB_OK | MB_ICONASTERISK);
  521.             bLogFile = FALSE;
  522.           }
  523.         }
  524.         /* Center dialog box */
  525.         CenterWnd (hDlg, NULL, TRUE);
  526.         break;
  527.              
  528.       default:
  529.         break;
  530.   } /* end switch (msg) */
  531.   return (bRet);
  532. } /* end Dlg_Main() */
  533. /*---------------------------------------------------------------------
  534.  * Function: Dlg_Login
  535.  *
  536.  * Description: Prompt for destination host, user name, and password
  537.  */                                        
  538. BOOL CALLBACK Dlg_Login (
  539.   HWND hDlg,
  540.   UINT msg,
  541.   UINT wParam,
  542.   LPARAM lParam)
  543. {
  544.    BOOL bRet = FALSE;
  545.    lParam = lParam;  /* avoid warning */
  546.    switch (msg) {
  547.      case WM_INITDIALOG:
  548.        SetDlgItemText (hDlg, IDC_SERVER, szHost);
  549.        SetDlgItemText (hDlg, IDC_USERNAME, szUser);
  550.        SetDlgItemText (hDlg, IDC_PASSWORD, szPWrd);
  551.        CenterWnd (hDlg, hWinMain, TRUE);
  552.        break;
  553.      case WM_COMMAND:
  554.        switch (wParam) {
  555.          case IDOK:
  556.            GetDlgItemText (hDlg, IDC_SERVER, szHost, MAXHOSTNAME);
  557.            GetDlgItemText (hDlg, IDC_USERNAME, szUser, MAXUSERNAME);
  558.            GetDlgItemText (hDlg, IDC_PASSWORD, szPWrd, MAXPASSWORD);
  559.            EndDialog (hDlg, TRUE);
  560.            bRet = TRUE;
  561.            break;
  562.          case IDCANCEL:
  563.            EndDialog (hDlg, FALSE);
  564.            bRet = FALSE;
  565.            break;
  566.          default:
  567.            break;
  568.        }
  569.    }        
  570.    return(bRet);
  571. } /* end Dlg_Login */
  572. /*---------------------------------------------------------------------
  573.  * Function: Dlg_Options()
  574.  *
  575.  * Description: Allow user to change a number of run-time parameters
  576.  *  that affect the operation, to allow experimentation and debugging.
  577.  */                                        
  578. BOOL CALLBACK Dlg_Options (
  579.   HWND hDlg,
  580.   UINT msg,
  581.   UINT wParam,
  582.   LPARAM lParam)
  583. {
  584.    BOOL bRet = FALSE;
  585.    lParam = lParam;  /* avoid warning */
  586.    switch (msg) {
  587.      case WM_INITDIALOG:
  588.        CheckDlgButton (hDlg, IDC_TO_NUL,  bToNul);
  589.        CheckDlgButton (hDlg, IDC_FROM_NUL,bFromNul);
  590.        CheckDlgButton (hDlg, IDC_LOGFILE, bLogFile);
  591.        CheckDlgButton (hDlg, IDC_IOBEEP,  bIOBeep);
  592.        CheckDlgButton (hDlg, IDC_REASYNC, bReAsync);
  593.        CenterWnd (hDlg, hWinMain, TRUE);
  594.        break;
  595.        
  596.      case WM_COMMAND:
  597.        switch (wParam) {
  598.          case IDC_TO_NUL:
  599.            bToNul = !bToNul;
  600.            break;
  601.          case IDC_FROM_NUL:
  602.            bFromNul = !bFromNul;
  603.            break;
  604.          case IDC_LOGFILE:
  605.            bLogFile = !bLogFile;
  606.            break;
  607.          case IDC_IOBEEP:
  608.            bIOBeep = !bIOBeep;
  609.            break;
  610.          case IDC_REASYNC:
  611.            bReAsync = !bReAsync;
  612.            break;
  613.          case IDOK:
  614.            if (bLogFile && hLogFile == HFILE_ERROR) {
  615.              bLogFile = FALSE;
  616.            } else if (!bLogFile && hLogFile != HFILE_ERROR) {
  617.              _lclose(hLogFile);
  618.              hLogFile = HFILE_ERROR;
  619.            } else if (bLogFile && hLogFile == HFILE_ERROR) {
  620.              hLogFile = _lcreat (szLogFile, 0);
  621.              if (hLogFile == HFILE_ERROR) { 
  622.                MessageBox (hWinMain, "Unable to open logfile",
  623.                  "File Error", MB_OK | MB_ICONASTERISK);
  624.                bLogFile = FALSE;
  625.              }
  626.            }
  627.            EndDialog (hDlg, TRUE);
  628.            bRet = TRUE;
  629.            break;
  630.        }
  631.    }        
  632.    return(bRet);
  633. } /* end Dlg_Options() */
  634. /*---------------------------------------------------------------
  635.  * Function: not_connected()
  636.  *
  637.  * Description: tell the user that the client needs a connection.
  638.  */
  639. void not_connected(void) {
  640.   MessageBox (hWinMain, "You need to connect to an FTP Server",
  641.    "Not Connected",  MB_OK | MB_ICONASTERISK);
  642. }
  643. /*--------------------------------------------------------------
  644.  * Function: CloseFtpConn()
  645.  *
  646.  * Description: Close the connection gracefully and robustly,
  647.  *  reading all remaining data into buffer before closure.
  648.  */
  649. int CloseFtpConn(SOCKET *hSock, LPSTR achInBuf, int len, HWND hWnd)
  650. {
  651.   char achDiscard[BUF_SIZE];
  652.   int nRet=0;
  653.   
  654.   if (*hSock != INVALID_SOCKET) {
  655.     /* disable asynchronous notification if window handle provided */
  656.     if (hWnd) {
  657.       nRet = WSAAsyncSelect(*hSock, hWnd, 0, 0);
  658.       if (nRet == SOCKET_ERROR)
  659.         WSAperror (WSAGetLastError(), "CloseFtpConn() WSAAsyncSelect()", hInst);
  660.     }
  661.   
  662.     /* Half-close the connection to close neatly */
  663.     nRet = shutdown (*hSock, 1);
  664.     if (nRet == SOCKET_ERROR) {
  665.       WSAperror (WSAGetLastError(), "shutdown()", hInst);
  666.     } else {
  667.       /* Read and discard remaining data (until EOF or error) */
  668.       nRet = 1;
  669.       while (nRet && (nRet != SOCKET_ERROR)) {
  670.         if (achInBuf) 
  671.           nRet = RecvData(*hSock, hDataFile, achInBuf, len);
  672.         else
  673.           nRet = recv (*hSock, (LPSTR)achDiscard, BUF_SIZE, 0);
  674.       }
  675.       /* close the socket, and ignore any error 
  676.        *  (since we can't do much about them anyway */
  677.       closesocket (*hSock);
  678.     }
  679.     *hSock = INVALID_SOCKET;  /* we always invalidate socket */
  680.   }
  681.   return (nRet);
  682. } /* end CloseFtpConn() */