<< Back
// SampleCPPDlg.cpp : implementation file
//
// Copyright © 1997-2008 - Rhino Software, Inc.
// FTP Voyager® is a registered trademark of Rhino Software, Inc.
// http://www.RhinoSoft.com/
//
// Author:  Mark P. Peterson
// Date:    August 19, 2005
//
// You are free to use/modify this code but leave this header intact.
// This code is public domain so you are free to use it any of your
// applications (Freeware, Trialware, Commercial, etc.).  FTP Voyager,
// the FTP Voyager Software Development Kit, and FtpTree ActiveX Control
// are not public domain.  Any registration IDs or non-public domain software
// from Rhino Software, Inc. remains copyrighted.  For more information
// refer to the license agreement distributed with the FTP Voyager SDK.
//
// If you decide to use the FTP Voyager Software Development Kit, or FtpTree
// ActiveX control, you must first purchase a license.  For more information
// visit http://www.RhinoSoft.com/
//------------------------------------------------------------------------------
//
// NOTE: This FTP Voyager SDK sample is more complex than the C Sample found in
// C:\Program Files\RhinoSoft.com\FVSDK\SampleC
// The intent of this sample is to cover all of the FTP Voyager SDK's functionality
//
//------------------------------------------------------------------------------

#include "stdafx.h"
#include "SampleCPP.h"
#include "SampleCPPDlg.h"
#include "GetFileNameDlg.h"
#include "GetCommandDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg dialog

CSampleCPPDlg::CSampleCPPDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CSampleCPPDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CSampleCPPDlg)
    m_sServer           = _T("ftp.simtel.net");
    m_sUserID           = _T("anonymous");
    m_sPassword         = _T("x@x.com");
    m_nPort             = 21;
    m_bPASV             = FALSE;
    m_bShowRawListings  = TRUE;
    m_bXferDialogs      = FALSE;
    //}}AFX_DATA_INIT

    // init vars
    m_pSession          = NULL;
    m_sLocalFileName    = "C:\\";

    // load the application icon
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} // CSampleCPPDlg


CSampleCPPDlg::~CSampleCPPDlg()
{
    // if this assertion fails, something is wrong because we didn't free the session
    ASSERT(! m_pSession);
} // ~CSampleCPPDlg


void CSampleCPPDlg::DoDataExchange(CDataExchange* pDX)
{
    // call the base class function
    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CSampleCPPDlg)
    DDX_Text(pDX, IDC_BUILD_DATE, m_sBuildDate);
    DDX_Text(pDX, IDC_VERSION, m_sVersion);
    DDX_Text(pDX, IDC_SERVER, m_sServer);
    DDX_Text(pDX, IDC_PORT, m_nPort);
    DDX_Text(pDX, IDC_USER_ID, m_sUserID);
    DDX_Text(pDX, IDC_PASSWORD, m_sPassword);
    DDX_Text(pDX, IDC_STATUS, m_sStatus);
    DDX_Check(pDX, IDC_PASV, m_bPASV);
    DDX_Check(pDX, IDC_RAW, m_bShowRawListings);
    DDX_Check(pDX, IDC_XFER_DIALOGS, m_bXferDialogs);
    DDX_Control(pDX, IDC_LOG_LIST, m_LogList);
    //}}AFX_DATA_MAP
} // DoDataExchange


BEGIN_MESSAGE_MAP(CSampleCPPDlg, CDialog)
    //{{AFX_MSG_MAP(CSampleCPPDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_CONNECT, OnBnClickedConnect)
    ON_BN_CLICKED(IDC_STOP, OnBnClickedStop)
    ON_BN_CLICKED(IDC_DISCONNECT, OnBnClickedDisconnect)
    ON_BN_CLICKED(IDC_CWD, OnBnClickedCwd)
    ON_BN_CLICKED(IDC_RMD, OnBnClickedRmd)
    ON_BN_CLICKED(IDC_MKD, OnBnClickedMkd)
    ON_BN_CLICKED(IDC_CDUP, OnBnClickedCdup)
    ON_BN_CLICKED(IDC_LAST_RESPONSE, OnBnClickedLastResponse)
    ON_BN_CLICKED(IDC_WELCOME_MESSAGE, OnBnClickedWelcomeMessage)
    ON_BN_CLICKED(IDC_SEND_COMMAND, OnBnClickedSendCommand)
    ON_BN_CLICKED(IDC_PASV, OnBnClickedPasv)
    ON_BN_CLICKED(IDC_LIST_DIR, OnBnClickedListDir)
    ON_BN_CLICKED(IDC_RAW, OnBnClickedRaw)
    ON_BN_CLICKED(IDC_DOWNLOAD, OnBnClickedDownload)
    ON_BN_CLICKED(IDC_MOVE_DOWN, OnBnClickedMoveDown)
    ON_BN_CLICKED(IDC_UPLOAD, OnBnClickedUpload)
    ON_BN_CLICKED(IDC_MOVE_UP, OnBnClickedMoveUp)
    ON_BN_CLICKED(IDC_CLEAR_LOG, OnBnClickedClearLog)
    ON_BN_CLICKED(IDC_DELETE_FILE, OnBnClickedDeleteFile)
    ON_BN_CLICKED(IDC_RENAME, OnBnClickedRename)
    ON_BN_CLICKED(IDC_SIZE_BUTTON, OnBnClickedSize)
    ON_BN_CLICKED(IDC_FILE_UPLOAD, OnBnClickedFileUpload)
    ON_BN_CLICKED(IDC_FILE_DOWNLOAD, OnBnClickedFileDownload)
    ON_BN_CLICKED(IDC_EDIT_FILE, OnBnClickedEditFile)
    ON_BN_CLICKED(IDC_VIEW_FILE, OnBnClickedViewFile)
    ON_BN_CLICKED(IDC_XFER_DIALOGS, OnBnClickedXferDialogs)
    ON_BN_CLICKED(IDC_FIND_FILES, OnBnClickedFindFiles)
    ON_BN_CLICKED(IDC_SYNC_FOLDERS, OnBnClickedSyncFolders)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg operations

