CFtpConnection.cls
上传用户:nicktai
上传日期:2010-01-26
资源大小:40k
文件大小:73k
源码类别:

Ftp服务器

开发平台:

Visual Basic

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "CFtpConnection"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. '********************************************************************************
  15. 'CFtpConnection class
  16. 'Copyright 2000 by Oleg Gdalevich
  17. 'Visual Basic Internet Programming website (http://www.vbip.com)
  18. '********************************************************************************
  19. 'To use this class module you need:
  20. '   CFtpFile    class module
  21. '   CFtpFiles   calss module
  22. '   CTimeout    class module
  23. '   MFtpSupport module
  24. '
  25. '   Also you need to set up the refernce to Winsock ActiveX Control
  26. '   via REFERENCES dialog window. To do this, open Project References
  27. '   dialog, click Browse button and select Mswinsck.ocx
  28. '
  29. '********************************************************************************
  30. 'Declarations of winsock objects.
  31. '********************************************************************************
  32. 'Winsock Control for control connection
  33. Private WithEvents wscControl As MSWinsockLib.Winsock
  34. Attribute wscControl.VB_VarHelpID = -1
  35. 'Winsock Control for data connection
  36. Private WithEvents wscData As MSWinsockLib.Winsock
  37. Attribute wscData.VB_VarHelpID = -1
  38. '********************************************************************************
  39. 'Local variables to hold values of the class properies
  40. '********************************************************************************
  41. Private m_strUserName           As String
  42. Private m_strPassword           As String
  43. Private m_varFtpServer          As Variant
  44. Private m_strCurrentDirectory   As String
  45. Private m_bPassiveMode          As Boolean
  46. Private m_bBusy                 As Boolean
  47. Private m_intTimeout            As Integer
  48. Private m_TransferMode          As FtpTransferModes
  49. '********************************************************************************
  50. 'Public Enums
  51. '********************************************************************************
  52. 'various states of ftp connection
  53. Public Enum FTP_CONNECTION_STATES
  54.     FTP_CONNECTION_RESOLVING_HOST
  55.     FTP_CONNECTION_HOST_RESOLVED
  56.     FTP_CONNECTION_CONNECTED
  57.     FTP_CONNECTION_AUTHENTICATION
  58.     FTP_USER_LOGGED
  59.     FTP_ESTABLISHING_DATA_CONNECTION
  60.     FTP_DATA_CONNECTION_ESTABLISHED
  61.     FTP_RETRIEVING_DIRECTORY_INFO
  62.     FTP_DIRECTORY_INFO_COMPLETED
  63.     FTP_TRANSFER_STARTING
  64.     FTP_TRANSFER_COMLETED
  65. End Enum
  66. 'all possible reply codes that can be sent by ftp server
  67. Private Enum FTP_RESPONSE_CODES
  68.     FTP_RESPONSE_RESTATRT_MARKER_REPLY = 110
  69.     FTP_RESPONSE_SERVICE_READY_IN_MINUTES = 120
  70.     FTP_RESPONSE_DATA_CONNECTION_ALREADY_OPEN = 125
  71.     FTP_RESPONSE_FILE_STATUS_OK = 150
  72.     FTP_RESPONSE_COMMAND_OK = 200
  73.     FTP_RESPONSE_COMMAND_NOT_IMPLEMENTED_SUPERFLUOUS_AT_THIS_SITE = 202 'superfluous at this site
  74.     FTP_RESPONSE_SYSTEM_STATUS_OR_SYSTEM_HELP_REPLY = 211
  75.     FTP_RESPONSE_DIRECTORY_STATUS = 212
  76.     FTP_RESPONSE_FILE_STATUS = 213
  77.     FTP_RESPONSE_HELP_MESSAGE = 214
  78.     FTP_RESPONSE_NAME_SYSTEM_TYPE = 215
  79.     FTP_RESPONSE_SERVICE_READY_FOR_NEW_USER = 220
  80.     FTP_RESPONSE_SERVICE_CLOSING_CONTROL_CONNECTION = 221
  81.     FTP_RESPONSE_DATA_CONNECTION_OPEN = 225
  82.     FTP_RESPONSE_CLOSING_DATA_CONNECTION = 226
  83.     FTP_RESPONSE_ENTERING_PASSIVE_MODE = 227
  84.     FTP_RESPONSE_USER_LOGGED_IN = 230
  85.     FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED = 250
  86.     FTP_RESPONSE_PATHNAME_CREATED = 257
  87.     FTP_RESPONSE_USER_NAME_OK_NEED_PASSWORD = 331
  88.     FTP_RESPONSE_NEED_ACCOUNT_FOR_LOGIN = 332
  89.     FTP_RESPONSE_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFO = 350
  90.     FTP_RESPONSE_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION = 421
  91.     FTP_RESPONSE_CANNOT_OPEN_DATA_CONNECTION = 425
  92.     FTP_RESPONSE_CONNECTION_CLOSED_TRANSFER_ABORTED = 426
  93.     FTP_RESPONSE_REQUESTED_FILE_ACTION_NOT_TAKEN = 450
  94.     FTP_RESPONSE_REQUESTED_ACTION_ABORTED = 451
  95.     FTP_RESPONSE_REQUESTED_ACTION_NOT_TAKEN = 452
  96.     FTP_RESPONSE_SYNTAX_ERROR_COMMAND_UNRECOGNIZED = 500
  97.     FTP_RESPONSE_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS = 501
  98.     FTP_RESPONSE_COMMAND_NOT_IMPLEMENTED = 502
  99.     FTP_RESPONSE_BAD_SEQUENCE_OF_COMMANDS = 503
  100.     FTP_RESPONSE_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER = 504
  101.     FTP_RESPONSE_NOT_LOGGED_IN = 530
  102.     FTP_RESPONSE_NEED_ACCOUNT_FOR_STORING_FILES = 532
  103.     FTP_RESPONSE_REQUESTED_ACTION_NOT_TAKEN_FILE_UNAVAILABLE = 550
  104.     FTP_RESPONSE_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN = 551
  105.     FTP_RESPONSE_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE_ALLOCATION = 552
  106.     FTP_RESPONSE_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED = 553
  107. End Enum
  108. 'transfer modes
  109. Public Enum FtpTransferModes
  110.     FTP_ASCII_MODE
  111.     FTP_IMAGE_MODE
  112. End Enum
  113. '********************************************************************************
  114. 'Class errors
  115. '********************************************************************************
  116. Public Enum FtpErrors
  117.     ERROR_FTP_WINSOCK_AddressInUse
  118.     ERROR_FTP_WINSOCK_AddressNotAvailable
  119.     ERROR_FTP_WINSOCK_AlreadyComplete
  120.     ERROR_FTP_WINSOCK_AlreadyConnected
  121.     ERROR_FTP_WINSOCK_BadState
  122.     ERROR_FTP_WINSOCK_ConnectAborted
  123.     ERROR_FTP_WINSOCK_ConnectionRefused
  124.     ERROR_FTP_WINSOCK_ConnectionReset
  125.     ERROR_FTP_WINSOCK_GetNotSupported
  126.     ERROR_FTP_WINSOCK_HostNotFound
  127.     ERROR_FTP_WINSOCK_HostNotFoundTryAgain
  128.     ERROR_FTP_WINSOCK_InProgress
  129.     ERROR_FTP_WINSOCK_InvalidArg
  130.     ERROR_FTP_WINSOCK_InvalidArgument
  131.     ERROR_FTP_WINSOCK_InvalidOp
  132.     ERROR_FTP_WINSOCK_InvalidPropertyValue
  133.     ERROR_FTP_WINSOCK_MsgTooBig
  134.     ERROR_FTP_WINSOCK_NetReset
  135.     ERROR_FTP_WINSOCK_NetworkSubsystemFailed
  136.     ERROR_FTP_WINSOCK_NetworkUnreachable
  137.     ERROR_FTP_WINSOCK_NoBufferSpace
  138.     ERROR_FTP_WINSOCK_NoData
  139.     ERROR_FTP_WINSOCK_NonRecoverableError
  140.     ERROR_FTP_WINSOCK_NotConnected
  141.     ERROR_FTP_WINSOCK_NotInitialized
  142.     ERROR_FTP_WINSOCK_NotSocket
  143.     ERROR_FTP_WINSOCK_OpCanceled
  144.     ERROR_FTP_WINSOCK_OutOfMemory
  145.     ERROR_FTP_WINSOCK_OutOfRange
  146.     ERROR_FTP_WINSOCK_PortNotSupported
  147.     ERROR_FTP_WINSOCK_SetNotSupported
  148.     ERROR_FTP_WINSOCK_SocketShutdown
  149.     ERROR_FTP_WINSOCK_Success
  150.     ERROR_FTP_WINSOCK_Timedout
  151.     ERROR_FTP_WINSOCK_Unsupported
  152.     ERROR_FTP_WINSOCK_WouldBlock
  153.     ERROR_FTP_WINSOCK_WrongProtocol
  154.     ERROR_FTP_PROTOCOL_SERVICE_READY_IN_MINUTES
  155.     ERROR_FTP_PROTOCOL_USER_NAME_OK_NEED_PASSWORD
  156.     ERROR_FTP_PROTOCOL_NEED_ACCOUNT_FOR_LOGIN
  157.     ERROR_FTP_PROTOCOL_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFO
  158.     ERROR_FTP_PROTOCOL_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION
  159.     ERROR_FTP_PROTOCOL_CANNOT_OPEN_DATA_CONNECTION
  160.     ERROR_FTP_PROTOCOL_CONNECTION_CLOSED_TRANSFER_ABORTED
  161.     ERROR_FTP_PROTOCOL_REQUESTED_FILE_ACTION_NOT_TAKEN
  162.     ERROR_FTP_PROTOCOL_REQUESTED_ACTION_ABORTED
  163.     ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN
  164.     ERROR_FTP_PROTOCOL_SYNTAX_ERROR_COMMAND_UNRECOGNIZED
  165.     ERROR_FTP_PROTOCOL_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS
  166.     ERROR_FTP_PROTOCOL_COMMAND_NOT_IMPLEMENTED
  167.     ERROR_FTP_PROTOCOL_BAD_SEQUENCE_OF_COMMANDS
  168.     ERROR_FTP_PROTOCOL_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER
  169.     ERROR_FTP_PROTOCOL_NOT_LOGGED_IN
  170.     ERROR_FTP_PROTOCOL_NEED_ACCOUNT_FOR_STORING_FILES
  171.     ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN_FILE_UNAVAILABLE
  172.     ERROR_FTP_PROTOCOL_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN
  173.     ERROR_FTP_PROTOCOL_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE_ALLOCATION
  174.     ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED
  175.     ERROR_FTP_USER_TIMEOUT
  176.     ERROR_FTP_USER_TRANSFER_IN_PROGRESS
  177. End Enum
  178. '********************************************************************************
  179. 'Class events
  180. '********************************************************************************
  181. Public Event StateChanged(State As FTP_CONNECTION_STATES)
  182. Public Event DownloadProgress(lBytes As Long)
  183. Public Event UploadProgress(lBytes As Long)
  184. '********************************************************************************
  185. 'Service constants and variables used inside the class
  186. '********************************************************************************
  187. Const RESPONSE_CODE_LENGHT = 3
  188. Private m_LastError             As FtpErrors
  189. Private m_strLastErrorDesc      As String
  190. Private m_strWinsockBuffer      As String
  191. Private m_strDataBuffer         As String
  192. Private m_strLocalFilePath      As String
  193. Private m_intLocalFileID        As Integer
  194. Private m_bTransferInProgress   As Boolean
  195. Private m_lDownloadedBytes      As Long
  196. Private m_bUploadFile           As Boolean
  197. Private m_lUploadedBytes        As Long
  198. Private m_strLastServerResponse As String
  199. Private m_objTimeOut            As CTimeout
  200. Private m_bFileIsOpened         As Boolean
  201. '
  202. Public Function FtpGetLastError() As FtpErrors
  203.     FtpGetLastError = m_LastError
  204. End Function
  205. Public Function CurrentDirectory() As String
  206.     CurrentDirectory = m_strCurrentDirectory
  207. End Function
  208. Public Function GetLastServerResponse() As String
  209.     GetLastServerResponse = m_strLastServerResponse
  210. End Function
  211. Public Property Get TransferMode() As FtpTransferModes
  212.     TransferMode = m_TransferMode
  213. End Property
  214. Public Property Let TransferMode(NewValue As FtpTransferModes)
  215.     
  216.     m_bBusy = True
  217.     If Not (NewValue = m_TransferMode) Then
  218.         If ProcessTYPECommand(NewValue) Then
  219.             m_TransferMode = NewValue
  220.         End If
  221.     End If
  222.     m_bBusy = False
  223. End Property
  224. Private Function ProcessLISTCommand() As Boolean
  225. '********************************************************************************
  226. 'Author      :Oleg Gdalevich
  227. 'Date/Time   :07.01.00
  228. 'Purpose     :
  229. '********************************************************************************
  230. On Error GoTo ProcessLISTCommand_Err_Handler
  231.     Dim strResponse As String
  232.     Dim strData     As String
  233.     wscControl.SendData "LIST" & vbCrLf
  234.     Debug.Print "LIST"
  235.     
  236.     m_objTimeOut.StartTimer
  237.     Do
  238.         DoEvents
  239.         '
  240.         If m_objTimeOut.Timeout Then
  241.             m_LastError = ERROR_FTP_USER_TIMEOUT
  242.             Exit Do
  243.         End If
  244.         '
  245.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  246.             If GetResponseCode(m_strWinsockBuffer) = 150 Or _
  247.                 GetResponseCode(m_strWinsockBuffer) = 125 Then
  248.                 'ignore 150 reply code
  249.                 m_strWinsockBuffer = Mid$(m_strWinsockBuffer, InStr(1, m_strWinsockBuffer, vbCrLf) + 2)
  250.             Else
  251.                 strData = m_strWinsockBuffer
  252.                 m_strWinsockBuffer = ""
  253.                 Exit Do
  254.             End If
  255.         End If
  256.     Loop
  257.     m_objTimeOut.StopTimer
  258.     
  259.     If GetResponseCode(strData) = FTP_RESPONSE_CLOSING_DATA_CONNECTION Or _
  260.         GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  261.         
  262.         ProcessLISTCommand = True
  263.     Else
  264.         ProcessFtpResponse GetResponseCode(strData)
  265.     End If
  266.     
  267. Exit_Label:
  268.     Exit Function
  269. ProcessLISTCommand_Err_Handler:
  270.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  271.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessLISTCommand", Err.Description
  272.     End If
  273.     GoTo Exit_Label
  274.     
  275. End Function
  276. Public Property Get PassiveMode() As Boolean
  277.     PassiveMode = m_bPassiveMode
  278. End Property
  279. Public Property Let PassiveMode(NewValue As Boolean)
  280.     m_bPassiveMode = NewValue
  281. End Property
  282. Public Function EnumFiles(oFiles As CFtpFiles) As Boolean
  283. '********************************************************************************
  284. 'Author      :Oleg Gdalevich
  285. 'Date/Time   :07.01.00
  286. 'Purpose     :Enumerates the files and dirs in the current directory
  287. '********************************************************************************
  288. Dim bDataConnectionEstablished As Boolean
  289. 'On Error GoTo EnumFiles_Err_Handler
  290.     m_bBusy = True
  291.     If m_bPassiveMode Then
  292.         'send PASV command
  293.         bDataConnectionEstablished = ProcessPASVCommand
  294.     Else
  295.         'send PORT command
  296.         bDataConnectionEstablished = ProcessPORTCommand
  297.     End If 'm_bPassiveMode
  298.     '
  299.     If bDataConnectionEstablished Then
  300.         RaiseEvent StateChanged(FTP_RETRIEVING_DIRECTORY_INFO)
  301.         If ProcessLISTCommand Then
  302.             m_objTimeOut.StartTimer
  303.             Do
  304.                 DoEvents
  305.                 '
  306.                 If m_objTimeOut.Timeout Then
  307.                     m_LastError = ERROR_FTP_USER_TIMEOUT
  308.                     If GetResponseCode(Left(m_strLastServerResponse, 3)) = FTP_RESPONSE_CLOSING_DATA_CONNECTION Then
  309.                         Set oFiles = GetFileList(m_strDataBuffer)
  310.                         EnumFiles = True
  311.                         RaiseEvent StateChanged(FTP_DIRECTORY_INFO_COMPLETED)
  312.                         m_strDataBuffer = ""
  313.                     End If
  314.                     Exit Do
  315.                 End If
  316.                 '
  317.                 If wscData.State = sckClosing Or wscData.State = sckClosed Then
  318.                     Set oFiles = Nothing
  319.                     Set oFiles = GetFileList(m_strDataBuffer)
  320.                     EnumFiles = True
  321.                     RaiseEvent StateChanged(FTP_DIRECTORY_INFO_COMPLETED)
  322.                     m_strDataBuffer = ""
  323.                     Exit Do
  324.                 End If
  325.             Loop
  326.             m_objTimeOut.StopTimer
  327.         Else
  328.             'raise error - LIST command
  329.         End If 'ProcessLISTCommand
  330.     Else 'bDataConnectionEstablished
  331.         'raise error - can't establish data connection
  332.     End If 'bDataConnectionEstablished
  333. Exit_Label:
  334.     m_bBusy = False
  335.     Exit Function
  336. EnumFiles_Err_Handler:
  337.     Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.EnumFiles", Err.Description
  338.     GoTo Exit_Label
  339. End Function
  340. Public Function SetCurrentDirectory(strNewDirectory As String) As Boolean
  341.     m_bBusy = True
  342.     SetCurrentDirectory = ProcessCWDCommand(strNewDirectory)
  343.     m_bBusy = False
  344.     
  345. End Function
  346. Public Property Get FtpServer() As Variant
  347.     FtpServer = m_varFtpServer
  348. End Property
  349. Public Property Let FtpServer(NewValue As Variant)
  350.     m_varFtpServer = NewValue
  351. End Property
  352. Public Property Get Password() As String
  353.     Password = m_strPassword
  354. End Property
  355. Public Property Let Password(NewValue As String)
  356.     m_strPassword = NewValue
  357. End Property
  358. Public Property Get UserName() As String
  359.     UserName = m_strUserName
  360. End Property
  361. Public Property Let UserName(NewValue As String)
  362.     m_strUserName = NewValue
  363. End Property
  364. Public Function Connect() As Boolean
  365. '********************************************************************************
  366. 'Author      :Oleg Gdalevich
  367. 'Date/Time   :28.12.99
  368. 'Purpose     :Establishes the connection to ftp server
  369. '********************************************************************************
  370. On Error GoTo Connect_Err_Handler
  371. Dim strData     As String
  372. m_strWinsockBuffer = ""
  373. m_bBusy = True
  374. If Len(m_varFtpServer) > 0 Then
  375.     With wscControl
  376.         .Close
  377.         .LocalPort = 0
  378.         .Connect m_varFtpServer, 21
  379.         m_objTimeOut.StartTimer
  380.         Do
  381.             DoEvents
  382.             '
  383.             If m_objTimeOut.Timeout Then
  384.                 m_LastError = ERROR_FTP_USER_TIMEOUT
  385.                 Exit Do
  386.             End If
  387.             '
  388.             If .State = sckConnected Then
  389.                 m_objTimeOut.StopTimer
  390.                 RaiseEvent StateChanged(FTP_CONNECTION_CONNECTED)
  391.                 m_objTimeOut.StartTimer
  392.                 Do
  393.                     DoEvents
  394.                     '
  395.                     If m_objTimeOut.Timeout Then
  396.                         m_LastError = ERROR_FTP_USER_TIMEOUT
  397.                         Exit Do
  398.                     End If
  399.                     '
  400.                     If Len(m_strWinsockBuffer) > (RESPONSE_CODE_LENGHT - 1) Then
  401.                         strData = m_strWinsockBuffer
  402.                         m_strWinsockBuffer = ""
  403.                         Exit Do
  404.                     End If
  405.                 Loop
  406.                 m_objTimeOut.StopTimer
  407.                 Select Case GetResponseCode(strData)
  408.                     Case FTP_RESPONSE_SERVICE_READY_FOR_NEW_USER
  409.                         Select Case ProcessUSERCommand
  410.                             Case FTP_RESPONSE_USER_LOGGED_IN
  411.                                 Connect = True
  412.                             Case FTP_RESPONSE_USER_NAME_OK_NEED_PASSWORD
  413.                                 If ProcessPASSCommand = FTP_RESPONSE_USER_LOGGED_IN Then
  414.                                     Connect = True
  415.                                 End If
  416.                         End Select
  417.                         'Get working directory
  418.                         If Connect Then
  419.                             Call ProcessPWDCommand
  420.                         End If
  421.                     Case FTP_RESPONSE_SERVICE_READY_IN_MINUTES
  422.                         '120 Service ready in nnn minutes.
  423.                         m_LastError = ERROR_FTP_PROTOCOL_SERVICE_READY_IN_MINUTES
  424.                     Case FTP_RESPONSE_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION
  425.                         '421 Service not available, closing control connection.
  426.                         m_LastError = ERROR_FTP_PROTOCOL_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION
  427.                 End Select
  428.                 Exit Do
  429.             ElseIf .State = sckConnectAborted Then
  430.                 m_LastError = ERROR_FTP_WINSOCK_ConnectAborted
  431.             ElseIf .State = sckResolvingHost Then
  432.                 RaiseEvent StateChanged(FTP_CONNECTION_RESOLVING_HOST)
  433.             ElseIf .State = sckHostResolved Then
  434.                 RaiseEvent StateChanged(FTP_CONNECTION_HOST_RESOLVED)
  435.             End If
  436.         Loop
  437.         m_objTimeOut.StopTimer
  438.     End With
  439. Else
  440.     'raise error
  441.     Connect = False
  442.     Exit Function
  443. End If
  444. Exit_Label:
  445.     If Connect Then RaiseEvent StateChanged(FTP_USER_LOGGED)
  446.     m_bBusy = False
  447.     Exit Function
  448. Connect_Err_Handler:
  449.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  450.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.Connect", Err.Description
  451.     End If
  452.     GoTo Exit_Label
  453.     
  454. End Function
  455. Private Sub Class_Initialize()
  456.     Set wscControl = New MSWinsockLib.Winsock
  457.     Set wscData = New MSWinsockLib.Winsock
  458.     Set m_objTimeOut = New CTimeout
  459. End Sub
  460. Private Function GetResponseCode(strResponse As String) As Integer
  461.     If Len(strResponse) > (RESPONSE_CODE_LENGHT - 1) Then
  462.         GetResponseCode = CInt(Left$(strResponse, 3))
  463.     End If
  464.         
  465. End Function
  466. Private Function ProcessUSERCommand() As FTP_RESPONSE_CODES
  467.     Dim strData     As String
  468.     
  469.     On Error GoTo ProcessUSERCommand_Err_Handler
  470.     
  471.     RaiseEvent StateChanged(FTP_CONNECTION_AUTHENTICATION)
  472.     m_strUserName = IIf(Len(m_strUserName) > 0, m_strUserName, "anonymous")
  473.     
  474.     If Len(m_strPassword) = 0 Then
  475.         If m_strUserName = "anonymous" Then
  476.             m_strPassword = "guest@unknown.com"
  477.         Else
  478.             'raise error
  479.             Exit Function
  480.         End If
  481.     End If
  482.     
  483.     wscControl.SendData "USER " & m_strUserName & vbCrLf
  484.     Debug.Print "USER " & m_strUserName
  485.     
  486.     m_objTimeOut.StartTimer
  487.     Do
  488.         DoEvents
  489.         '
  490.         If m_objTimeOut.Timeout Then
  491.             m_LastError = ERROR_FTP_USER_TIMEOUT
  492.             Exit Do
  493.         End If
  494.         '
  495.         If Len(m_strWinsockBuffer) > RESPONSE_CODE_LENGHT Then
  496.             strData = m_strWinsockBuffer
  497.             m_strWinsockBuffer = ""
  498.             Exit Do
  499.         End If
  500.     Loop
  501.     m_objTimeOut.StopTimer
  502.     
  503.     Select Case GetResponseCode(strData)
  504.         Case FTP_RESPONSE_USER_LOGGED_IN
  505.             ProcessUSERCommand = FTP_RESPONSE_USER_LOGGED_IN
  506.         Case FTP_RESPONSE_USER_NAME_OK_NEED_PASSWORD
  507.             ProcessUSERCommand = FTP_RESPONSE_USER_NAME_OK_NEED_PASSWORD
  508.         Case Else
  509.             ProcessFtpResponse GetResponseCode(strData)
  510.     End Select
  511.     
  512. Exit_Label:
  513.     Exit Function
  514. ProcessUSERCommand_Err_Handler:
  515.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  516.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessUSERCommand", Err.Description
  517.     End If
  518.     GoTo Exit_Label
  519.     
  520. End Function
  521. Private Function ProcessPASSCommand() As FTP_RESPONSE_CODES
  522.     Dim strResponse As String
  523.     Dim strData     As String
  524.     '
  525.     On Error GoTo ProcessPASSCommand_Err_Handler
  526.     wscControl.SendData "PASS " & m_strPassword & vbCrLf
  527.     Debug.Print "PASS " & m_strPassword
  528.     
  529.     m_objTimeOut.StartTimer
  530.     Do
  531.         DoEvents
  532.         '
  533.         If m_objTimeOut.Timeout Then
  534.             m_LastError = ERROR_FTP_USER_TIMEOUT
  535.             Exit Do
  536.         End If
  537.         '
  538.         If Len(m_strWinsockBuffer) > RESPONSE_CODE_LENGHT Then
  539.             strData = m_strWinsockBuffer
  540.             Exit Do
  541.         End If
  542.     Loop
  543.     m_objTimeOut.StopTimer
  544.     If GetResponseCode(strData) = FTP_RESPONSE_USER_LOGGED_IN Then
  545.         Do
  546.             DoEvents
  547.             If InStr(1, m_strWinsockBuffer, "230 ") > 0 Then
  548.                 ProcessPASSCommand = FTP_RESPONSE_USER_LOGGED_IN
  549.                 m_strWinsockBuffer = ""
  550.                 Exit Function
  551.             End If
  552.         Loop
  553.     Else
  554.         ProcessFtpResponse GetResponseCode(strData)
  555.     End If
  556.     ProcessPASSCommand = GetResponseCode(strData)
  557.     
  558. Exit_Label:
  559.     Exit Function
  560. ProcessPASSCommand_Err_Handler:
  561.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  562.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessPASSCommand", Err.Description
  563.     End If
  564.     GoTo Exit_Label
  565.     
  566. End Function
  567. Private Function ProcessPWDCommand() As Boolean
  568.     Dim strResponse As String
  569.     Dim strData     As String
  570.     
  571.     On Error GoTo ProcessPWDCommand_Err_Handler
  572.     wscControl.SendData "PWD" & vbCrLf
  573.     Debug.Print "PWD"
  574.     
  575.     m_objTimeOut.StartTimer
  576.     Do
  577.         DoEvents
  578.         '
  579.         If m_objTimeOut.Timeout Then
  580.             m_LastError = ERROR_FTP_USER_TIMEOUT
  581.             Exit Do
  582.         End If
  583.         '
  584.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  585.             strData = m_strWinsockBuffer
  586.             m_strWinsockBuffer = ""
  587.             Exit Do
  588.         End If
  589.     Loop
  590.     m_objTimeOut.StopTimer
  591.     If GetResponseCode(strData) = FTP_RESPONSE_PATHNAME_CREATED Then
  592.         Dim intPosA As Integer, intPosB As Integer
  593.         intPosA = InStr(1, strData, Chr$(34)) + 1
  594.         intPosB = InStr(intPosA, strData, Chr$(34))
  595.         If intPosA > 1 And intPosB > 0 Then
  596.             m_strCurrentDirectory = Mid$(strData, intPosA, intPosB - intPosA)
  597.             ProcessPWDCommand = True
  598.         Else
  599.             'raise error - unknown response format
  600.         End If
  601.     Else
  602.         ProcessFtpResponse GetResponseCode(strData)
  603.     End If
  604.     
  605. Exit_Label:
  606.     Exit Function
  607. ProcessPWDCommand_Err_Handler:
  608.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  609.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessPWDCommand", Err.Description
  610.     End If
  611.     GoTo Exit_Label
  612.         
  613. End Function
  614. Private Sub Class_Terminate()
  615.     
  616.     Call BreakeConnection
  617.     Set wscData = Nothing
  618.     Set wscControl = Nothing
  619.     
  620.     m_objTimeOut.StopTimer
  621.     Set m_objTimeOut = Nothing
  622.     
  623. End Sub
  624. Private Sub wscControl_DataArrival(ByVal bytesTotal As Long)
  625.     
  626.     Dim strData As String
  627.     
  628.     wscControl.GetData strData
  629.     m_strWinsockBuffer = m_strWinsockBuffer & strData
  630.     m_strLastServerResponse = strData
  631.     m_objTimeOut.Reset
  632.     
  633.     
  634.     If GetResponseCode(strData) = 426 Then
  635.         If m_bTransferInProgress Or m_bUploadFile Then
  636.             wscData.Close
  637.             Close m_intLocalFileID
  638.             m_strDataBuffer = ""
  639.             m_lDownloadedBytes = 0
  640.             m_lUploadedBytes = 0
  641.             m_bTransferInProgress = False
  642.             m_bUploadFile = False
  643.             m_bFileIsOpened = False
  644.         End If
  645.         wscControl.Close
  646.         m_bBusy = False
  647.     End If
  648.     
  649.     Debug.Print Left(strData, Len(strData) - 2)
  650.     
  651. End Sub
  652. Private Function ProcessPORTCommand() As Boolean
  653.     Dim intPort         As Integer
  654.     Dim strIPAddress    As String
  655.     Dim colIPAddresses  As New Collection
  656.     Dim strSend         As String
  657.     Dim strData         As String
  658.     
  659.     On Error Resume Next
  660.     
  661.     RaiseEvent StateChanged(FTP_ESTABLISHING_DATA_CONNECTION)
  662.     
  663.     Do
  664.         intPort = GetFreePort
  665.         If wscData.State <> sckClosed Then wscData.Close
  666.         wscData.LocalPort = intPort
  667.         wscData.Listen
  668.         If Not Err Then Exit Do
  669.     Loop
  670.     
  671.     On Error GoTo ProcessPORTCommand_Err_Handler
  672.     '
  673.     strIPAddress = CStr(wscControl.LocalIP)
  674.     '
  675.     strSend = "PORT " & Replace(strIPAddress, ".", ",")
  676.     strSend = strSend & "," & intPort  256 & "," & (intPort Mod 256)
  677.     '
  678.     strSend = strSend & vbCrLf
  679.     '
  680.     wscControl.SendData strSend
  681.     Debug.Print Left(strSend, Len(strSend) - 2)
  682.     
  683.     m_objTimeOut.StartTimer
  684.     Do
  685.         DoEvents
  686.         '
  687.         If m_objTimeOut.Timeout Then
  688.             m_LastError = ERROR_FTP_USER_TIMEOUT
  689.             Exit Do
  690.         End If
  691.         '
  692.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  693.             strData = m_strWinsockBuffer
  694.             m_strWinsockBuffer = ""
  695.             Exit Do
  696.         End If
  697.     Loop
  698.     m_objTimeOut.StopTimer
  699.     
  700.     If GetResponseCode(strData) = FTP_RESPONSE_COMMAND_OK Then
  701.         ProcessPORTCommand = True
  702.         RaiseEvent StateChanged(FTP_DATA_CONNECTION_ESTABLISHED)
  703.     Else
  704.         ProcessFtpResponse GetResponseCode(strData)
  705.     End If
  706.     
  707. Exit_Label:
  708.     Exit Function
  709. ProcessPORTCommand_Err_Handler:
  710.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  711.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessPORTCommand", Err.Description
  712.     End If
  713.     GoTo Exit_Label
  714.         
  715. End Function
  716. Private Function GetFreePort() As Integer
  717.     
  718.     Static intPort As Integer
  719.     
  720.     If intPort = 0 Then
  721.         intPort = 1100
  722.     Else
  723.         intPort = intPort + 1
  724.     End If
  725.     
  726.     GetFreePort = intPort
  727.     
  728. End Function
  729. Private Sub wscData_ConnectionRequest(ByVal requestID As Long)
  730.     
  731.     If wscData.State <> sckClosed Then wscData.Close
  732.     
  733.     wscData.Accept (requestID)
  734.     
  735. End Sub
  736. Private Sub wscData_DataArrival(ByVal bytesTotal As Long)
  737.     
  738.     Dim strData As String
  739.     
  740.     wscData.GetData strData
  741.     
  742.     If m_bTransferInProgress Then
  743.         If m_bFileIsOpened Then
  744.             '
  745.             'write data to local file
  746.             '
  747.             Put m_intLocalFileID, , strData
  748.             '
  749.             'raise DownloadProgress event
  750.             '
  751.             m_lDownloadedBytes = m_lDownloadedBytes + bytesTotal
  752.             RaiseEvent DownloadProgress(m_lDownloadedBytes)
  753.         End If
  754.     Else
  755.         m_strDataBuffer = m_strDataBuffer & strData
  756. '        Debug.Print strData
  757.     End If
  758.     
  759.     m_objTimeOut.Reset
  760. End Sub
  761. Public Function RenameFile(strOldFileName As String, strNewFileName As String) As Boolean
  762.     
  763.     m_bBusy = True
  764.     If ProcessRNFRCommand(strOldFileName) Then
  765.         If ProcessRNTOCommand(strNewFileName) Then
  766.             RenameFile = True
  767.         End If
  768.     End If
  769.     m_bBusy = False
  770. End Function
  771. Public Function DeleteFile(strFileName As String) As Boolean
  772.     
  773.     m_bBusy = True
  774.     DeleteFile = ProcessDELECommand(strFileName)
  775.     m_bBusy = False
  776. End Function
  777. Public Function RemoveDirectory(strDirName As String) As Boolean
  778.     
  779.     m_bBusy = True
  780.     RemoveDirectory = ProcessRMDCommand(strDirName)
  781.     m_bBusy = False
  782.     
  783. End Function
  784. Public Function CreateDirectory(strDirName As String) As Boolean
  785.     
  786.     m_bBusy = True
  787.     CreateDirectory = ProcessMKDCommand(strDirName)
  788.     m_bBusy = False
  789.     
  790. End Function
  791. Private Function GetFileList(strListing As String) As CFtpFiles
  792.     '
  793.     Dim vFiles      As Variant
  794.     Dim vFile       As Variant
  795.     Dim vComponents As Variant
  796.     Dim oFtpFile    As CFtpFile
  797.     Dim oFtpFiles   As New CFtpFiles
  798.     
  799.     On Error Resume Next
  800.     '
  801.     Set GetFileList = Nothing
  802.     '
  803.     vFiles = Split(strListing, vbCrLf)
  804.     '
  805.     For Each vFile In vFiles
  806.         Set oFtpFile = New CFtpFile
  807.         '
  808.         'replace multiple whitespaces with single whitespace
  809.         '
  810.         For i = 15 To 2 Step -1
  811.             vFile = Replace(vFile, Space(i), " ")
  812.         Next
  813.         '
  814.         If Len(vFile) > 0 Then
  815.             If Not LCase(Left(vFile, 5)) = "total" Then
  816.                 vComponents = Split(vFile, " ")
  817.                 If UBound(vComponents) > 7 Then
  818.                     With oFtpFile
  819.                         If Left(vComponents(0), 1) = "d" Then
  820.                             oFtpFile.IsDirectory = True
  821.                         ElseIf Left(vFile, 1) = "l" Then
  822.                             .FilePath = vComponents(10)
  823.                             If Not CBool(InStr(InStrRev(vComponents(10), "/") + 1, vComponents(10), ".")) Then
  824.                                 .IsDirectory = True
  825.                             End If
  826.                         End If
  827.                         .FileSize = vComponents(4)
  828.                         .FileName = vComponents(8)
  829.                         .LastWriteTime = GetDate(vComponents(6), vComponents(5), vComponents(7))
  830.                         If Not (.FileName = "." Or .FileName = "..") Then
  831.                             oFtpFiles.Add oFtpFile, oFtpFile.FileName
  832.                         End If
  833.                     End With
  834.                 Else
  835.                     With oFtpFile
  836.                         If vComponents(2) = "<DIR>" Then
  837.                             .IsDirectory = True
  838.                         Else
  839.                             .FileSize = CLng(vComponents(2))
  840.                         End If
  841.                         If UBound(vComponents) > 3 Then
  842.                             Dim strFile As String
  843.                             For i = 3 To UBound(vComponents)
  844.                                strFile = strFile & " " & vComponents(i)
  845.                             Next i
  846.                             strFile = Mid$(strFile, 2)
  847.                         Else
  848.                             strFile = vComponents(3)
  849.                         End If
  850.                         .FileName = strFile
  851.                         .LastWriteTime = CDate(vComponents(0) & " " & vComponents(1))
  852.                         oFtpFiles.Add oFtpFile, oFtpFile.FileName
  853.                     End With
  854.                 End If
  855.                 Set oFtpFile = Nothing
  856.             End If
  857.         End If
  858.         strFile = ""
  859.     Next
  860.     
  861.     Set GetFileList = oFtpFiles
  862.     Set oFtpFiles = Nothing
  863.     
  864. End Function
  865. Private Function GetDate(vDay, vMonth, vYear) As Date
  866.     vYear = IIf(InStr(1, vYear, ":"), Year(Now), vYear)
  867.     
  868.     Select Case vMonth
  869.         Case "Jan": vMonth = 1
  870.         Case "Feb": vMonth = 2
  871.         Case "Mar": vMonth = 3
  872.         Case "Apr": vMonth = 4
  873.         Case "May": vMonth = 5
  874.         Case "Jun": vMonth = 6
  875.         Case "Jul": vMonth = 7
  876.         Case "Aug": vMonth = 8
  877.         Case "Sep": vMonth = 9
  878.         Case "Oct": vMonth = 10
  879.         Case "Nov": vMonth = 11
  880.         Case "Dec": vMonth = 12
  881.     End Select
  882.     
  883.     GetDate = DateSerial(CInt(vYear), CInt(vMonth), CInt(vDay))
  884. End Function
  885. Private Function ProcessPASVCommand() As Boolean
  886.     Dim strResponse As String
  887.     Dim strData     As String
  888.     
  889.     On Error GoTo ProcessPASVCommand_Err_Handler
  890.     
  891.     RaiseEvent StateChanged(FTP_ESTABLISHING_DATA_CONNECTION)
  892.     wscControl.SendData "PASV" & vbCrLf
  893.     Debug.Print "PASV"
  894.     
  895.     m_objTimeOut.StartTimer
  896.     Do
  897.         DoEvents
  898.         '
  899.         If m_objTimeOut.Timeout Then
  900.             m_LastError = ERROR_FTP_USER_TIMEOUT
  901.             Exit Do
  902.         End If
  903.         '
  904.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  905.             strData = m_strWinsockBuffer
  906.             m_strWinsockBuffer = ""
  907.             Exit Do
  908.         End If
  909.     Loop
  910.     m_objTimeOut.StopTimer
  911.     If GetResponseCode(strData) = FTP_RESPONSE_ENTERING_PASSIVE_MODE Then
  912.         ProcessPASVCommand = MakePassiveDataConnection(strData)
  913.     Else
  914.         ProcessFtpResponse GetResponseCode(strData)
  915.     End If
  916. Exit_Label:
  917.     Exit Function
  918. ProcessPASVCommand_Err_Handler:
  919.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  920.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessPASVCommand", Err.Description
  921.     End If
  922.     GoTo Exit_Label
  923. End Function
  924. Private Function MakePassiveDataConnection(sData As String) As Boolean
  925.     '
  926.     'Example of the string passed with sData argument
  927.     '227 Entering Passive Mode (194,220,224,2,7,189)
  928.     '
  929.     Dim iPos            As Integer
  930.     Dim iPos2           As Integer
  931.     Dim strDataAddress  As String
  932.     Dim strIP           As String
  933.     Dim lPort           As Long
  934.     '
  935.     On Error GoTo MakePassiveDataConnection_Err_Handler
  936.     '
  937.     iPos = InStr(1, sData, "(") + 1
  938.     If Not CBool(iPos) Then Exit Function
  939.     strDataAddress = Mid$(sData, iPos, InStr(1, sData, ")") - iPos)
  940.     strDataAddress = Replace(strDataAddress, ",", ".", 1, 3)
  941.     iPos = InStr(1, strDataAddress, ",")
  942.     strIP = Left$(strDataAddress, iPos - 1)
  943.     lPort = CLng(Mid$(strDataAddress, iPos + 1, InStr(iPos + 1, strDataAddress, ",") - iPos))
  944.     lPort = lPort * 256
  945.     lPort = lPort + CLng(Mid$(strDataAddress, InStrRev(strDataAddress, ",") + 1))
  946.     
  947.     wscData.Close
  948.     wscData.LocalPort = 0
  949.     wscData.Connect strIP, lPort
  950.     
  951.     m_objTimeOut.StartTimer
  952.     Do
  953.         DoEvents
  954.         '
  955.         If m_objTimeOut.Timeout Then
  956.             m_LastError = ERROR_FTP_USER_TIMEOUT
  957.             Exit Do
  958.         End If
  959.         '
  960.         If wscData.State = sckConnected Then
  961.             MakePassiveDataConnection = True
  962.             RaiseEvent StateChanged(FTP_DATA_CONNECTION_ESTABLISHED)
  963.             Debug.Print "Connecting to: " & strIP & ":" & lPort
  964.             Exit Do
  965.         End If
  966.     Loop
  967.     m_objTimeOut.StopTimer
  968.     
  969. Exit_Label:
  970.     Exit Function
  971.     
  972. MakePassiveDataConnection_Err_Handler:
  973.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  974.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.MakePassiveDataConnection", Err.Description
  975.     End If
  976.     GoTo Exit_Label
  977.     
  978. End Function
  979. Public Function DownloadFile(strFileName As String, strLocalFileName As String, vTransferMode As FtpTransferModes, Optional lStartPoint As Long) As Boolean
  980.     Dim bDataConnectionEstablished As Boolean
  981.     
  982.     m_bBusy = True
  983.     
  984.     If ProcessTYPECommand(vTransferMode) Then
  985.         m_TransferMode = vTransferMode
  986.     Else
  987.         Exit Function
  988.     End If
  989.     
  990.     If m_bPassiveMode Then
  991.         bDataConnectionEstablished = ProcessPASVCommand
  992.     Else
  993.         bDataConnectionEstablished = ProcessPORTCommand
  994.     End If
  995.     
  996.     If bDataConnectionEstablished Then
  997.         If lStartPoint > 0 Then
  998.             m_lDownloadedBytes = lStartPoint
  999.             If Not ProcessRESTCommand(lStartPoint) Then
  1000.                 'can't restart download
  1001.                 DownloadFile = False
  1002.                 Exit Function
  1003.             End If
  1004.         End If
  1005.         m_bTransferInProgress = True
  1006.         m_strLocalFilePath = strLocalFileName
  1007.         If ProcessRETRCommand(strFileName, lStartPoint) Then
  1008.             m_objTimeOut.StartTimer
  1009.             Do
  1010.                 DoEvents
  1011.                 '
  1012.                 If m_objTimeOut.Timeout Then
  1013.                     m_LastError = ERROR_FTP_USER_TIMEOUT
  1014.                     Exit Do
  1015.                 End If
  1016.                 '
  1017.                 If wscData.State = sckClosed Or wscData.State = sckClosing Then
  1018.                     RaiseEvent StateChanged(FTP_TRANSFER_COMLETED)
  1019.                     'close file
  1020.                     Close #m_intLocalFileID
  1021.                     m_bFileIsOpened = False
  1022.                     m_bTransferInProgress = False
  1023.                     m_lDownloadedBytes = 0
  1024.                     If Left$(GetLastServerResponse, 3) = "426" Then
  1025.                         m_LastError = FTP_RESPONSE_CONNECTION_CLOSED_TRANSFER_ABORTED
  1026.                         Call ProcessFtpResponse(FTP_RESPONSE_CONNECTION_CLOSED_TRANSFER_ABORTED)
  1027.                         DownloadFile = False
  1028.                     Else
  1029.                         DownloadFile = True
  1030.                     End If
  1031.                     Exit Do
  1032.                 End If
  1033.             Loop
  1034.             m_objTimeOut.StopTimer
  1035.         Else
  1036.             DownloadFile = False
  1037.             m_bTransferInProgress = False
  1038.             Close m_intLocalFileID
  1039.         End If
  1040.     End If
  1041.     
  1042.     m_bBusy = False
  1043. End Function
  1044. Private Function ProcessRETRCommand(strFileName As String, lStartPoint As Long) As Boolean
  1045.     
  1046.     Dim strResponse As String
  1047.     Dim strData     As String
  1048.     
  1049.     On Error GoTo ProcessRETRCommand_Err_Handler
  1050.     
  1051.     m_strDataBuffer = ""
  1052.     wscControl.SendData "RETR " & strFileName & vbCrLf
  1053.     Debug.Print "RETR " & strFileName
  1054.     
  1055.     m_objTimeOut.StartTimer
  1056.     Do
  1057.         DoEvents
  1058.         '
  1059.         If m_objTimeOut.Timeout Then
  1060.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1061.             Exit Do
  1062.         End If
  1063.         '
  1064.         If Not m_bTransferInProgress Then
  1065.             strData = m_strWinsockBuffer
  1066.             Exit Do
  1067.         End If
  1068.         '
  1069.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1070.             If GetResponseCode(m_strWinsockBuffer) = 150 Or _
  1071.                 GetResponseCode(m_strWinsockBuffer) = 125 Then
  1072.                 If lStartPoint = 0 And FileExists(m_strLocalFilePath) Then
  1073.                     Kill m_strLocalFilePath
  1074.                 End If
  1075.                 m_intLocalFileID = FreeFile
  1076.                 Open m_strLocalFilePath For Binary As m_intLocalFileID
  1077.                 If lStartPoint > 0 Then
  1078.                     Seek m_intLocalFileID, lStartPoint + 1
  1079.                 End If
  1080.                 'turn on flag m_bFileIsOpened
  1081.                 m_bFileIsOpened = True
  1082.                 'ignore 150 and 125 reply codes
  1083.                 m_strWinsockBuffer = Mid$(m_strWinsockBuffer, InStr(1, m_strWinsockBuffer, vbCrLf) + 2)
  1084.                 RaiseEvent StateChanged(FTP_TRANSFER_STARTING)
  1085.             Else
  1086.                 strData = m_strWinsockBuffer
  1087.                 m_strWinsockBuffer = ""
  1088.                 Exit Do
  1089.             End If
  1090.         End If
  1091.     Loop
  1092.     m_objTimeOut.StopTimer
  1093.     
  1094.     If GetResponseCode(strData) = FTP_RESPONSE_CLOSING_DATA_CONNECTION Or _
  1095.         GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  1096.         ProcessRETRCommand = True
  1097.     Else
  1098.         ProcessFtpResponse GetResponseCode(strData)
  1099.     End If
  1100.     
  1101. Exit_Label:
  1102.     Exit Function
  1103. ProcessRETRCommand_Err_Handler:
  1104.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1105.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessRETRCommand", Err.Description
  1106.     End If
  1107.     GoTo Exit_Label
  1108.         
  1109. End Function
  1110. Private Function ProcessRESTCommand(lStartPoint As Long) As Boolean
  1111.     Dim strResponse As String
  1112.     Dim strData     As String
  1113.     
  1114.     On Error GoTo ProcessRESTCommand_Err_Handler
  1115.     
  1116.     wscControl.SendData "REST " & lStartPoint & vbCrLf
  1117.     Debug.Print "REST " & lStartPoint
  1118.     
  1119.     m_objTimeOut.StartTimer
  1120.     Do
  1121.         DoEvents
  1122.         '
  1123.         If m_objTimeOut.Timeout Then
  1124.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1125.             Exit Do
  1126.         End If
  1127.         '
  1128.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1129.             strData = m_strWinsockBuffer
  1130.             m_strWinsockBuffer = ""
  1131.             Exit Do
  1132.         End If
  1133.     Loop
  1134.     m_objTimeOut.StopTimer
  1135.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFO Then
  1136.         ProcessRESTCommand = True
  1137.     Else
  1138.         ProcessFtpResponse GetResponseCode(strData)
  1139.     End If
  1140.     
  1141. Exit_Label:
  1142.     Exit Function
  1143. ProcessRESTCommand_Err_Handler:
  1144.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1145.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessRESTCommand", Err.Description
  1146.     End If
  1147.     GoTo Exit_Label
  1148.         
  1149. End Function
  1150. Public Sub BreakeConnection()
  1151.     
  1152.     On Error Resume Next
  1153.     
  1154.     If wscData <> sckClosed Then
  1155.         wscData.Close
  1156.     Else
  1157.         wscControl.Close
  1158.     End If
  1159.     
  1160.     If m_bTransferInProgress Or m_bUploadFile Then
  1161.         Close m_intLocalFileID
  1162.         m_strDataBuffer = ""
  1163.         m_lDownloadedBytes = 0
  1164.         m_lUploadedBytes = 0
  1165.         m_bTransferInProgress = False
  1166.         m_bUploadFile = False
  1167.     End If
  1168.     m_bFileIsOpened = False
  1169.     m_bBusy = False
  1170.     m_objTimeOut.StopTimer
  1171.     
  1172. End Sub
  1173. Private Function ProcessTYPECommand(vType As FtpTransferModes) As Boolean
  1174.     Dim strResponse As String
  1175.     Dim strData     As String
  1176.     
  1177.     On Error GoTo ProcessTYPECommand_Err_Handler
  1178.     
  1179.     wscControl.SendData "TYPE " & IIf(vType = FTP_ASCII_MODE, "A", "I") & vbCrLf
  1180.     Debug.Print "TYPE " & IIf(vType = FTP_ASCII_MODE, "A", "I")
  1181.     
  1182.     m_objTimeOut.StartTimer
  1183.     Do
  1184.            DoEvents
  1185.         '
  1186.         If m_objTimeOut.Timeout Then
  1187.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1188.             Exit Do
  1189.         End If
  1190.         '
  1191.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1192.             strData = m_strWinsockBuffer
  1193.             m_strWinsockBuffer = ""
  1194.             Exit Do
  1195.         End If
  1196.     Loop
  1197.     m_objTimeOut.StopTimer
  1198.     
  1199.     If GetResponseCode(strData) = FTP_RESPONSE_COMMAND_OK Then
  1200.         ProcessTYPECommand = True
  1201.     Else
  1202.         ProcessFtpResponse GetResponseCode(strData)
  1203.     End If
  1204.     
  1205. Exit_Label:
  1206.     Exit Function
  1207. ProcessTYPECommand_Err_Handler:
  1208.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1209.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessTYPECommand", Err.Description
  1210.     End If
  1211.     GoTo Exit_Label
  1212.     
  1213. End Function
  1214. Private Function FileExists(strFileName As String) As Boolean
  1215.     
  1216.     On Error GoTo ERROR_HANDLER
  1217.     
  1218.     FileExists = (GetAttr(strFileName) And vbDirectory) = 0
  1219. ERROR_HANDLER:
  1220.     
  1221. End Function
  1222. Private Function ProcessDELECommand(strFileName As String) As Boolean
  1223.     Dim strResponse As String
  1224.     Dim strData     As String
  1225.     '
  1226.     On Error GoTo ProcessDELECommand_Err_Handler
  1227.     
  1228.     wscControl.SendData "DELE " & strFileName & vbCrLf
  1229.     Debug.Print "DELE " & strFileName
  1230.     
  1231.     m_objTimeOut.StartTimer
  1232.     Do
  1233.         DoEvents
  1234.         '
  1235.         If m_objTimeOut.Timeout Then
  1236.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1237.             Exit Do
  1238.         End If
  1239.         '
  1240.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1241.             strData = m_strWinsockBuffer
  1242.             m_strWinsockBuffer = ""
  1243.             Exit Do
  1244.         End If
  1245.     Loop
  1246.     m_objTimeOut.StopTimer
  1247.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  1248.         ProcessDELECommand = True
  1249.     Else
  1250.         ProcessFtpResponse (GetResponseCode(strData))
  1251.     End If
  1252.     
  1253. Exit_Label:
  1254.     Exit Function
  1255.     
  1256. ProcessDELECommand_Err_Handler:
  1257.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1258.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessDELECommand", Err.Description
  1259.     End If
  1260.     GoTo Exit_Label
  1261. End Function
  1262. Private Function ProcessMKDCommand(strDirName As String) As Boolean
  1263.     Dim strResponse As String
  1264.     Dim strData     As String
  1265.     '
  1266.     On Error GoTo ProcessMKDCommand_Err_Handler
  1267.     
  1268.     wscControl.SendData "MKD " & strDirName & vbCrLf
  1269.     Debug.Print "MKD " & strDirName
  1270.     
  1271.     m_objTimeOut.StartTimer
  1272.     Do
  1273.         DoEvents
  1274.         '
  1275.         If m_objTimeOut.Timeout Then
  1276.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1277.             Exit Do
  1278.         End If
  1279.         '
  1280.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1281.             strData = m_strWinsockBuffer
  1282.             m_strWinsockBuffer = ""
  1283.             Exit Do
  1284.         End If
  1285.     Loop
  1286.     m_objTimeOut.StopTimer
  1287.     If GetResponseCode(strData) = FTP_RESPONSE_PATHNAME_CREATED Then
  1288.         ProcessMKDCommand = True
  1289.     Else
  1290.         ProcessFtpResponse GetResponseCode(strData)
  1291.     End If
  1292. Exit_Label:
  1293.     Exit Function
  1294. ProcessMKDCommand_Err_Handler:
  1295.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1296.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessMKDCommand", Err.Description
  1297.     End If
  1298.     GoTo Exit_Label
  1299.     
  1300. End Function
  1301. Private Function ProcessRMDCommand(strDirName As String) As Boolean
  1302.     Dim strResponse As String
  1303.     Dim strData     As String
  1304.     
  1305.     On Error GoTo ProcessRMDCommand_Err_Handler
  1306.     
  1307.     wscControl.SendData "RMD " & strDirName & vbCrLf
  1308.     Debug.Print "RMD " & strDirName
  1309.     
  1310.     m_objTimeOut.StartTimer
  1311.     Do
  1312.         DoEvents
  1313.         '
  1314.         If m_objTimeOut.Timeout Then
  1315.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1316.             Exit Do
  1317.         End If
  1318.         '
  1319.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1320.             strData = m_strWinsockBuffer
  1321.             m_strWinsockBuffer = ""
  1322.             Exit Do
  1323.         End If
  1324.     Loop
  1325.     m_objTimeOut.StopTimer
  1326.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  1327.         ProcessRMDCommand = True
  1328.     Else
  1329.         ProcessFtpResponse GetResponseCode(strData)
  1330.     End If
  1331.     
  1332. Exit_Label:
  1333.     Exit Function
  1334. ProcessRMDCommand_Err_Handler:
  1335.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1336.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessRMDCommand", Err.Description
  1337.     End If
  1338.     GoTo Exit_Label
  1339. End Function
  1340. Private Function ProcessRNFRCommand(strFileName As String) As Boolean
  1341.     Dim strResponse As String
  1342.     Dim strData     As String
  1343.     
  1344.     On Error GoTo ProcessRNFRCommand_Err_Handler
  1345.     
  1346.     wscControl.SendData "RNFR " & strFileName & vbCrLf
  1347.     Debug.Print "RNFR " & strFileName
  1348.     
  1349.     m_objTimeOut.StartTimer
  1350.     Do
  1351.         DoEvents
  1352.         '
  1353.         If m_objTimeOut.Timeout Then
  1354.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1355.             Exit Do
  1356.         End If
  1357.         '
  1358.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1359.             strData = m_strWinsockBuffer
  1360.             m_strWinsockBuffer = ""
  1361.             Exit Do
  1362.         End If
  1363.     Loop
  1364.     m_objTimeOut.StopTimer
  1365.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFO Then
  1366.         ProcessRNFRCommand = True
  1367.     Else
  1368.         ProcessFtpResponse GetResponseCode(strData)
  1369.     End If
  1370. Exit_Label:
  1371.     Exit Function
  1372. ProcessRNFRCommand_Err_Handler:
  1373.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1374.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessRNFRCommand", Err.Description
  1375.     End If
  1376.     GoTo Exit_Label
  1377.     
  1378. End Function
  1379. Private Function ProcessRNTOCommand(strFileName As String) As Boolean
  1380.     Dim strResponse As String
  1381.     Dim strData     As String
  1382.     
  1383.     On Error GoTo ProcessRNTOCommand_Err_Handler
  1384.     
  1385.     wscControl.SendData "RNTO " & strFileName & vbCrLf
  1386.     Debug.Print "RNTO " & strFileName
  1387.     
  1388.     m_objTimeOut.StartTimer
  1389.     Do
  1390.         DoEvents
  1391.         '
  1392.         If m_objTimeOut.Timeout Then
  1393.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1394.             Exit Do
  1395.         End If
  1396.         '
  1397.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1398.             strData = m_strWinsockBuffer
  1399.             m_strWinsockBuffer = ""
  1400.             Exit Do
  1401.         End If
  1402.     Loop
  1403.     m_objTimeOut.StopTimer
  1404.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  1405.         ProcessRNTOCommand = True
  1406.     Else
  1407.         ProcessFtpResponse GetResponseCode(strData)
  1408.     End If
  1409.     
  1410. Exit_Label:
  1411.     Exit Function
  1412. ProcessRNTOCommand_Err_Handler:
  1413.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1414.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessRNTOCommand", Err.Description
  1415.     End If
  1416.     GoTo Exit_Label
  1417. End Function
  1418. Public Function UploadFile(strLocalFileName As String, strRemoteFileName As String, vTransferMode As FtpTransferModes, Optional lStartPoint As Long) As Boolean
  1419.     Dim bDataConnectionEstablished As Boolean
  1420.         
  1421.     m_bBusy = True
  1422.         
  1423.     If Not (vTransferMode = m_TransferMode) Then
  1424.         If ProcessTYPECommand(vTransferMode) Then
  1425.             m_TransferMode = vTransferMode
  1426.         Else
  1427.             Exit Function
  1428.         End If
  1429.     End If
  1430.     
  1431.     If m_bPassiveMode Then
  1432.         bDataConnectionEstablished = ProcessPASVCommand
  1433.     Else
  1434.         bDataConnectionEstablished = ProcessPORTCommand
  1435.     End If
  1436.     
  1437.     If bDataConnectionEstablished Then
  1438.         '
  1439.         If Not IsMissing(lStartPoint) Then
  1440.             If Not ProcessRESTCommand(lStartPoint) Then
  1441.                 UploadFile = False
  1442.                 Exit Function
  1443.             End If
  1444.         End If
  1445.         '
  1446.         m_strLocalFilePath = strLocalFileName
  1447.         m_bUploadFile = True
  1448.         If ProcessSTORCommand(strLocalFileName, strRemoteFileName, lStartPoint) Then
  1449.             m_objTimeOut.StartTimer
  1450.             Do
  1451.                 DoEvents
  1452.                 '
  1453.                 If m_objTimeOut.Timeout Then
  1454.                     m_LastError = ERROR_FTP_USER_TIMEOUT
  1455.                     Exit Do
  1456.                 End If
  1457.                 '
  1458.                 If wscData.State = sckClosing Or _
  1459.                     wscData.State = sckClosed Then
  1460.                     'clear winsock buffer
  1461.                     RaiseEvent StateChanged(FTP_TRANSFER_COMLETED)
  1462.                     Exit Do
  1463.                 End If
  1464.             Loop
  1465.             m_objTimeOut.StopTimer
  1466.             UploadFile = True
  1467.         End If
  1468.     End If
  1469.     
  1470.     m_bBusy = False
  1471.     
  1472. End Function
  1473. Private Function ProcessSTORCommand(strLocalFileName As String, strRemoteFileName As String, lStartPoint As Long) As Boolean
  1474.     
  1475.     Dim strResponse As String
  1476.     Dim strData     As String
  1477.     
  1478.     On Error GoTo ProcessSTORCommand_Err_Handler
  1479.     
  1480.     m_strDataBuffer = ""
  1481.     wscControl.SendData "STOR " & strRemoteFileName & vbCrLf
  1482.     Debug.Print "STOR " & strRemoteFileName
  1483.     
  1484.     m_objTimeOut.StartTimer
  1485.     Do
  1486.         DoEvents
  1487.         '
  1488.         If m_objTimeOut.Timeout Then
  1489.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1490.             Exit Do
  1491.         End If
  1492.         '
  1493.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1494.             If GetResponseCode(m_strWinsockBuffer) = 150 Or _
  1495.                 GetResponseCode(m_strWinsockBuffer) = 125 Then
  1496.                 m_strWinsockBuffer = ""
  1497.                 RaiseEvent StateChanged(FTP_TRANSFER_STARTING)
  1498.                 m_strLocalFilePath = strLocalFileName
  1499.                 Call UploadData(lStartPoint)
  1500.             Else
  1501.                 strData = m_strWinsockBuffer
  1502.                 m_strWinsockBuffer = ""
  1503.                 Exit Do
  1504.             End If
  1505.         End If
  1506.     Loop
  1507.     m_objTimeOut.StopTimer
  1508.     If GetResponseCode(strData) = FTP_RESPONSE_CLOSING_DATA_CONNECTION Or _
  1509.         GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  1510.         ProcessSTORCommand = True
  1511.     Else
  1512.         ProcessFtpResponse GetResponseCode(strData)
  1513.     End If
  1514.     
  1515. Exit_Label:
  1516.     Exit Function
  1517. ProcessSTORCommand_Err_Handler:
  1518.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1519.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessSTORCommand", Err.Description
  1520.     End If
  1521.     GoTo Exit_Label
  1522. End Function
  1523. Private Sub wscData_SendComplete()
  1524.     
  1525.     If m_bUploadFile Then
  1526.         Call UploadData(0)
  1527.     End If
  1528.     
  1529.     m_objTimeOut.Reset
  1530.     
  1531. End Sub
  1532. Private Sub wscData_SendProgress(ByVal bytesSent As Long, ByVal bytesRemaining As Long)
  1533.     m_lUploadedBytes = m_lUploadedBytes + bytesSent
  1534.     
  1535.     RaiseEvent UploadProgress(m_lUploadedBytes)
  1536. End Sub
  1537. Private Sub UploadData(lStartPoint As Long)
  1538. '--------------------------------------------------------------------------------
  1539. 'Author      :Oleg Gdalevich
  1540. 'Date/Time   :14.09.99
  1541. 'Purpose     :Opens file, reads data from the file and
  1542. '             sends the data to remote computer by 4kb (CHANK_SIZE) chanks.
  1543. 'Description :If file size is more than CHANK_SIZE the procedure called one or
  1544. '             multiple times from wscFtpData_SendComplete event procedure.
  1545. '--------------------------------------------------------------------------------
  1546.     
  1547.     Const CHANK_SIZE As Integer = 4096
  1548.     
  1549.     Static bFileIsOpen  As Boolean  'flag variable
  1550.     Static lChanksCount As Long     'quantity of chanks to send
  1551.     Static lCounter     As Long     'sent chanks counter
  1552.     Static intRemainder As Integer  '
  1553.     Dim strData         As String   'data buffer to send
  1554.     
  1555.     On Error GoTo UploadData_Err_Handler
  1556.     'if bFileIsOpen = True, the procedure was called before
  1557.     If m_bFileIsOpened Then
  1558.         'if we have to send next chank
  1559.         If lCounter < lChanksCount And lCounter > 0 Then
  1560.             'prepare the buffer
  1561.             strData = Space(CHANK_SIZE)
  1562.             'increament counter
  1563.             lCounter = lCounter + 1
  1564.             'read data from file
  1565.             Get m_intLocalFileID, , strData
  1566.             'send data
  1567.             wscData.SendData strData
  1568.         Else
  1569.             'all the data is sent
  1570.             If lCounter = 0 Then
  1571.                 '
  1572.                 'close data connection to inform ftp server
  1573.                 'that transfer is comlteted
  1574.                 '
  1575.                 wscData.Close
  1576.                 '
  1577.                 'close local file
  1578.                 '
  1579.                 Close #m_intLocalFileID
  1580.                 '
  1581.                 RaiseEvent StateChanged(FTP_TRANSFER_COMLETED)
  1582.                 '
  1583.                 'reset values of all static and module
  1584.                 'level variables
  1585.                 '
  1586.                 m_lUploadedBytes = 0:       lChanksCount = 0: intRemainder = 0
  1587.                 m_bFileIsOpened = False:        m_bUploadFile = False
  1588.                 '
  1589.             Else
  1590.                 'all the chanks are sent
  1591.                 'now we have to send the remainder
  1592.                 '
  1593.                 'prepare the buffer
  1594.                 strData = Space(intRemainder)
  1595.                 'reset the counter
  1596.                 lCounter = 0
  1597.                 'read data from file
  1598.                 Get m_intLocalFileID, , strData
  1599.                 'send data
  1600.                 m_objTimeOut.StartTimer
  1601.                 Do
  1602.                     DoEvents
  1603.                     '
  1604.                     If m_objTimeOut.Timeout Then
  1605.                         m_LastError = ERROR_FTP_USER_TIMEOUT
  1606.                         Exit Do
  1607.                     End If
  1608.                     '
  1609.                     If wscData.State = sckConnected Then
  1610.                         wscData.SendData strData
  1611.                         Exit Do
  1612.                     End If
  1613.                 Loop
  1614.                 m_objTimeOut.StopTimer
  1615.             End If
  1616.         End If
  1617.     Else
  1618.         '
  1619.         'if we are here, the procedure called at first time
  1620.         '
  1621.         m_bFileIsOpened = True  'turn on flag variable
  1622.         '
  1623.         m_intLocalFileID = FreeFile
  1624.         '
  1625.         Open m_strLocalFilePath For Binary As m_intLocalFileID
  1626.         '
  1627.         If lStartPoint > 0 Then
  1628.             Seek m_intLocalFileID, lStartPoint + 1
  1629.             m_lUploadedBytes = lStartPoint
  1630.             'get quantity of chancks to send
  1631.             lChanksCount = CLng((FileLen(m_strLocalFilePath) - lStartPoint)  CHANK_SIZE)
  1632.             'get remainder in bytes
  1633.             intRemainder = (FileLen(m_strLocalFilePath) - lStartPoint) Mod CHANK_SIZE
  1634.         Else
  1635.             '
  1636.             'get quantity of chancks to send
  1637.             lChanksCount = CLng(FileLen(m_strLocalFilePath)  CHANK_SIZE)
  1638.             '
  1639.             'get remainder in bytes
  1640.             intRemainder = FileLen(m_strLocalFilePath) Mod CHANK_SIZE
  1641.         End If
  1642.         
  1643.         If lChanksCount = 0 Then
  1644.             'if amount of data is less then 4Kb
  1645.             'prepare buffer to read data from a file
  1646.             strData = Space(intRemainder)
  1647.         Else
  1648.             '
  1649.             'prepare buffer to read data from a file
  1650.             strData = Space(CHANK_SIZE)
  1651.             'increament counter of sent chanks
  1652.             lCounter = 1
  1653.         End If
  1654.         'open file to read data
  1655.         'Open m_strLocalFilePath For Binary As #intFile
  1656.         'read data to buffer strData
  1657.         Get m_intLocalFileID, , strData
  1658.         'send data
  1659.                 Do
  1660.                     DoEvents
  1661.                     If wscData.State = sckConnected Then
  1662.                         wscData.SendData strData
  1663.                         Exit Do
  1664.                     End If
  1665.                 Loop
  1666.         '
  1667.         'If lCounter>0, file size if equal or less then chank size
  1668.         'and we have to send more data. At the next time this sub will
  1669.         'be called from wscData_SendComplete event procedure to send
  1670.         'next chank or remainder.
  1671.         '
  1672.     End If
  1673.     
  1674.     Exit Sub
  1675.     
  1676. Exit_Label:
  1677.     Exit Sub
  1678. UploadData_Err_Handler:
  1679.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1680.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.UploadData", Err.Description
  1681.     End If
  1682.     Close #intFile
  1683.     GoTo Exit_Label
  1684.     
  1685. End Sub
  1686. Private Function ShowTimeOut() As Boolean
  1687.     Dim intRetVal As Integer
  1688.     
  1689.     intRetVal = MsgBox("A time-out occurred while communicating with the server." & _
  1690.                 "The server took too long to respond." & vbCrLf & vbCrLf & _
  1691.                 "Would you like to wait for server response?", vbYesNo + vbQuestion, _
  1692.                 "Time out")
  1693.     
  1694.     If intRetVal = vbYes Then
  1695.         m_objTimeOut.Reset
  1696.         m_objTimeOut.StartTimer
  1697.         ShowTimeOut = True
  1698.     End If
  1699.     
  1700. End Function
  1701. Public Property Let Timeout(NewValue As Integer)
  1702.     m_intTimeout = NewValue
  1703.     m_objTimeOut.TimeoutValue = NewValue
  1704. End Property
  1705. Public Property Get Timeout() As Integer
  1706.     Timeout = m_intTimeout
  1707. End Property
  1708. Public Property Get Busy() As Boolean
  1709.     Busy = m_bBusy
  1710. End Property
  1711. Private Function ProcessWinsockError(intError As ErrorConstants, strDesc As String) As Boolean
  1712.     m_strLastErrorDesc = strDesc
  1713.     
  1714.     Select Case intError
  1715.         Case sckAddressInUse
  1716.             m_LastError = ERROR_FTP_WINSOCK_AddressInUse
  1717.         Case sckAddressNotAvailable
  1718.             m_LastError = ERROR_FTP_WINSOCK_AddressNotAvailable
  1719.         Case sckAlreadyComplete
  1720.             m_LastError = ERROR_FTP_WINSOCK_AlreadyComplete
  1721.         Case sckAlreadyConnected
  1722.             m_LastError = ERROR_FTP_WINSOCK_AlreadyConnected
  1723.         Case sckBadState
  1724.             m_LastError = ERROR_FTP_WINSOCK_BadState
  1725.         Case sckConnectAborted
  1726.             m_LastError = ERROR_FTP_WINSOCK_ConnectAborted
  1727.         Case sckConnectionRefused
  1728.             m_LastError = ERROR_FTP_WINSOCK_ConnectionRefused
  1729.         Case sckConnectionReset
  1730.             m_LastError = ERROR_FTP_WINSOCK_ConnectionReset
  1731.         Case sckGetNotSupported
  1732.             m_LastError = ERROR_FTP_WINSOCK_GetNotSupported
  1733.         Case sckHostNotFound
  1734.             m_LastError = ERROR_FTP_WINSOCK_HostNotFound
  1735.         Case sckHostNotFoundTryAgain
  1736.             m_LastError = ERROR_FTP_WINSOCK_HostNotFoundTryAgain
  1737.         Case sckInProgress
  1738.             m_LastError = ERROR_FTP_WINSOCK_InProgress
  1739.         Case sckInvalidArg
  1740.             m_LastError = ERROR_FTP_WINSOCK_InvalidArg
  1741.         Case sckInvalidArgument
  1742.             m_LastError = ERROR_FTP_WINSOCK_InvalidArgument
  1743.         Case sckInvalidOp
  1744.             m_LastError = ERROR_FTP_WINSOCK_InvalidOp
  1745.         Case sckInvalidPropertyValue
  1746.             m_LastError = ERROR_FTP_WINSOCK_InvalidPropertyValue
  1747.         Case sckMsgTooBig
  1748.             m_LastError = ERROR_FTP_WINSOCK_MsgTooBig
  1749.         Case sckNetReset
  1750.             m_LastError = ERROR_FTP_WINSOCK_NetReset
  1751.         Case sckNetworkSubsystemFailed
  1752.             m_LastError = ERROR_FTP_WINSOCK_NetworkSubsystemFailed
  1753.         Case sckNetworkUnreachable
  1754.             m_LastError = ERROR_FTP_WINSOCK_NetworkUnreachable
  1755.         Case sckNoBufferSpace
  1756.             m_LastError = ERROR_FTP_WINSOCK_NoBufferSpace
  1757.         Case sckNoData
  1758.             m_LastError = ERROR_FTP_WINSOCK_NoData
  1759.         Case sckNonRecoverableError
  1760.             m_LastError = ERROR_FTP_WINSOCK_NonRecoverableError
  1761.         Case sckNotConnected
  1762.             m_LastError = ERROR_FTP_WINSOCK_NotConnected
  1763.         Case sckNotInitialized
  1764.             m_LastError = ERROR_FTP_WINSOCK_NotInitialized
  1765.         Case sckNotSocket
  1766.             m_LastError = ERROR_FTP_WINSOCK_NotSocket
  1767.         Case sckOpCanceled
  1768.             m_LastError = ERROR_FTP_WINSOCK_OpCanceled
  1769.         Case sckOutOfMemory
  1770.             m_LastError = ERROR_FTP_WINSOCK_OutOfMemory
  1771.         Case sckOutOfRange
  1772.             m_LastError = ERROR_FTP_WINSOCK_OutOfRange
  1773.         Case sckPortNotSupported
  1774.             m_LastError = ERROR_FTP_WINSOCK_PortNotSupported
  1775.         Case sckSetNotSupported
  1776.             m_LastError = ERROR_FTP_WINSOCK_SetNotSupported
  1777.         Case sckSocketShutdown
  1778.             m_LastError = ERROR_FTP_WINSOCK_SocketShutdown
  1779.         Case sckSuccess
  1780.             m_LastError = ERROR_FTP_WINSOCK_Success
  1781.         Case sckTimedout
  1782.             m_LastError = ERROR_FTP_WINSOCK_Timedout
  1783.         Case sckUnsupported
  1784.             m_LastError = ERROR_FTP_WINSOCK_Unsupported
  1785.         Case sckWouldBlock
  1786.             m_LastError = ERROR_FTP_WINSOCK_WouldBlock
  1787.         Case sckWrongProtocol
  1788.             m_LastError = ERROR_FTP_WINSOCK_WrongProtocol
  1789.     Case Else
  1790.         ProcessWinsockError = False
  1791.         Exit Function
  1792.     End Select
  1793.     
  1794.     ProcessWinsockError = True
  1795.     
  1796. End Function
  1797. Private Function ProcessFtpResponse(intCode As FTP_RESPONSE_CODES) As Boolean
  1798.     Select Case intCode
  1799.         Case FTP_RESPONSE_RESTATRT_MARKER_REPLY
  1800.         Case FTP_RESPONSE_SERVICE_READY_IN_MINUTES
  1801.         Case FTP_RESPONSE_DATA_CONNECTION_ALREADY_OPEN
  1802.         Case FTP_RESPONSE_FILE_STATUS_OK
  1803.         Case FTP_RESPONSE_COMMAND_OK
  1804.         Case FTP_RESPONSE_COMMAND_NOT_IMPLEMENTED_SUPERFLUOUS_AT_THIS_SITE
  1805.         Case FTP_RESPONSE_SYSTEM_STATUS_OR_SYSTEM_HELP_REPLY
  1806.         Case FTP_RESPONSE_DIRECTORY_STATUS
  1807.         Case FTP_RESPONSE_FILE_STATUS
  1808.         Case FTP_RESPONSE_HELP_MESSAGE
  1809.         Case FTP_RESPONSE_NAME_SYSTEM_TYPE
  1810.         Case FTP_RESPONSE_SERVICE_READY_FOR_NEW_USER
  1811.         Case FTP_RESPONSE_SERVICE_CLOSING_CONTROL_CONNECTION
  1812.         Case FTP_RESPONSE_DATA_CONNECTION_OPEN
  1813.         Case FTP_RESPONSE_CLOSING_DATA_CONNECTION
  1814.         Case FTP_RESPONSE_ENTERING_PASSIVE_MODE
  1815.         Case FTP_RESPONSE_USER_LOGGED_IN
  1816.         Case FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED
  1817.         Case FTP_RESPONSE_PATHNAME_CREATED
  1818.         Case FTP_RESPONSE_USER_NAME_OK_NEED_PASSWORD
  1819.             m_LastError = ERROR_FTP_PROTOCOL_USER_NAME_OK_NEED_PASSWORD
  1820.         Case FTP_RESPONSE_NEED_ACCOUNT_FOR_LOGIN
  1821.             m_LastError = ERROR_FTP_PROTOCOL_NEED_ACCOUNT_FOR_LOGIN
  1822.         Case FTP_RESPONSE_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFO
  1823.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFO
  1824.         Case FTP_RESPONSE_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION
  1825.             m_LastError = ERROR_FTP_PROTOCOL_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION
  1826.             m_strLastErrorDesc = "Service not available, closing control connection."
  1827.         Case FTP_RESPONSE_CANNOT_OPEN_DATA_CONNECTION
  1828.             m_strLastErrorDesc = "Can't open data connection."
  1829.             m_LastError = ERROR_FTP_PROTOCOL_CANNOT_OPEN_DATA_CONNECTION
  1830.         Case FTP_RESPONSE_CONNECTION_CLOSED_TRANSFER_ABORTED
  1831.             m_strLastErrorDesc = "Connection closed; transfer aborted."
  1832.             m_LastError = ERROR_FTP_PROTOCOL_CONNECTION_CLOSED_TRANSFER_ABORTED
  1833.         Case FTP_RESPONSE_REQUESTED_FILE_ACTION_NOT_TAKEN
  1834.             m_strLastErrorDesc = "Requested file action not taken."
  1835.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN
  1836.         Case FTP_RESPONSE_REQUESTED_ACTION_ABORTED
  1837.             m_strLastErrorDesc = "Requested action aborted: local error in processing."
  1838.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_ACTION_ABORTED
  1839.         Case FTP_RESPONSE_REQUESTED_ACTION_NOT_TAKEN
  1840.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN
  1841.             m_strLastErrorDesc = "Requested action not taken. Insufficient storage space in system."
  1842.         Case FTP_RESPONSE_SYNTAX_ERROR_COMMAND_UNRECOGNIZED
  1843.             m_strLastErrorDesc = "Syntax error, command unrecognized."
  1844.             m_LastError = ERROR_FTP_PROTOCOL_SYNTAX_ERROR_COMMAND_UNRECOGNIZED
  1845.         Case FTP_RESPONSE_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS
  1846.             m_strLastErrorDesc = "Syntax error in parameters or arguments."
  1847.             m_LastError = ERROR_FTP_PROTOCOL_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS
  1848.         Case FTP_RESPONSE_COMMAND_NOT_IMPLEMENTED
  1849.             m_strLastErrorDesc = "Command not implemented."
  1850.             m_LastError = ERROR_FTP_PROTOCOL_COMMAND_NOT_IMPLEMENTED
  1851.         Case FTP_RESPONSE_BAD_SEQUENCE_OF_COMMANDS
  1852.             m_strLastErrorDesc = "Bad sequence of commands."
  1853.             m_LastError = ERROR_FTP_PROTOCOL_BAD_SEQUENCE_OF_COMMANDS
  1854.         Case FTP_RESPONSE_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER
  1855.             m_strLastErrorDesc = "Command not implemented for that parameter."
  1856.             m_LastError = ERROR_FTP_PROTOCOL_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER
  1857.         Case FTP_RESPONSE_NOT_LOGGED_IN
  1858.             m_strLastErrorDesc = "Not logged in."
  1859.             m_LastError = ERROR_FTP_PROTOCOL_NOT_LOGGED_IN
  1860.         Case FTP_RESPONSE_NEED_ACCOUNT_FOR_STORING_FILES
  1861.             m_strLastErrorDesc = "Need account for storing files."
  1862.             m_LastError = ERROR_FTP_PROTOCOL_NEED_ACCOUNT_FOR_STORING_FILES
  1863.         Case FTP_RESPONSE_REQUESTED_ACTION_NOT_TAKEN_FILE_UNAVAILABLE
  1864.             m_strLastErrorDesc = "Requested action not taken. File unavailable (e.g., file not found, no access)."
  1865.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN_FILE_UNAVAILABLE
  1866.         Case FTP_RESPONSE_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN
  1867.             m_strLastErrorDesc = "Requested action aborted: page type unknown."
  1868.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN
  1869.         Case FTP_RESPONSE_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE_ALLOCATION
  1870.             m_strLastErrorDesc = "Requested file action aborted. Exceeded storage allocation (for current directory or dataset)."
  1871.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE_ALLOCATION
  1872.         Case FTP_RESPONSE_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED
  1873.             m_strLastErrorDesc = "Requested action not taken. File name not allowed."
  1874.             m_LastError = ERROR_FTP_PROTOCOL_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED
  1875.         Case Else
  1876.             ProcessFtpResponse = False
  1877.             Exit Function
  1878.     End Select
  1879.     
  1880.     ProcessFtpResponse = True
  1881.     
  1882. End Function
  1883. Public Function GetCurrentDirectory() As String
  1884.     m_bBusy = True
  1885.     If ProcessPWDCommand Then
  1886.         GetCurrentDirectory = m_strCurrentDirectory
  1887.     End If
  1888.     m_bBusy = False
  1889.     
  1890. End Function
  1891. Private Function ProcessQUITCommand() As Boolean
  1892.     Dim strResponse As String
  1893.     Dim strData     As String
  1894.     
  1895.     On Error GoTo ProcessQUITCommand_Err_Handler
  1896.     
  1897.     wscControl.SendData "QUIT" & vbCrLf
  1898.     Debug.Print "QUIT"
  1899.     
  1900.     m_objTimeOut.StartTimer
  1901.     Do
  1902.         DoEvents
  1903.         '
  1904.         If m_objTimeOut.Timeout Then
  1905.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1906.             Exit Do
  1907.         End If
  1908.         '
  1909.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1910.             strData = m_strWinsockBuffer
  1911.             m_strWinsockBuffer = ""
  1912.             Exit Do
  1913.         End If
  1914.     Loop
  1915.     m_objTimeOut.StopTimer
  1916.     
  1917.     If GetResponseCode(strData) = FTP_RESPONSE_SERVICE_CLOSING_CONTROL_CONNECTION Then
  1918.         ProcessQUITCommand = True
  1919.     Else
  1920.         ProcessFtpResponse GetResponseCode(strData)
  1921.     End If
  1922.     
  1923. Exit_Label:
  1924.     Exit Function
  1925. ProcessQUITCommand_Err_Handler:
  1926.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1927.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessQUITCommand", Err.Description
  1928.     End If
  1929.     GoTo Exit_Label
  1930.     
  1931. End Function
  1932. Private Function ProcessABORCommand() As Boolean
  1933.     Dim strResponse As String
  1934.     Dim strData     As String
  1935.     
  1936.     On Error GoTo ProcessABORCommand_Err_Handler
  1937.     
  1938.     wscControl.SendData "ABOR" & vbCrLf
  1939.     Debug.Print "ABOR"
  1940.     
  1941.     m_objTimeOut.StartTimer
  1942.     Do
  1943.         DoEvents
  1944.         '
  1945.         If m_objTimeOut.Timeout Then
  1946.             m_LastError = ERROR_FTP_USER_TIMEOUT
  1947.             Exit Do
  1948.         End If
  1949.         '
  1950.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  1951.             strData = m_strWinsockBuffer
  1952.             m_strWinsockBuffer = "226" & vbCrLf
  1953.             Exit Do
  1954.         End If
  1955.     Loop
  1956.     m_objTimeOut.StopTimer
  1957.     
  1958.     If GetResponseCode(strData) = 426 Then
  1959.         ProcessABORCommand = True
  1960.     Else
  1961.         ProcessFtpResponse GetResponseCode(strData)
  1962.     End If
  1963.     
  1964. Exit_Label:
  1965.     Exit Function
  1966. ProcessABORCommand_Err_Handler:
  1967.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  1968.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessABORCommand", Err.Description
  1969.     End If
  1970.     GoTo Exit_Label
  1971.     
  1972. End Function
  1973. Public Function CancelTransfer() As Boolean
  1974.     m_bBusy = True
  1975.     If ProcessABORCommand Then
  1976.         CancelTransfer = True
  1977.     End If
  1978.     If m_bTransferInProgress Or m_bUploadFile Then
  1979.         Close m_intLocalFileID
  1980.         m_strDataBuffer = ""
  1981.         m_lDownloadedBytes = 0
  1982.         m_lUploadedBytes = 0
  1983.         m_bTransferInProgress = False
  1984.         m_bUploadFile = False
  1985.     End If
  1986.     m_bFileIsOpened = False
  1987.     m_objTimeOut.StopTimer
  1988. '    wscData.Close
  1989.     m_bBusy = False
  1990.     
  1991. End Function
  1992. Public Function SetParentAsCurrentDirectory() As Boolean
  1993.     m_bBusy = True
  1994.     SetParentAsCurrentDirectory = ProcessCDUPCommand
  1995.     m_bBusy = False
  1996.     
  1997. End Function
  1998. Private Function ProcessCDUPCommand() As Boolean
  1999.     Dim strResponse As String
  2000.     Dim strData     As String
  2001.     
  2002.     On Error GoTo ProcessCDUPCommand_Err_Handler
  2003.     
  2004.     wscControl.SendData "CDUP" & vbCrLf
  2005.     Debug.Print "CDUP"
  2006.     
  2007.     m_objTimeOut.StartTimer
  2008.     Do
  2009.         DoEvents
  2010.         '
  2011.         If m_objTimeOut.Timeout Then
  2012.             m_LastError = ERROR_FTP_USER_TIMEOUT
  2013.             Exit Do
  2014.         End If
  2015.         '
  2016.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  2017.             strData = m_strWinsockBuffer
  2018.             m_strWinsockBuffer = ""
  2019.             Exit Do
  2020.         End If
  2021.     Loop
  2022.     m_objTimeOut.StopTimer
  2023.     
  2024.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  2025.         ProcessCDUPCommand = True
  2026.     Else
  2027.         ProcessFtpResponse GetResponseCode(strData)
  2028.     End If
  2029.     
  2030. Exit_Label:
  2031.     Exit Function
  2032. ProcessCDUPCommand_Err_Handler:
  2033.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  2034.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessCDUPCommand", Err.Description
  2035.     End If
  2036.     GoTo Exit_Label
  2037.     
  2038. End Function
  2039. Private Function ProcessCWDCommand(strNewDir As String) As Boolean
  2040.     Dim strResponse As String
  2041.     Dim strData     As String
  2042.     
  2043.     On Error GoTo ProcessCWDCommand_Err_Handler
  2044.         
  2045.     wscControl.SendData "CWD " & strNewDir & vbCrLf
  2046.     Debug.Print "CWD " & strNewDir
  2047.     
  2048.     m_objTimeOut.StartTimer
  2049.     Do
  2050.         DoEvents
  2051.         '
  2052.         If m_objTimeOut.Timeout Then
  2053.             m_LastError = ERROR_FTP_USER_TIMEOUT
  2054.             Exit Do
  2055.         End If
  2056.         '
  2057.         If InStr(1, m_strWinsockBuffer, vbCrLf) > 0 Then
  2058.             strData = m_strWinsockBuffer
  2059.             m_strWinsockBuffer = ""
  2060.             Exit Do
  2061.         End If
  2062.     Loop
  2063.     m_objTimeOut.StopTimer
  2064.     If GetResponseCode(strData) = FTP_RESPONSE_REQUESTED_FILE_ACTION_OK_COMPLETED Then
  2065.         ProcessCWDCommand = True
  2066.     Else
  2067.         ProcessFtpResponse GetResponseCode(strData)
  2068.     End If
  2069.     
  2070. Exit_Label:
  2071.     Exit Function
  2072. ProcessCWDCommand_Err_Handler:
  2073.     If Not ProcessWinsockError(Err.Number, Err.Description) Then
  2074.         Err.Raise vbObjectError + 1000 + Err.Number, "CFtpConnection.ProcessCWDCommand", Err.Description
  2075.     End If
  2076.     GoTo Exit_Label
  2077. End Function
  2078. Public Function GetFtpErrorDescription() As String
  2079.     GetFtpErrorDescription = m_strLastErrorDesc
  2080. End Function
  2081. Public Function CloseConnection() As Boolean
  2082.     m_bBusy = True
  2083.     If m_bTransferInProgress Or m_bUploadFile Then
  2084.         m_LastError = ERROR_FTP_USER_TRANSFER_IN_PROGRESS
  2085.         m_strLastErrorDesc = "Can't close control connection. Transfer in progress."
  2086.     Else
  2087.         CloseConnection = ProcessQUITCommand
  2088.         wscData.Close
  2089.         wscControl.Close
  2090.     End If
  2091.     m_bBusy = False
  2092.     
  2093. End Function