BOOL CSampleCPPDlg::LastOperationStopped()
{
    // check if the last operation was stopped
    return (FVSDK_LastOperationStopped(m_pSession) == FVSDK_YES);
} // LastOperationStopped


int CSampleCPPDlg::MsgBox(LPCTSTR pszMsg, UINT nType /*=MB_OK*/)
{
    int nRet = MB_OK;

    // check for registration ID errors, put up a message if it's a registration ID error
    switch (m_pSession->fvecLastError) {

        case FVSDK_INVALID_REGISTRATION_ID :
        case FVSDK_EXPIRED_REGISTRATION_ID :
        case FVSDK_EXPIRED_TEMP_REGISTRATION_ID :
        case FVSDK_EXPIRED_TRIAL :
            nRet = MsgBox(0);
            break;

        default :
            nRet = AfxMessageBox(pszMsg, nType);
            break;
    } // switch

    // return the return value from the message box
    return (nRet);
} // MsgBox


int CSampleCPPDlg::MsgBox(int nID, UINT nType /*=MB_OK*/)
{
    int nRet = MB_OK;

    // check for registration ID errors, put up a message if it's a registration ID error
    switch (m_pSession->fvecLastError) {

        case FVSDK_INVALID_REGISTRATION_ID :
            nRet = AfxMessageBox(IDS_INVALID_REGISTRATION_ID, (MB_ICONEXCLAMATION | MB_OK));
            break;

        case FVSDK_EXPIRED_REGISTRATION_ID :
            nRet = AfxMessageBox(IDS_EXPIRED_REGISTRATION_ID, (MB_ICONEXCLAMATION | MB_OK));
            break;

        case FVSDK_EXPIRED_TEMP_REGISTRATION_ID :
            nRet = AfxMessageBox(IDS_EXPIRED_TEMP_REGISTRATION_ID, (MB_ICONEXCLAMATION | MB_OK));
            break;

        case FVSDK_EXPIRED_TRIAL :
            nRet = AfxMessageBox(IDS_EXPIRED_TRIAL, (MB_ICONEXCLAMATION | MB_OK));
            break;

        default :
            if (! LastOperationStopped())
                nRet = AfxMessageBox(nID, nType);
            break;
    } // switch

    // return the return value from the message box
    return (nRet);
} // MsgBox


BOOL CSampleCPPDlg::CheckBusy()
{
    BOOL    bRet = FALSE;

    // check if the FTP Voyager SDK is busy or not
    if (FVSDK_Working(m_pSession) == FVSDK_YES) {

        // put up a "generic" sort of message that the SDK is busy
        MsgBox(IDS_CURRENTLY_BUSY, MB_ICONEXCLAMATION);

        // yes, it's busy
        bRet = TRUE;
    } // if

    // return TRUE if the FVSDK is busy with another operation, or FALSE if it's not
    return (bRet);
} // CheckBusy


BOOL CSampleCPPDlg::CheckNotConnected()
{
    BOOL    bRet = FALSE;

    // check if the connected or not
    if (FVSDK_Connected(m_pSession) == FVSDK_NO) {

        // put up a "generic" sort of message that the session isn't connected
        MsgBox(IDS_NOT_CONNECTED, MB_ICONEXCLAMATION);

        // it's not connected
        bRet = TRUE;
    } // if

    // return TRUE if the session is disconnected, or FALSE if it's connected
    return (bRet);
} // CheckNotConnected


void CSampleCPPDlg::SetCurrentDirText()
{
    CString             sDir;
    FVSDK_ERROR_CODE    fvecLastError = m_pSession->fvecLastError;

    // current directory
    if (FVSDK_Connected(m_pSession) == FVSDK_YES) {
        char    pszBuffer[MAX_PATH * 2];

        // show the current directory
        if (FVSDK_GetCurrentDirectory(m_pSession, pszBuffer, sizeof(pszBuffer)) == FVSDK_OK)
            sDir = pszBuffer;
        else
            sDir.LoadString(IDS_NA);
    } // if
    else
        sDir.LoadString(IDS_NA);

    // set the current directory string
    m_sCurrentDir.Format(m_sCurrentDirFmt, sDir);

    // instead of calling UpdateData(), just set the text of the string
    GetDlgItem(IDC_CURRENT_DIR)->SetWindowText(m_sCurrentDir);

    // reset the last error code
    m_pSession->fvecLastError = fvecLastError;
} // SetCurrentDirText


void CSampleCPPDlg::SetStatus(int nSampleStatus /*=SAMPLE_CHECK_STATUS*/)
{
    int                 nID = IDS_UNKNOWN;
    CString             sStatus;
    FVSDK_ERROR_CODE    fvecLastError = m_pSession->fvecLastError;

    // get the status string ID
    switch (nSampleStatus) {

        case SAMPLE_CONNECTING :
            nID = IDS_CONNECTING;
            break;

        case SAMPLE_DISCONNECTING :
            nID = IDS_DISCONNECTING;
            break;

        case SAMPLE_CHECK_STATUS :
            if (CheckBusy())
                nID = IDS_BUSY;
            else if (FVSDK_Connected(m_pSession) == FVSDK_YES)
                nID = IDS_CONNECTED;
            else if (FVSDK_Connected(m_pSession) == FVSDK_NO)
                nID = IDS_DISCONNECTED; 
            break;
    } // switch

    // load the status string
    sStatus.LoadString(nID);

    // make it upper case so it's easier to see
    sStatus.MakeUpper();

    // build the status string for the dialog
    m_sStatus.Format(m_sStatusFmt, sStatus);

    // instead of calling UpdateData(), just set the text of the string
    GetDlgItem(IDC_STATUS)->SetWindowText(m_sStatus);

    // set the current directory text
    SetCurrentDirText();

    // reset the last error code
    m_pSession->fvecLastError = fvecLastError;
} // SetStatus


BOOL CSampleCPPDlg::GetFileName(CString& rsFileName, LPCTSTR pszDefault /*=NULL*/)
{
    char    pszBuffer[MAX_PATH * 2];
    BOOL    bRet = FALSE;

    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return (bRet);

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return (bRet);

    // get the current directory so that we have somewhere to start in the dialog
    if (FVSDK_GetCurrentDirectory(m_pSession, pszBuffer, sizeof(pszBuffer)) == FVSDK_YES) {
        CGetFileNameDlg Dlg;
        CString         sDir = pszBuffer;

        // create the default file name
        if (pszDefault) {

            // build the filename
            if (sDir.Right(1) == '/')
                sDir += pszDefault;
            else if (! sDir.IsEmpty())
                sDir += (CString("/") + pszDefault);
            else
                sDir = pszDefault;
        } // if

        // fill in the default
        Dlg.SetFileName(sDir);

        // ask the user for the directory name
        if ((Dlg.DoModal() == IDOK) && (! Dlg.GetFileName().IsEmpty())) {
            rsFileName = Dlg.GetFileName();
            bRet = TRUE;
        } // if
    } // if
    else
        MsgBox(IDS_UNABLE_TO_GET_CURRENT_DIRECTORY);

    // return TRUE if successful, FALSE if not
    return (bRet);
} // GetFileName


BOOL CSampleCPPDlg::GetLocalFileName(CString& rsFileName)
{
    BOOL            bRet = FALSE;
    CGetFileNameDlg Dlg;

    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return (bRet);

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return (bRet);

    // fill in the default
    Dlg.SetFileName(m_sLocalFileName);

    // ask the user for the directory name
    if ((Dlg.DoModal() == IDOK) && (! Dlg.GetFileName().IsEmpty())) {
        rsFileName = m_sLocalFileName = Dlg.GetFileName();
        bRet = TRUE;
    } // if

    // return TRUE if successful, FALSE if not
    return (bRet);
} // GetLocalFileName

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg message handlers

BOOL CSampleCPPDlg::OnInitDialog()
{
    FVSDK_ERROR_CODE    fvecRet;
    char                pszVersion[32];
    CString             sStr;
    tm                  tmBuildDate;

    // get the FTP Voyager SDK build date and time
    FVSDK_BuildDate(&tmBuildDate);

    // for simplicity's sake, convert the build date and time to a CTime object
    CTime BuildTime((1900 + tmBuildDate.tm_year), (tmBuildDate.tm_mon + 1), tmBuildDate.tm_mday,
                                    tmBuildDate.tm_hour, tmBuildDate.tm_min, tmBuildDate.tm_sec);

    // subclass the log rich edit control
    m_LogList.SubclassDlgItem(IDC_LOG_LIST, this);

    // get the format string for the build date
    GetDlgItem(IDC_BUILD_DATE)->GetWindowText(sStr);

    // build the build date string
    m_sBuildDate.Format(sStr, BuildTime.Format("%c"));

    // get the format string for the version number
    GetDlgItem(IDC_VERSION)->GetWindowText(sStr);

    // get the FTP Voyager SDK version numbers
    FVSDK_Version(pszVersion, sizeof(pszVersion));

    // build version number string
    m_sVersion.Format(sStr, pszVersion);

    // get the format string for the version number
    GetDlgItem(IDC_STATUS)->GetWindowText(m_sStatusFmt);

    // build version number string
    m_sVersion.Format(sStr, pszVersion);

    // get the format string for the current directory
    GetDlgItem(IDC_CURRENT_DIR)->GetWindowText(m_sCurrentDirFmt);

    // call the base class function
    CDialog::OnInitDialog();

    // set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // make sure we have an allocated session, if not display an error message to the user
    if ((fvecRet = FVSDK_NewSession(&m_pSession)) != FVSDK_OK) {
        CString sMsg;

        // let the user know what the error number is
        sMsg.Format(IDS_SESSION_INITIALIZATION_FAILED_FMT, fvecRet);

        // put the error up in a message box
        MsgBox(sMsg, MB_ICONEXCLAMATION);
    } // if
    else {
        CString sVer, sDate;

        // set the main window handle
        m_pSession->hwndMainWnd = m_hWnd;

        // set the name of our application and version number
        m_pSession->pszAppName = AfxGetAppName();
        m_pSession->pszAppVersion = ((CSampleCPPApp *) AfxGetApp())->GetVersionInfo();

        // get the format string for the FtpTree version number
        GetDlgItem(IDC_FTPTREE_VERSION)->GetWindowText(sStr);

        // get the version number
        if (FVSDK_FtpTreeVersion(m_pSession, pszVersion, sizeof(pszVersion)) == FVSDK_OK)
            sVer.Format(sStr, pszVersion);
        else {
            CString sNA;
            sNA.LoadString(IDS_NA);
            sVer.Format(sStr, sNA);
        } // else

        // set the FtpTree version number in the dialog
        GetDlgItem(IDC_FTPTREE_VERSION)->SetWindowText(sVer);

        // get the format string for the FtpTree build date
        GetDlgItem(IDC_FTPTREE_BUILD_DATE)->GetWindowText(sStr);

        // get the version number
        if (FVSDK_FtpTreeBuildDate(m_pSession, &tmBuildDate) == FVSDK_OK) {
            CTime   BuildTime((1900 + tmBuildDate.tm_year), (tmBuildDate.tm_mon + 1), tmBuildDate.tm_mday,
                                tmBuildDate.tm_hour, tmBuildDate.tm_min, tmBuildDate.tm_sec);

            // get the build date string
            sDate.Format(sStr, BuildTime.Format("%c"));
        } // if
        else {
            CString sNA;
            sNA.LoadString(IDS_NA);
            sDate.Format(sStr, sNA);
        } // else

        // set the FtpTree build date in the dialog
        GetDlgItem(IDC_FTPTREE_BUILD_DATE)->SetWindowText(sDate);

        // setup the log callback
        m_LogList.SetupCallback(m_pSession);

        // setup the dialog callbacks
        m_pSession->pfnDownloadError            = OnDownloadError;
        m_pSession->pvDownloadErrorData         = this;
        m_pSession->pfnUploadError              = OnUploadError;
        m_pSession->pvUploadErrorData           = this;
        m_pSession->pfnNotifyTransferStatus     = OnNotifyTransferStatus;
        m_pSession->pvNotifyTransferStatusData  = this;
    } // else

    // set the status
    SetStatus();

    return (TRUE);  // return TRUE  unless you set the focus to a control
} // OnInitDialog


void CSampleCPPDlg::OnOK()
{
    // release the session if we have one allocated to us
    if (m_pSession) {
        FVSDK_ERROR_CODE    fvecError;

        // don't do anything if the FTP Voyager SDK is working on another operation
        if (CheckBusy())
            return ;

        // release the session, if that fails, manually release it
        if ((fvecError = FVSDK_FreeSession(m_pSession)) != FVSDK_OK) {
            CString sMsg;

            // let the user know what the error number is
            sMsg.Format(IDS_SESSION_FREE_FAILED_FMT, fvecError);

            // put the error up in a message box
            MsgBox(sMsg, MB_ICONEXCLAMATION);

            // release the allocated structure manually, since there was a failure the structure wasn't freed by the DLL
            delete m_pSession;
        } // if

        // clear the pointer
        m_pSession = NULL;
    } // if

    // call the base class function
    CDialog::OnOK();
} // OnOK


void CSampleCPPDlg::OnCancel()
{
    // ESC and X are still there, this function is called, call OnOK() instead
    OnOK();
} // OnCancel


void CSampleCPPDlg::OnBnClickedClearLog()
{
    // clear the log between sessions
    m_LogList.ClearLog();
} // OnBnClickedClearLog

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg callback operations

void CALLBACK CSampleCPPDlg::OnDownloadError(FVSDK_CALLBACK_DATA pvData, long nErr, long nCause, LPCTSTR pszError, LPCTSTR pszRemotePath, LPCTSTR pszDestFileName, LPCTSTR pszExtraInfo)
{
    CString sMsg;

    // build the message
    // for a definition of nErr, refer to FtpTreeErrors.h
    sMsg.Format(IDS_DOWNLOAD_ERROR_FMT, nErr, nCause, pszError, pszRemotePath, pszDestFileName, pszExtraInfo);

    // put up a simple error message
    AfxMessageBox(sMsg, (MB_ICONEXCLAMATION | MB_OK));
} // OnDownloadError


void CALLBACK CSampleCPPDlg::OnUploadError(FVSDK_CALLBACK_DATA pvData, long nErr, long nCause, LPCTSTR pszError, LPCTSTR pszRemotePath, LPCTSTR pszLocalPath)
{
    CString sMsg;

    // build the message
    // for a definition of nErr, refer to FtpTreeErrors.h
    sMsg.Format(IDS_UPLOAD_ERROR_FMT, nErr, nCause, pszError, pszRemotePath, pszLocalPath);

    // put up a simple error message
    AfxMessageBox(sMsg, (MB_ICONEXCLAMATION | MB_OK));
} // OnUploadError


CString FormatDoubleStr(double dVal, int nPrec)
{
    char        buf[512];
    CString     sStr;
    NUMBERFMT   Num;

    // convert to text
    sStr.Format("%.*lf", nPrec, dVal);

    // get locale information
    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, buf, 10);
    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, &buf[10], 10);

    // the number of digits
    Num.NumDigits       = nPrec;
    Num.LeadingZero     = TRUE;
    Num.Grouping        = 3;
    Num.lpDecimalSep    = &buf[10];
    Num.lpThousandSep   = buf;
    Num.NegativeOrder   = 0;

    // convert the string to a readable form
    GetNumberFormat(LOCALE_USER_DEFAULT, 0, sStr, &Num, buf, sizeof(buf));

    // return the formated string
    return (buf);
} // FormatDoubleStr


void CALLBACK CSampleCPPDlg::OnNotifyTransferStatus(FVSDK_CALLBACK_DATA pvData, UINT nStatus, FVSDK_TransferStatus* pTransferStatus)
{
    CSampleCPPDlg*  pThis = (CSampleCPPDlg *) pvData;
    CWnd*           pStatus = pThis->GetDlgItem(IDC_TRANSFER_STATUS);
    CString         sStatus, sOldStatus;

    // nothing to do if we can't get the status control
    if (! pStatus)
        return ;

    // should not be negative
    if (nStatus == FVSDK_TRANSFER_END) {

        // the transfer is done
        sStatus.LoadString(IDS_TRANSFER_DONE);
    } // if
    else {
        CString sStr;
        double  dBytesPerSec = pTransferStatus->dBytesPerSecond;

        // make it a bit easier to read
        if (dBytesPerSec <= 1024.00)
            sStr.LoadString(IDS_BYTES);
        else if ((dBytesPerSec /= (double) 1024.00) < 1024.00)
            sStr.LoadString(IDS_KB);
        else {
            sStr.LoadString(IDS_MB);
            dBytesPerSec /= 1024.00;
        } // else 

        // build a string with the transfer rate and time remaining
        sStatus.Format(IDS_TIME_FMT, pTransferStatus->dwRemainingHours, pTransferStatus->dwRemainingMinutes,
                        pTransferStatus->dwRemainingSeconds, FormatDoubleStr(dBytesPerSec, 2), (LPCTSTR) sStr);
    } // else

    // get the current status
    pStatus->GetWindowText(sOldStatus);

    // update the display only if it's changed
    if (sStatus != sOldStatus)
        pStatus->SetWindowText(sStatus);
} // OnNotifyTransferStatus

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg connection operations

void CSampleCPPDlg::OnBnClickedConnect()
{
    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return ;

    // copy the fields from the dialog, then connect
    if (UpdateData()) {

        // set the status
        SetStatus(SAMPLE_CONNECTING);

        // clear the log between sessions
        m_LogList.ClearLog();

        // copy variables to the dialog
        m_pSession->pszServer               = (LPCTSTR) m_sServer;
        m_pSession->nPort                   = m_nPort;
        m_pSession->pszUserID               = (LPCTSTR) m_sUserID;
        m_pSession->pszPassword             = (LPCTSTR) m_sPassword;

        // extra parameters from the sample application
        m_pSession->bPasv                   = m_bPASV;
        m_pSession->bShowRawListings        = m_bShowRawListings;
        m_pSession->bShowTransferDialogs    = m_bXferDialogs;

        // try to connect to the server
        FVSDK_ERROR_CODE fvecRet = FVSDK_Connect(m_pSession);

        // set the current status
        SetStatus();

        // display an error message if we were unable to connect
        if (fvecRet != FVSDK_OK) {

            // display an error message if the operation was not stopped or canceled
            MsgBox(IDS_UNABLE_TO_CONNECT, MB_ICONEXCLAMATION);
        } // if
    } // if
    else
        MsgBox(IDS_UNABLE_TO_COPY_FROM_DIALOG, MB_ICONEXCLAMATION);
} // OnBnClickedConnect


void CSampleCPPDlg::OnBnClickedDisconnect()
{
    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return ;

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return ;

    // set the status
    SetStatus(SAMPLE_DISCONNECTING);

    // disconnect
    FVSDK_Disconnect(m_pSession);

    // set the current status
    SetStatus();
} // OnBnClickedDisconnect

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg directory operations

void CSampleCPPDlg::OnBnClickedCwd()
{
    CString sDirName;

    // get the directory name from the user
    if (GetFileName(sDirName)) {

        // try changing to the specified directory, put up an error if it fails
        if (FVSDK_SetCurrentDirectory(m_pSession, sDirName) != FVSDK_YES)
            MsgBox(IDS_UNABLE_TO_SET_CURRENT_DIRECTORY);
        else
            SetStatus();
    } // if
} // OnBnClickedCwd


void CSampleCPPDlg::OnBnClickedRmd()
{
    CString sDirName;

    // get the directory name from the user
    if (GetFileName(sDirName)) {

        // try removing the specified directory, put up an error if it fails
        if (FVSDK_RemoveDirectory(m_pSession, sDirName) != FVSDK_YES)
            MsgBox(IDS_UNABLE_TO_REMOVE_DIRECTORY);
        else
            SetStatus();
    } // if
} // OnBnClickedRmd


void CSampleCPPDlg::OnBnClickedMkd()
{
    CString sDirName;

    // get the directory name from the user
    if (GetFileName(sDirName)) {

        // try creating the specified directory, put up an error if it fails
        if (FVSDK_CreateDirectory(m_pSession, sDirName) != FVSDK_YES)
            MsgBox(IDS_UNABLE_TO_CREATE_DIRECTORY);
        else
            SetStatus();
    } // if
} // OnBnClickedMkd


void CSampleCPPDlg::OnBnClickedCdup()
{
    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return ;

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return ;

    // try going up one directory, put up an error if it fails
    if (FVSDK_UpOneDirectory(m_pSession) != FVSDK_YES)
        MsgBox(IDS_UNABLE_TO_MOVE_UP_ONE_DIRECTORY);
    else
        SetStatus();
} // OnBnClickedCdup

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg misc. operations

void CSampleCPPDlg::OnBnClickedStop()
{
    // stop any operation that may be going on
    FVSDK_Stop(m_pSession);
} // OnBnClickedStop


void CSampleCPPDlg::OnBnClickedLastResponse()
{
    char    pszBuffer[128];
    int     nIndex = 0;
    CString sResponse;

    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return ;

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return ;

    // get responses to the last command
    while (FVSDK_GetLastResponse(m_pSession, nIndex++, pszBuffer, sizeof(pszBuffer)) == FVSDK_OK) {

        // add the response to the message string
        sResponse += pszBuffer;

        // add a <CR><LF> for formatting
        sResponse += "\r\n";
    } // while

    // show the last full response in a message box
    MsgBox(sResponse, (MB_ICONINFORMATION | MB_OK));
} // OnBnClickedLastResponse


void CSampleCPPDlg::OnBnClickedWelcomeMessage()
{
    char    pszBuffer[128];
    int     nIndex = 0;
    CString sWelcomeMessage;

    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return ;

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return ;

    // get the welcome message sent by the server when we connected
    while (FVSDK_GetWelcomeMessage(m_pSession, nIndex++, pszBuffer, sizeof(pszBuffer)) == FVSDK_OK) {

        // add the welcome message string to the message string
        sWelcomeMessage += pszBuffer;

        // add a <CR><LF> for formatting
        sWelcomeMessage += "\r\n";
    } // while

    // show the last full welcome message in a message box
    MsgBox(sWelcomeMessage, (MB_ICONINFORMATION | MB_OK));
} // OnBnClickedWelcomeMessage


void CSampleCPPDlg::OnBnClickedSendCommand()
{
    CGetCommandDlg  Dlg;

    // don't do anything if the FTP Voyager SDK is working on another operation
    if (CheckBusy())
        return ;

    // don't do anything if we're not connected
    if (CheckNotConnected())
        return ;

    // fill in the default
    Dlg.SetCommand("HELP");

    // ask the user for the command
    if ((Dlg.DoModal() == IDOK) && (! Dlg.GetCommand().IsEmpty())) {
        int     nResp;
        CString sMsg;

        // send a command to the server
        if (FVSDK_SendCommand(m_pSession, Dlg.GetCommand(), &nResp) == FVSDK_OK) {

            // format a message for the user
            sMsg.Format(IDS_COMMAND_RESP_FMT, nResp, Dlg.GetCommand());

            // put up a message box telling the user what happened
            MsgBox(sMsg, (MB_ICONINFORMATION | MB_OK));
        } // if
        else {

            // build the message
            sMsg.Format(IDS_ERROR_SENDING_COMMAND_FMT, Dlg.GetCommand());

            // put up an error message
            MsgBox(sMsg, (MB_ICONEXCLAMATION | MB_OK));
        } // else
    } // if
} // OnBnClickedSendCommand

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg apply session settings

void CSampleCPPDlg::OnBnClickedPasv()
{
    // copy from the dialog
    if (UpdateData()) {

        // change the PASV setting in the session
        m_pSession->bPasv = m_bPASV;

        // apply the session changes
        // NOTE: in "normal" applications it is best to make many changes to the
        // session structure, then call this function.  For demonstration purposes
        // only one setting is being changed here.
        FVSDK_ApplySessionChange(m_pSession);
    } // if
} // OnBnClickedPasv


void CSampleCPPDlg::OnBnClickedRaw()
{
    // copy from the dialog
    if (UpdateData()) {

        // show raw listings in the log?
        m_pSession->bShowRawListings = m_bShowRawListings;

        // apply the session changes
        // NOTE: in "normal" applications it is best to make many changes to the
        // session structure, then call this function.  For demonstration purposes
        // only one setting is being changed here.
        FVSDK_ApplySessionChange(m_pSession);
    } // if
} // OnBnClickedRaw


void CSampleCPPDlg::OnBnClickedXferDialogs()
{
    // copy from the dialog
    if (UpdateData()) {

        // show transfer dialogs
        m_pSession->bShowTransferDialogs = m_bXferDialogs;

        // apply the session changes
        // NOTE: in "normal" applications it is best to make many changes to the
        // session structure, then call this function.  For demonstration purposes
        // only one setting is being changed here.
        FVSDK_ApplySessionChange(m_pSession);
    } // if
} // OnBnClickedXferDialogs

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg directory listing

void CSampleCPPDlg::OnBnClickedListDir()
{
    // make sure we're not busy and we're connected
    if ((! CheckBusy()) && (! CheckNotConnected())) {

        // find the file or files in the current directory
        if (FVSDK_FindFile(m_pSession, "*") == FVSDK_YES) {
            FVSDK_ERROR_CODE    fvecRet;
            FVSDK_FileInfo      FileInfo;

            // initialize the file info structure
            FileInfo.nVersion   = FVSDK_FILE_INFO_CURRENT_VERSION;
            FileInfo.nSize      = sizeof(FileInfo);

            // find each of the files in the current directory all
            do {

                // get the current file information and move to the next file
                fvecRet = FVSDK_FindNextFile(m_pSession, &FileInfo);

            } while ((fvecRet == FVSDK_YES) && (! LastOperationStopped()));
        } // if

        // close the file find operation
        FVSDK_FindFileClose(m_pSession);
    } // if
} // OnBnClickedListDir

/////////////////////////////////////////////////////////////////////////////
// CSampleCPPDlg file transfer

void CSampleCPPDlg::OnBnClickedDownload()
{
    CString sSourcePath, sDestPath;

    // as the user for the file (or wild card) to download
    if (GetFileName(sSourcePath)) {

        // ask the user where it should be downloaded
        if (GetLocalFileName(sDestPath)) {

            // download the file
            FVSDK_Download(m_pSession, sSourcePath, sDestPath);
        } // if
    } // if
} // OnBnClickedDownload


void CSampleCPPDlg::OnBnClickedMoveDown()
{
    CString sSourcePath, sDestPath;

    // as the user for the file (or wild card) to download
    if (GetFileName(sSourcePath)) {

        // ask the user where it should be downloaded
        if (GetLocalFileName(sDestPath)) {

            // move the file down
            FVSDK_MoveDown(m_pSession, sSourcePath, sDestPath);
        } // if
    } // if
} // OnBnClickedMoveDown


void CSampleCPPDlg::OnBnClickedUpload()
{
    CString sSourcePath, sDestPath;

    // as the user for the file (or wild card) to upload
    if (GetLocalFileName(sSourcePath)) {

        // ask the user where it should be uploaded
        if (GetFileName(sDestPath)) {

            // upload the file
            FVSDK_Upload(m_pSession, sSourcePath, sDestPath);
        } // if
    } // if
} // OnBnClickedUpload


void CSampleCPPDlg::OnBnClickedMoveUp()
{
    CString sSourcePath, sDestPath;

    // as the user for the file (or wild card) to upload
    if (GetLocalFileName(sSourcePath)) {

        // ask the user where it should be uploaded
        if (GetFileName(sDestPath)) {

            // move the file up
            FVSDK_MoveUp(m_pSession, sSourcePath, sDestPath);
        } // if
    } // if
} // OnBnClickedMoveUp


void CSampleCPPDlg::OnBnClickedDeleteFile()
{
    CString sPathName;

    // get the file name from the user
    if (GetFileName(sPathName)) {

        // try removing the specified file, put up an error if it fails
        if (FVSDK_RemoveFile(m_pSession, sPathName) != FVSDK_YES)
            MsgBox(IDS_UNABLE_TO_REMOVE_FILE, MB_ICONEXCLAMATION);
    } // if
} // OnBnClickedDeleteFile


void CSampleCPPDlg::OnBnClickedRename()
{
    CString sOldPathName, sNewPathName;

    // as the user for the old file path name
    if (GetFileName(sOldPathName)) {

        // ask the new file path name
        if (GetFileName(sNewPathName)) {

            // rename the file or directory
            if (FVSDK_Rename(m_pSession, sOldPathName, sNewPathName) != FVSDK_YES)
                MsgBox(IDS_UNABLE_TO_RENAME, MB_ICONEXCLAMATION);
        } // if
    } // if
} // OnBnClickedRename


CString FormatIntStr(FVSDK_FILE_SIZE fsNum)
{
    char        buf[512];
    CString     sStr;
    NUMBERFMT   Num;

    // convert to text
    sStr.Format("%I64d", fsNum);

    // get locale information
    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, buf, 10);
    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, &buf[10], 10);

    // the number of digits
    Num.NumDigits       = 0;
    Num.LeadingZero     = 0;
    Num.Grouping        = 3;
    Num.lpDecimalSep    = &buf[10];
    Num.lpThousandSep   = buf;
    Num.NegativeOrder   = 0;

    // convert the string to a readable form
    GetNumberFormat(LOCALE_USER_DEFAULT, 0, sStr, &Num, buf, sizeof(buf));

    // return the formated string
    return (buf);
} // FormatIntStr


void CSampleCPPDlg::OnBnClickedSize()
{
    CString sPathName;

    // get the file name from the user
    if (GetFileName(sPathName)) {
        FVSDK_FILE_SIZE FileSize;

        // get the file size from the server
        if (FVSDK_Size(m_pSession, sPathName, &FileSize) != FVSDK_YES)
            MsgBox(IDS_UNABLE_TO_GET_SIZE, MB_ICONEXCLAMATION);
        else {
            CString sMsg;

            // build a message to display to the user
            sMsg.Format("The file size is %s bytes.", FormatIntStr(FileSize));

            // display a message to the user
            MsgBox(sMsg, MB_ICONINFORMATION);
        } // else
    } // if
} // OnBnClickedSize


void CSampleCPPDlg::OnBnClickedFileUpload()
{
    CString sPathName;

    // get the file name from the user
    if (GetLocalFileName(sPathName)) {
        CStdioFile  File;

        // use try / catch to catch any local file errors
        try {

            // open the local file
            if (File.Open(sPathName, (CFile::modeRead | CFile::typeBinary | CFile::shareDenyWrite))) {
                CString         sRemoteName = sPathName;
                int             nPos;
                FVSDK_FILE_SIZE fsLocalFileSize = File.GetLength();

                // get just the file name, removing any path information
                if ((nPos = sRemoteName.ReverseFind('\\')) >= 0)
                    sRemoteName = sRemoteName.Mid(nPos + 1);

                // get the file name from the user
                if (GetFileName(sRemoteName, sRemoteName)) {

                    // attempt to open the file to be uploaded
                    if (FVSDK_CreateFile(m_pSession, sRemoteName, TRUE, 0) == FVSDK_YES) {
                        BYTE            Buffer[1024];
                        int             nBytes;
                        FVSDK_FILE_SIZE fsWritten = 0;

                        // read all of the data from the local file, and write it to the remote file
                        while ((nBytes = File.Read(Buffer, sizeof(Buffer))) > 0) {

                            // do the write
                            if (FVSDK_WriteFile(m_pSession, Buffer, &nBytes, ((nBytes + fsWritten) >= fsLocalFileSize)) != FVSDK_YES) {

                                // put up an error message
                                MsgBox(IDS_UNABLE_TO_WRITE_TO_FILE, MB_ICONEXCLAMATION);

                                // get out
                                break;
                            } // if

                            // increment the number of bytes written to the file
                            fsWritten += nBytes;
                        } // while

                        // close the remote file
                        if (FVSDK_CloseFile(m_pSession) != FVSDK_YES)
                            MsgBox(IDS_UNABLE_TO_CLOSE_FILE, MB_ICONEXCLAMATION);
                        else {
                            CFileStatus Status;

                            // get the status of the local file, then set the date and time of the remote file
                            if (File.GetStatus(Status)) {
                                tm  tmLocalTime;

                                // get the last time the file was modified
                                Status.m_mtime.GetLocalTm(&tmLocalTime);

                                // set the date and time of the remote file, put up an error if it fails
                                if (FVSDK_SetFileDateAndTime(m_pSession, sRemoteName, &tmLocalTime) != FVSDK_YES)
                                    MsgBox(IDS_UNABLE_TO_SET_REMOTE_FILE_DATE_TIME, MB_ICONEXCLAMATION);
                            } // if
                        } // else
                    } // if
                    else
                        MsgBox(IDS_UNABLE_TO_CREATE_FILE, MB_ICONEXCLAMATION);
                } // if

                // close the local file
                File.Close();
            } // if
            else
                MsgBox(IDS_UNABLE_TO_OPEN_LOCAL_FILE, MB_ICONEXCLAMATION);
        } // try
        catch (CFileException* pEx) {
            char    pszError[1024];

            // get the error message
            pEx->GetErrorMessage(pszError, sizeof(pszError));

            // put up a message about the local file error
            AfxMessageBox(pszError);

            // close the remote file
            FVSDK_CloseFile(m_pSession);

            // release the exception
            pEx->Delete();
        } // catch
    } // if
} // OnBnClickedFileUpload


void CSampleCPPDlg::OnBnClickedFileDownload()
{
    CString sPathName;

    // get the file name from the user
    if (GetFileName(sPathName)) {
        CString     sLocalName = sPathName;
        int         nPos;

        // get just the file name, removing any path information
        if ((nPos = sLocalName.ReverseFind('/')) >= 0)
            sLocalName = sLocalName.Mid(nPos + 1);

        // create what is probably a good local file name
        if ((nPos = m_sLocalFileName.ReverseFind('\\')) >= 0)
            m_sLocalFileName = (m_sLocalFileName.Left(nPos + 1) + sLocalName);

        // get the local file name
        if (GetLocalFileName(sLocalName)) {
            CStdioFile  File;

            // use try / catch to catch any local file errors
            try {

                // create the local file
                if (File.Open(sLocalName, (CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite))) {

                    // attempt to open the file to be downloaded
                    if (FVSDK_OpenFile(m_pSession, sPathName, TRUE, 0) == FVSDK_YES) {
                        BYTE    Buffer[1024];
                        int     nBytes = sizeof(Buffer);

                        // read all of the data from the remote file, and write it to the local file
                        while (FVSDK_ReadFile(m_pSession, Buffer, &nBytes) == FVSDK_YES) {

                            // write the data to the local file
                            File.Write(Buffer, nBytes);

                            // reset the buffer size
                            nBytes = sizeof(Buffer);
                        } // while

                        // close the remote file
                        if (FVSDK_CloseFile(m_pSession) != FVSDK_YES)
                            MsgBox(IDS_UNABLE_TO_CLOSE_FILE, MB_ICONEXCLAMATION);
                    } // if
                    else
                        MsgBox(IDS_UNABLE_TO_OPEN_FILE, MB_ICONEXCLAMATION);

                    // close the local file
                    File.Close();
                } // if
                else
                    MsgBox(IDS_UNABLE_TO_CREATE_LOCAL_FILE, MB_ICONEXCLAMATION);
            } // try
            catch (CFileException* pEx) {
                char    pszError[1024];

                // get the error message
                pEx->GetErrorMessage(pszError, sizeof(pszError));

                // put up a message about the local file error
                AfxMessageBox(pszError);

                // close the remote file
                FVSDK_CloseFile(m_pSession);

                // release the exception
                pEx->Delete();
            } // catch
        } // if
    } // if
} // OnBnClickedFileDownload


void CSampleCPPDlg::OnBnClickedEditFile()
{
    CString sPathName;

    // get the file name from the user
    if (GetFileName(sPathName)) {

        // perform a remote file edit
        FVSDK_RemoteEdit(m_pSession, sPathName);
    } // if
} // OnBnClickedEditFile


void CSampleCPPDlg::OnBnClickedViewFile()
{
    CString sPathName;

    // get the file name from the user
    if (GetFileName(sPathName)) {

        // perform a remote file view
        FVSDK_RemoteView(m_pSession, sPathName);
    } // if
} // OnBnClickedViewFile


void CSampleCPPDlg::OnBnClickedFindFiles()
{
    CString sPathName;

    // get the file name from the user
    if (GetFileName(sPathName)) {

        // do the find files dialog
        FVSDK_FindFilesDialog(m_pSession, sPathName);
    } // if
} // OnBnClickedFindFiles


void CSampleCPPDlg::OnBnClickedSyncFolders()
{
    CString sRemoteDir;

    // get the file name from the user
    if (GetFileName(sRemoteDir)) {
        CString sLocalDir;

        // get the local file name
        if (GetLocalFileName(sLocalDir)) {
            DWORD   dwSyncOptions = 0;

            // set the synchronize folders options
            dwSyncOptions |= FVSDK_SYNCOPT_IGNORECASE;
            dwSyncOptions |= FVSDK_SYNCOPT_COMPARESIZE;
            dwSyncOptions |= FVSDK_SYNCOPT_COMPARETIME;
            dwSyncOptions |= FVSDK_SYNCOPT_INCLUDEDIRS;
            dwSyncOptions |= FVSDK_SYNCOPT_DONTDELETE;
            dwSyncOptions |= FVSDK_SYNCOPT_OVERWRITECONFIRMATIONS;
            dwSyncOptions |= FVSDK_SYNCOPT_DELETECONFIRMATIONS;
            dwSyncOptions |= FVSDK_SYNCOPT_REMOTEIGNOREOLDER;
            dwSyncOptions |= FVSDK_SYNCOPT_LOCALIGNORENEWER;
            dwSyncOptions |= FVSDK_SYNCOPT_QUEUEERRORMESSAGES;
            dwSyncOptions |= FVSDK_SYNCOPT_USEDIALOG;

            // do the sync folders
            FVSDK_SyncFolders(m_pSession, sRemoteDir, sLocalDir, dwSyncOptions, "", 1);
        } // if
    } // if
} // OnBnClickedSyncFolders