VBSOCK.BAS
上传用户:guantou168
上传日期:2015-06-25
资源大小:74k
文件大小:30k
源码类别:

Ftp服务器

开发平台:

Visual Basic

  1. Attribute VB_Name = "VBSOCK"
  2. Option Explicit
  3. Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Dest As Any, Src As Any, ByVal cb&)
  4. Public Declare Function lstrlen Lib "kernel32" (ByVal lpString As Any) As Integer
  5. Public DnsHost As String
  6. Public MaxSockets As Integer
  7. Public MaxUDP As Long
  8. Public Description As String
  9. Public Status As String
  10. Public sintax_error_list(10) As String 'the list of the messages which signal a sintax error in a FTP command
  11. Public users(MAX_N_USERS) As User
  12. Public Type file_info
  13.   Full_Name As String
  14.   data_representation As String * 1
  15.   open_file As Integer
  16.   retr_stor As Integer  '0=RETR; 1=STOR
  17.   Buffer As String  'contains data to send
  18.   File_Len As Long  '--- Binary mode only
  19.   blocks As Long  'number of 1024 bytes blocks in file
  20.   spare_bytes As Long
  21.   next_block As Long  'next block to send
  22.   next_byte As Long  'points to position in file of the next block to send
  23.   try_again As Integer  'if try_again=true the old line is sent =Ascii mode only
  24. End Type
  25. Public files_info(5) As file_info
  26. 'contains error during function call
  27. Public retf As Integer
  28. '*** Variables used during TCP/IP exchange
  29. 'slot number assigned to Server
  30. Public ServerSlot As Long
  31. 'number of clients connected to server
  32. Public num_users As Integer
  33. Public ListenSock As Long
  34. Public NewSlot As Long
  35. '-------------------------------------
  36. 'used by jenny
  37.  Public FTP_Index As Integer
  38.  Public FTP_Command As String
  39.  Public FTP_Args() As String
  40. Function ConnectSocket(ByVal hWndtyp As Long, ByVal Host As String, ByVal Port As Integer) As Long
  41.   Dim SockreadBuffer As String, RetIpPort As String
  42.   Dim s As Long, Dummy As Long
  43.   'Dim NewSock As SockAddr
  44.   Dim SelectOps As Integer
  45.     
  46.     SockreadBuffer = ""
  47.     SockAddr.sin_family = AF_INET
  48.     SockAddr.sin_port = htons(Port)
  49.     If Val(SockAddr.sin_zero) = INVALID_SOCKET Then
  50.         ConnectSocket = INVALID_SOCKET
  51.         Exit Function
  52.     End If
  53.     SockAddr.sin_addr = GetHostByNameAlias(Host)
  54.     If SockAddr.sin_addr = INADDR_NONE Then
  55.         ConnectSocket = INVALID_SOCKET
  56.         Exit Function
  57.     End If
  58.     RetIpPort = GetAscIP(SockAddr.sin_addr) & ":" & ntohs(SockAddr.sin_port)
  59.     Debug.Print RetIpPort
  60.     s = Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
  61.     If s < 0 Then
  62.         ConnectSocket = INVALID_SOCKET
  63.         Exit Function
  64.     End If
  65.     'If SetSockLinger(S, 1, 0) = SOCKET_ERROR Then
  66.     '    If S > 0 Then
  67.     '       Dummy = closesocket(S)
  68.     '    End If
  69.     '    ConnectSocket = INVALID_SOCKET
  70.     '    Exit Function
  71.     'End If
  72.     SelectOps = FD_CONNECT Or FD_READ Or FD_WRITE Or FD_CLOSE Or FD_ACCEPT
  73.     If WSAAsyncSelect(s, hWndtyp, ByVal 5152, ByVal SelectOps) Then
  74.         If s > 0 Then
  75.             Dummy = closesocket(s)
  76.         End If
  77.         ConnectSocket = INVALID_SOCKET
  78.         Exit Function
  79.     End If
  80.     If connect(s, SockAddr, SockAddr_Size) <> -1 Then
  81.         If s > 0 Then
  82.             Dummy = closesocket(s)
  83.         End If
  84.         ConnectSocket = INVALID_SOCKET
  85.         Exit Function
  86.     End If
  87.     ConnectSocket = s
  88. End Function
  89. Function WSAGetSelectEvent(ByVal lParam As Long) As Long
  90.     WSAGetSelectEvent = Int(lParam Mod 65536)
  91. End Function
  92. 'Public Function WSAGetSelectEvent(ByVal lParam As Long) As Integer
  93. '    If (lParam And &HFFFF&) > &H7FFF Then
  94. '        WSAGetSelectEvent = (lParam And &HFFFF&) - &H10000
  95. '    Else
  96. '        WSAGetSelectEvent = lParam And &HFFFF&
  97. '    End If
  98. 'End Function
  99. Public Function WSAGetAsyncError(ByVal lParam As Long) As Long
  100.     WSAGetAsyncError = (lParam And &HFFFF0000)  &H10000
  101. End Function
  102. Function DNS_Lookup(ByVal dnsip As String) As String
  103.   DnsHost = ""
  104.   vbWSAStartup
  105.   DoEvents
  106.   DNS_Lookup = vbGetHostByAddress(dnsip)
  107.   DoEvents
  108.   vbWSACleanup
  109. End Function
  110. Function vbGetHostByAddress(ByVal sAddress As String) As String
  111.   Dim lAddress As Long
  112.   Dim PointerToMemoryLocation As Long
  113.   Dim HostName As String
  114.   Dim hostent As hostent
  115.   lAddress = inet_addr(sAddress)
  116.   PointerToMemoryLocation = gethostbyaddr(lAddress, 4, PF_INET)
  117.   If PointerToMemoryLocation <> 0 Then
  118.     CopyMemory hostent, ByVal PointerToMemoryLocation, Len(hostent)
  119.     HostName = String(256, 0)
  120.     CopyMemory ByVal HostName, ByVal hostent.h_name, 256
  121.     If HostName = "" Then
  122.       vbGetHostByAddress = "Unable to Resolve Address"
  123.     Else
  124.       vbGetHostByAddress = Left(HostName, InStr(HostName, Chr(0)) - 1)
  125.     End If
  126.   Else
  127.     vbGetHostByAddress = "No DNS Entry"
  128.   End If
  129. End Function
  130. Function LoByte(ByVal wParam As Integer)
  131.   LoByte = wParam And &HFF&
  132. End Function
  133. Function HiByte(ByVal wParam As Integer)
  134.   HiByte = wParam / &H100 And &HFF&
  135. End Function
  136. Sub vbWSAStartup()
  137.   Dim iReturn As Integer
  138.   Dim sHighByte As String
  139.   Dim sLowByte As String
  140.   Dim sMsg As String
  141.   Dim i As Integer
  142.   iReturn = WSAStartup(&H101, WSAdata)
  143.    If LoByte(WSAdata.wVersion) < WS_VERSION_MAJOR Or _
  144.     (LoByte(WSAdata.wVersion) = WS_VERSION_MAJOR _
  145.     And HiByte(WSAdata.wVersion) < WS_VERSION_MINOR) Then
  146.         sHighByte = Trim(str(HiByte(WSAdata.wVersion)))
  147.         sLowByte = Trim(str(LoByte(WSAdata.wVersion)))
  148.     End If
  149.     If WSAdata.iMaxSockets < MIN_SOCKETS_REQD Then
  150.         sMsg = "This application requires a minimum of "
  151.         sMsg = sMsg & Trim$(str$(MIN_SOCKETS_REQD)) & " supported sockets."
  152.     End If
  153.     MaxSockets = WSAdata.iMaxSockets
  154.     If MaxSockets < 0 Then
  155.         MaxSockets = 65536 + MaxSockets
  156.     End If
  157.     MaxUDP = WSAdata.iMaxUdpDg
  158.     If MaxUDP < 0 Then
  159.         MaxUDP = 65536 + MaxUDP
  160.     End If
  161.     Description = WSAdata.szDescription
  162.     Status = ""
  163.     Status = WSAdata.szSystemStatus
  164. End Sub
  165. Sub vbWSACleanup()
  166.   Dim iReturn As Long
  167.   Dim sMsg As String
  168.   iReturn = WSACleanup()
  169.   If iReturn <> 0 Then
  170.     sMsg = "WSock32 Error - " & Trim$(str$(iReturn)) & " occurred in Cleanup"
  171.   End If
  172. End Sub
  173. 'returns IP as long, in network byte order
  174. Public Function GetHostByNameAlias(ByVal HostName$) As Long
  175.     'Return IP address as a long, in network byte order
  176.     Dim phe&
  177.     Dim heDestHost As hostent
  178.     Dim addrList&
  179.     Dim retIP&
  180.     retIP = inet_addr(HostName$)
  181.     If retIP = INADDR_NONE Then
  182.         phe = gethostbyname(HostName$)
  183.         If phe <> 0 Then
  184.             CopyMemory heDestHost, ByVal phe, Len(heDestHost)
  185.             CopyMemory addrList, ByVal heDestHost.h_addr_list, 4
  186.             CopyMemory retIP, ByVal addrList, heDestHost.h_length
  187.         Else
  188.             retIP = INADDR_NONE
  189.         End If
  190.     End If
  191.     GetHostByNameAlias = retIP
  192. End Function
  193. Public Function GetAscIP(ByVal inn As Long) As String
  194.   Dim nStr&
  195.   Dim lpStr&
  196.   Dim retString$
  197.   retString = String(32, 0)
  198.   lpStr = inet_ntoa(inn)
  199.   If lpStr Then
  200.     nStr = lstrlen(lpStr)
  201.     If nStr > 32 Then nStr = 32
  202.     CopyMemory ByVal retString, ByVal lpStr, nStr
  203.     retString = Left(retString, nStr)
  204.     GetAscIP = retString
  205.   Else
  206.     GetAscIP = "255.255.255.255"
  207.   End If
  208. End Function
  209. Public Function SetSockLinger(ByVal SockNum As Long, ByVal OnOff As Integer, ByVal LingerTime As Integer) As Long
  210.     Dim Linger As LingerType
  211.     Linger.l_onoff = OnOff
  212.     Linger.l_linger = LingerTime
  213.     If setsockopt(SockNum, SOL_SOCKET, SO_LINGER, Linger, 4) Then
  214.         Debug.Print "Error setting linger info: " & WSAGetLastError()
  215.         SetSockLinger = SOCKET_ERROR
  216.     Else
  217.         If getsockopt(SockNum, SOL_SOCKET, SO_LINGER, Linger, 4) Then
  218.             Debug.Print "Error getting linger info: " & WSAGetLastError()
  219.             SetSockLinger = SOCKET_ERROR
  220.         Else
  221.             Debug.Print "Linger is on if nonzero: "; Linger.l_onoff
  222.             Debug.Print "Linger time if linger is on: "; Linger.l_linger
  223.         End If
  224.     End If
  225. End Function
  226. Public Function ListenForConnect(ByVal Port&, ByVal HWndToMsg&) As Long
  227. Dim s As Long, Dummy As Long
  228. Dim SelectOps As Integer
  229.     s = Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
  230.     If s < 0 Then
  231.         ListenForConnect = INVALID_SOCKET
  232.         Exit Function
  233.     End If
  234.     
  235.     SockAddr.sin_family = AF_INET
  236.     SockAddr.sin_port = htons(Port)
  237.     If SockAddr.sin_port = INVALID_SOCKET Then
  238.         ListenForConnect = INVALID_SOCKET
  239.         Exit Function
  240.     End If
  241.     SockAddr.sin_addr = htonl(INADDR_ANY)
  242.     If SockAddr.sin_addr = INADDR_NONE Then
  243.         ListenForConnect = INVALID_SOCKET
  244.         Exit Function
  245.     End If
  246.     If bind(s, SockAddr, SockAddr_Size) Then
  247.         If s > 0 Then
  248.             Dummy = closesocket(s)
  249.         End If
  250.         ListenForConnect = INVALID_SOCKET
  251.         Exit Function
  252.     End If
  253.     
  254.     If listen(s, 1) Then
  255.         If s > 0 Then
  256.             Dummy = closesocket(s)
  257.         End If
  258.         ListenForConnect = INVALID_SOCKET
  259.         Exit Function
  260.     End If
  261.     
  262.     SelectOps = FD_CONNECT Or FD_READ Or FD_WRITE Or FD_CLOSE Or FD_ACCEPT
  263.     If WSAAsyncSelect(s, HWndToMsg, ByVal 5150, ByVal SelectOps) Then
  264.         If s > 0 Then
  265.             Dummy = closesocket(s)
  266.         End If
  267.         ListenForConnect = SOCKET_ERROR
  268.         Exit Function
  269.     End If
  270.     ListenForConnect = s
  271. End Function
  272. Function GetWSAErrorString(ByVal errnum As Long) As String
  273.   On Error Resume Next
  274.   Select Case errnum
  275.   Case 10004: GetWSAErrorString = "Interrupted system call."
  276.   Case 10009: GetWSAErrorString = "Bad file number."
  277.   Case 10013: GetWSAErrorString = "Permission Denied."
  278.   Case 10014: GetWSAErrorString = "Bad Address."
  279.   Case 10022: GetWSAErrorString = "Invalid Argument."
  280.   Case 10024: GetWSAErrorString = "Too many open files."
  281.   Case 10035: GetWSAErrorString = "Operation would block."
  282.   Case 10036: GetWSAErrorString = "Operation now in progress."
  283.   Case 10037: GetWSAErrorString = "Operation already in progress."
  284.   Case 10038: GetWSAErrorString = "Socket operation on nonsocket."
  285.   Case 10039: GetWSAErrorString = "Destination address required."
  286.   Case 10040: GetWSAErrorString = "Message too long."
  287.   Case 10041: GetWSAErrorString = "Protocol wrong type for socket."
  288.   Case 10042: GetWSAErrorString = "Protocol not available."
  289.   Case 10043: GetWSAErrorString = "Protocol not supported."
  290.   Case 10044: GetWSAErrorString = "Socket type not supported."
  291.   Case 10045: GetWSAErrorString = "Operation not supported on socket."
  292.   Case 10046: GetWSAErrorString = "Protocol family not supported."
  293.   Case 10047: GetWSAErrorString = "Address family not supported by protocol family."
  294.   Case 10048: GetWSAErrorString = "Address already in use."
  295.   Case 10049: GetWSAErrorString = "Can't assign requested address."
  296.   Case 10050: GetWSAErrorString = "Network is down."
  297.   Case 10051: GetWSAErrorString = "Network is unreachable."
  298.   Case 10052: GetWSAErrorString = "Network dropped connection."
  299.   Case 10053: GetWSAErrorString = "Software caused connection abort."
  300.   Case 10054: GetWSAErrorString = "Connection reset by peer."
  301.   Case 10055: GetWSAErrorString = "No buffer space available."
  302.   Case 10056: GetWSAErrorString = "Socket is already connected."
  303.   Case 10057: GetWSAErrorString = "Socket is not connected."
  304.   Case 10058: GetWSAErrorString = "Can't send after socket shutdown."
  305.   Case 10059: GetWSAErrorString = "Too many references: can't splice."
  306.   Case 10060: GetWSAErrorString = "Connection timed out."
  307.   Case 10061: GetWSAErrorString = "Connection refused."
  308.   Case 10062: GetWSAErrorString = "Too many levels of symbolic links."
  309.   Case 10063: GetWSAErrorString = "File name too long."
  310.   Case 10064: GetWSAErrorString = "Host is down."
  311.   Case 10065: GetWSAErrorString = "No route to host."
  312.   Case 10066: GetWSAErrorString = "Directory not empty."
  313.   Case 10067: GetWSAErrorString = "Too many processes."
  314.   Case 10068: GetWSAErrorString = "Too many users."
  315.   Case 10069: GetWSAErrorString = "Disk quota exceeded."
  316.   Case 10070: GetWSAErrorString = "Stale NFS file handle."
  317.   Case 10071: GetWSAErrorString = "Too many levels of remote in path."
  318.   Case 10091: GetWSAErrorString = "Network subsystem is unusable."
  319.   Case 10092: GetWSAErrorString = "Winsock DLL cannot support this application."
  320.   Case 10093: GetWSAErrorString = "Winsock not initialized."
  321.   Case 10101: GetWSAErrorString = "Disconnect."
  322.   Case 11001: GetWSAErrorString = "Host not found."
  323.   Case 11002: GetWSAErrorString = "Nonauthoritative host not found."
  324.   Case 11003: GetWSAErrorString = "Nonrecoverable error."
  325.   Case 11004: GetWSAErrorString = "Valid name, no data record of requested type."
  326.   Case Else:  GetWSAErrorString = "Unknown Error..."
  327.   End Select
  328. End Function
  329. Public Function args_ctrl(ArgS As String, Type_Args As String, ByRef argument() As String) As Integer
  330.   Dim Dummy As String
  331.   Dim len_args As Integer, i As Integer, ascii As Integer
  332.   Dim s As Integer, e As Integer
  333.   Dim S1 As String
  334.   
  335.   ReDim h(6) As Long
  336.   
  337.   'the arguments of type <username>, <password> and
  338.   '<pathname> are strings
  339.   If Type_Args = "username" Or Type_Args = "password" _
  340.   Or Type_Args = "pathname" Then
  341.     Type_Args = "string"
  342.   End If
  343.   
  344.   'command Ok
  345.   args_ctrl = 0
  346.   
  347.   len_args = Len(ArgS)
  348.   
  349.   Select Case Type_Args
  350.   
  351.   Case "string" '<string>  <string:= char | char&string>
  352.     For i = 1 To len_args
  353.       ascii = Asc(Mid$(ArgS, i, 1))
  354.       If ascii < 32 Or ascii > 126 Then      'only printable characters
  355.         args_ctrl = 3           'sintax error in parameters or arguments
  356.         Exit For
  357.       End If
  358.     Next
  359.     argument(0) = ArgS
  360.   Case "host-port" '<h1,h2,h3,h4,p1,p2>  <h?:=1..255>  <p?:=1..255>
  361.     '<Host> is formed by 4 elements, divided by comma, which representing IP address;
  362.     '<port> is formed by 2 elements, divided by comma, which representing the MSB and LSB of the port.
  363.     'add a separator for simplifing the procedure
  364.     Dummy = ArgS & ","
  365.     Debug.Print "Port String = " & Dummy
  366.     e = 1    'point to next element
  367.     For i = 1 To 6
  368.       s = InStr(e, Dummy, ",") 's point to next separator (ie. comma)
  369.       If s = 0 Then
  370.         args_ctrl = 3          'sintax error in parameters or arguments
  371.         Exit For
  372.       Else
  373.         'every element of the argument must be an integer,
  374.         'represented as string, in the range 1 to 255
  375.         h(i) = Val(Mid$(Dummy, e, s - e))
  376.         Debug.Print "h(" & CStr(i) & ") = " & h(i)
  377.         If h(i) < 0 Or h(i) > 255 Then
  378.           args_ctrl = 3       'sintax error in parameters or arguments
  379.           Exit For
  380.         End If
  381.       End If
  382.       e = s + 1       'point to next element
  383.     Next
  384.     argument(0) = Format$(h(1))              'IP address
  385.     argument(1) = Format$(h(2))
  386.     argument(2) = Format$(h(3))
  387.     argument(3) = Format$(h(4))
  388.     argument(4) = Format$(h(5) * 256 + h(6)) 'port
  389.   
  390.   Case "type-code"  '<A [A N] | I>
  391.     S1 = InStr(ArgS, " ")
  392.     If S1 = 0 Then
  393.       If ArgS = "A" Or ArgS = "" Then
  394.         'arguments assume default values
  395.         argument(0) = "A"  'Ascii
  396.         argument(1) = "N"  'No print
  397.       ElseIf ArgS = "E" Then
  398.         'command not implemented for that parameter
  399.         args_ctrl = 6
  400.         argument(0) = ArgS
  401.       ElseIf ArgS = "I" Then
  402.         argument(0) = "I"
  403.       Else
  404.         'sintax error in parameters or arguments
  405.         args_ctrl = 3
  406.         argument(0) = ArgS
  407.       End If
  408.     Else
  409.       If Left$(ArgS, S1 - 1) = "A" Then
  410.         argument(0) = "A"
  411.         While Mid$(ArgS, S1, 1) = " "
  412.           S1 = S1 + 1
  413.         Wend
  414.         If Mid$(ArgS, S1) = "" Or Mid$(ArgS, S1) = "N" Then
  415.           argument(1) = "N"
  416.         ElseIf Mid$(ArgS, S1) = "T" Then
  417.           'command not implemented for that parameter
  418.           args_ctrl = 6
  419.           argument(1) = Mid$(ArgS, S1)
  420.         ElseIf Mid$(ArgS, S1) = "C" Then
  421.           'command not implemented for that parameter
  422.           args_ctrl = 6
  423.           argument(1) = Mid$(ArgS, S1)
  424.         Else
  425.           'sintax error in parameters or arguments
  426.           args_ctrl = 3
  427.           argument(1) = Mid$(ArgS, S1)
  428.         End If
  429.       ElseIf Left$(ArgS, S1 - 1) = "L" Then
  430.         'command not implemented for that parameter
  431.         args_ctrl = 6
  432.         argument(1) = Mid$(ArgS, S1)
  433.       ElseIf Left$(ArgS, S1 - 1) = "I" Then
  434.         argument(0) = "I"
  435.       Else
  436.         'sintax error in parameters or arguments
  437.         args_ctrl = 3
  438.         argument(0) = Left$(ArgS, S1 - 1)
  439.       End If
  440.     End If
  441.   
  442.   Case "mode-code"  '<S>
  443.     If ArgS = "" Or ArgS = "S" Then
  444.       'argument assumes default value
  445.       argument(0) = "S"  'Stream
  446.     ElseIf ArgS = "B" Then
  447.       'command not implemented for that parameter
  448.       args_ctrl = 6
  449.       argument(0) = ArgS
  450.     ElseIf ArgS = "C" Then
  451.       'command not implemented for that parameter
  452.       args_ctrl = 6
  453.       argument(0) = ArgS
  454.     Else
  455.       'sintax error in parameters or arguments
  456.       args_ctrl = 3
  457.       argument(0) = Left$(ArgS, S1 - 1)
  458.     End If
  459.   Case "structure-code"  '<F | R>
  460.     If ArgS = "" Or ArgS = "F" Then
  461.       'argument assumes default value
  462.       argument(0) = "F" 'File
  463.     ElseIf ArgS = "R" Then
  464.       'command not implemented for that parameter
  465.       args_ctrl = 6
  466.       argument(0) = ArgS
  467.     ElseIf ArgS = "P" Then
  468.       'command not implemented for that parameter
  469.       args_ctrl = 6
  470.       argument(0) = ArgS
  471.     Else
  472.       'sintax error in parameters or arguments
  473.       args_ctrl = 3
  474.       argument(0) = ArgS
  475.     End If
  476.   
  477.   End Select
  478. End Function
  479. Public Function close_data_connect(ID_User As Integer) As Integer
  480.   
  481.   retf = closesocket(users(ID_User).data_slot)
  482.   If retf = 0 Then
  483.     'updates user record
  484.     users(ID_User).data_slot = INVALID_SOCKET
  485.     users(ID_User).IP_Address = ""
  486.     users(ID_User).Port = 0
  487.     users(ID_User).State = Service_Commands ' 2
  488.   End If
  489.   close_data_connect = retf
  490. End Function
  491. Public Function logoff(ID_User As Integer) As Integer
  492.   retf = send_reply("221 Closing control connection, GoodBye!", ID_User)
  493.   retf = closesocket(users(ID_User).control_slot)
  494.   If retf = 0 Then
  495.     're-initialize the record containing user informations
  496.     users(ID_User).list_index = 0
  497.     users(ID_User).control_slot = INVALID_SOCKET
  498.     users(ID_User).data_slot = INVALID_SOCKET
  499.     users(ID_User).IP_Address = ""
  500.     users(ID_User).Port = 0
  501.     users(ID_User).data_representation = "A"
  502.     users(ID_User).data_format_ctrls = "N"
  503.     users(ID_User).data_structure = "F"
  504.     users(ID_User).data_tx_mode = "S"
  505.     users(ID_User).cur_dir = ""
  506.     users(ID_User).State = Log_In_Out ' 0
  507.     users(ID_User).full = False
  508.     users(ID_User).Jenny.Terminate
  509.     Set users(ID_User).Jenny = Nothing
  510.   Else
  511.  '   frmFTP.StatusBar.Panels(1) = "Error: Couldn't Close Connection!"
  512.   End If
  513.   num_users = num_users - 1
  514.  ' frmFTP.UsrCnt = CStr(num_users)
  515.   logoff = retf
  516. End Function
  517. Public Function open_data_connect(ID_User As Integer) As Integer
  518.   
  519.   'open data connection
  520.   retf = send_reply("150 Open data connection.", ID_User)
  521.   open_data_connect = retf
  522. End Function
  523. Public Function receive_data(RecvBuffer As String, ID_User As Integer) As Integer
  524.   Dim fixstr As String * 1024
  525.   'receives data on connection
  526.   retf = recv(users(ID_User).data_slot, fixstr, 1024, 0)
  527.   If retf > 0 Then
  528.     RecvBuffer = Left$(fixstr, retf)
  529.   End If
  530.   receive_data = retf
  531. End Function
  532. Public Function send_data(data_ As String, ID_User As Integer) As Integer
  533.   Dim WriteBuffer As String
  534.   Dim lenBuffer As Integer
  535.   'sends data on connection
  536.   WriteBuffer = data_
  537.   lenBuffer = Len(WriteBuffer)
  538.   retf = send(users(ID_User).data_slot, WriteBuffer, lenBuffer, 0)
  539.   send_data = retf
  540. End Function
  541. Public Function send_reply(reply As String, ID_User As Integer) As Integer
  542.   Dim WriteBuffer As String
  543.   Dim lenBuffer As Integer
  544.   WriteBuffer = reply & vbCrLf
  545.   lenBuffer = Len(WriteBuffer)
  546.   retf = send(users(ID_User).control_slot, WriteBuffer, lenBuffer, 0)
  547.   If retf = SOCKET_ERROR Then
  548. '    ServerLog "Error sending reply:" & CStr(retf)
  549.   Else
  550.     'log replies
  551. '    ServerLog "<" & Format$(ID_User, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ") & reply
  552.   End If
  553.   send_reply = retf
  554. End Function
  555. Public Function sintax_ctrl(cmd As String, ByRef Kwrd As String, ByRef argument() As String) As Integer
  556.   Dim ArgS As String
  557.   Dim k As Integer
  558.   Dim len_cmd As Integer
  559.   
  560.   'the command must be terminated by CR&LF characters
  561.   len_cmd = InStr(cmd, vbCrLf) - 1
  562.   If len_cmd = 0 Then
  563.     sintax_ctrl = 2 'sintax error, command unrecognized
  564.     Exit Function
  565.   Else
  566.     'suppresses CR&LF characters
  567.     cmd = Left$(cmd, len_cmd)
  568.   End If
  569.   
  570.   'extract keyword
  571.   k = InStr(cmd, " ")
  572.   If k <> 0 Then
  573.     'command with arguments
  574.     Kwrd = Left$(cmd, k - 1)  'keyword
  575.     While Mid$(cmd, k, 1) = " "
  576.      k = k + 1
  577.     Wend
  578.     ArgS = Mid$(cmd, k)       'arguments
  579.   Else
  580.     'command without arguments
  581.     Kwrd = cmd
  582.     ArgS = ""
  583.   End If
  584.   
  585.   'command Ok
  586.   sintax_ctrl = 0
  587.   
  588.   Select Case UCase$(Kwrd)
  589.     
  590.   Case "USER"  'USER <username>
  591.     sintax_ctrl = args_ctrl(ArgS, "username", argument())
  592.     
  593.   Case "PASS" 'PASS <password>
  594.     sintax_ctrl = args_ctrl(ArgS, "password", argument())
  595.   
  596.   Case "ACCT"
  597.     sintax_ctrl = 4 'command not implemented
  598.     
  599.   Case "CWD", "XCWD" 'CWD <pathname>
  600.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  601.     
  602.   Case "CDUP", "XCUP"  'CDUP
  603.     '------------------
  604.   
  605.   Case "SMNT"
  606.     sintax_ctrl = 4 'command not implemented
  607.   
  608.   Case "QUIT" 'QUIT
  609.     '-----------------
  610.   
  611.   Case "PORT" 'PORT <host-port>
  612.     sintax_ctrl = args_ctrl(ArgS, "host-port", argument())
  613.   
  614.   Case "PASV"
  615.     sintax_ctrl = 4 'command not implemented
  616.   
  617.   Case "TYPE" 'TYPE <type-code>
  618.     sintax_ctrl = args_ctrl(ArgS, "type-code", argument())
  619.   
  620.   Case "STRU" 'STRU <structure-code>
  621.     sintax_ctrl = args_ctrl(ArgS, "structure-code", argument())
  622.     
  623.   Case "MODE" 'MODE <mode-code>
  624.     sintax_ctrl = args_ctrl(ArgS, "mode-code", argument())
  625.     
  626.   Case "RETR" 'RETR <pathname>
  627.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  628.     
  629.   Case "STOR" 'STOR <pathname>
  630.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  631.     
  632.   Case "RNFR"  'RNFR <pathname>
  633.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  634.     
  635.   Case "RNTO"  'RNTO <pathname>
  636.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  637.     
  638.   Case "ABOR"
  639.     sintax_ctrl = 4 'command not implemented
  640.     
  641.   Case "DELE"  'DELE <pathname>
  642.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  643.     
  644.   Case "RMD", "XRMD" 'RMD <pathname>
  645.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  646.   
  647.   Case "MKD", "XMKD" 'MKD <pathname>
  648.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  649.   
  650.   Case "PWD", "XPWD" 'PWD
  651.     '----------------
  652.   
  653.   Case "LIST" 'LIST <pathname>
  654.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  655.     
  656.   Case "NLST" 'NLST <pathname>
  657.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  658.     
  659.     
  660.   Case "SYST"  'SYST
  661.     '------------------
  662.   
  663.   Case "STAT"  'STAT <pathname>
  664.     sintax_ctrl = args_ctrl(ArgS, "pathname", argument())
  665.   
  666.   Case "HELP"  'HELP <string>
  667.     sintax_ctrl = args_ctrl(ArgS, "string", argument())
  668.     
  669.   Case "NOOP": 'NOOP
  670.     '-----------------
  671.   
  672.   Case "REIN" 'REIN
  673.     sintax_ctrl = 4 'command not implemented
  674.   Case "STOU"
  675.     sintax_ctrl = 4 'command not implemented
  676.   
  677.   Case "APPE"
  678.     sintax_ctrl = 4 'command not implemented
  679.   
  680.   Case "ALLO"
  681.     sintax_ctrl = 1 'command not implemented, superfluous at this side
  682.   
  683.   Case "REST"
  684.     sintax_ctrl = 4 'command not implemented
  685.   
  686.   Case "SITE"
  687.     sintax_ctrl = 4 'command not implemented
  688.   
  689.   Case Else
  690.     sintax_ctrl = 2 'sintax error, command unrecognized
  691.   End Select
  692.   
  693. End Function
  694. Public Sub ServerLog(ByVal str As String)
  695.     
  696.   frmFTP.LogWnd.AddItem str
  697.   frmFTP.LogWnd.Selected(frmFTP.LogWnd.ListCount - 1) = True
  698. End Sub
  699. 'EXEC A FTP COMMAND:
  700. '<id_user> is a number in the range 1 to MAX_N_USERS
  701. 'identifing the user who sends the command;
  702. '<cmd> is the command.
  703. Public Function ChkPath(ByVal ID_User As Integer, ByVal Arg As String) As String
  704.     If Left$(Arg, 1) = "" Then
  705.       ChkPath = Left$(users(ID_User).cur_dir, 2) & Arg                  'absolute path
  706.       'ChkPath = DEFAULT_DRIVE & Arg                   'absolute path
  707.     Else
  708.       If Right$(Arg, 1) = ":" And Len(Arg) = 2 Then 'Change Drive letter
  709.         ChkPath = Arg
  710.       ElseIf Right$(users(ID_User).cur_dir, 1) = "" Then 'relative path
  711.         ChkPath = users(ID_User).cur_dir & Arg        'radix
  712.       Else
  713.         ChkPath = users(ID_User).cur_dir & "" & Arg
  714.       End If
  715.     End If
  716. End Function
  717. Public Sub SendBuffer(ID_User As Integer, ByRef Buffer As String)
  718. Dim ii As Long
  719.   Debug.Print Buffer
  720.   'sends data in buffer on data connection;
  721.   'data are sending in blocks of 1024 bytes
  722.   ii = 1
  723.   Do While Mid$(Buffer, ii, 1024) <> ""
  724.     retf = send_data(Mid$(Buffer, ii, 1024), ID_User)
  725.     If retf < 0 Then
  726.       retf = WSAGetLastError()
  727.       If retf = WSAEWOULDBLOCK Then
  728.         'try again
  729.       Else
  730.         'error on send
  731.         Exit Do
  732.       End If
  733.     Else
  734.       ii = ii + 1024
  735.     End If
  736.     DoEvents
  737.   Loop
  738.   Buffer = ""
  739. End Sub
  740. Public Sub LIST_NLST(ByVal ID_User As Integer, ByVal Typ As String, ByVal Arg As String)
  741.   Dim File_Name As String, name_ As String, exte_ As String
  742.   Dim DummyS As String
  743.   Dim SepN As Integer
  744.   Dim Full_Name As String 'pathname & file name
  745.   Dim PathName As String, Buffer As String
  746.   If users(ID_User).State = Busy Then  '3
  747.     If InStr(Arg, "-a -L") Then Arg = Left(Arg, (InStr(Arg, "-a -L") - 1))
  748.     If Arg = "" Then
  749.       'if LIST/NLST command has no argument the working directory is the current directory
  750.       PathName = users(ID_User).cur_dir
  751.     Else
  752.       PathName = ChkPath(ID_User, Arg)
  753.     End If
  754.     If InStr(PathName, "*") Or InStr(PathName, "?") Then
  755.       'the GettAttr command blows up with a * or ?
  756.       'possibly because file doesn't exist?
  757.       
  758.       'the pathname indicates a file
  759.       Full_Name = PathName
  760.       File_Name = Dir$(Full_Name)
  761.     ElseIf (GetAttr(PathName) And 16) <> 0 Then
  762.       '--- the pathname indicates a directory
  763.       'if radix then elides final backslash
  764.       If Right$(PathName, 1) = "" Then
  765.         PathName = Left$(PathName, Len(PathName) - 1)
  766.       End If
  767.       File_Name = Dir$(PathName & "*.*", 16)
  768.       'rebuilds the full file name
  769.       '(pathname & file name)
  770.       Full_Name = PathName & "" & File_Name
  771.     Else
  772.       'the pathname indicates a file
  773.       Full_Name = PathName
  774.       File_Name = Dir$(Full_Name)
  775.     End If
  776.     If Err.Number = 0 Then
  777.       'opens data connection
  778.       retf = open_data_connect(ID_User)
  779.       Do
  780.         If Not File_Name = "pagefile.sys" Then
  781.         
  782.         If File_Name = "." Or File_Name = ".." Then
  783.           'parent directories
  784.           DummyS = Format$(File_Name, "@@@@@@@@@@@@!") & " <DIR>"
  785.         ElseIf InStr(Full_Name, "*") Or InStr(Full_Name, "?") Then
  786.           'file
  787.           SepN = InStr(File_Name, ".")
  788.           If SepN <> 0 Then
  789.             'name
  790.             name_ = Left$(File_Name, SepN - 1)
  791.             'extension
  792.             exte_ = Mid$(File_Name, SepN + 1)
  793.           Else
  794.             name_ = File_Name
  795.             exte_ = "   "
  796.           End If
  797.           DummyS = "-rwxr--r--   1 user    group  "
  798.           If Typ = "LIST" Then
  799.             DummyS = DummyS & Format$(FileLen(Full_Name), " @@@@@@@@@") _
  800.              & " " & Format$(FileDateTime(Full_Name), " mmm dd hh:nn ") & File_Name
  801.           ElseIf Typ = "NLST" Then
  802.             'DummyS = Format$(FileLen(Full_Name), " @@@@@@@@@") & " " & File_Name
  803.             DummyS = " " & File_Name & " "
  804.           End If
  805.         ElseIf GetAttr(Full_Name) = 16 Then
  806.           'subdirectory
  807.           SepN = InStr(File_Name, ".")
  808.           If SepN <> 0 Then
  809.             'name
  810.             name_ = Left$(File_Name, SepN - 1)
  811.             'extension
  812.             exte_ = Mid$(File_Name, SepN + 1)
  813.           Else
  814.             name_ = File_Name
  815.             exte_ = "   "
  816.           End If
  817.           DummyS = "drwxr-xr-x   1 user    group  "
  818.           If Typ = "LIST" Then
  819.             DummyS = DummyS & Format$(FileLen(Full_Name), " @@@@@@@@@") _
  820.              & " " & Format$(FileDateTime(Full_Name), " mmm dd hh:nn ") & File_Name
  821.           ElseIf Typ = "NLST" Then
  822.             DummyS = Format$(FileLen(Full_Name), " @@@@@@@@@") & " "
  823.           End If
  824.         Else
  825.           'file
  826.           SepN = InStr(File_Name, ".")
  827.           If SepN <> 0 Then
  828.             'name
  829.             name_ = Left$(File_Name, SepN - 1)
  830.             'extension
  831.             exte_ = Mid$(File_Name, SepN + 1)
  832.           Else
  833.             name_ = File_Name
  834.             exte_ = "   "
  835.           End If
  836.           DummyS = "-rwxr--r--   1 user    group  "
  837.           If Typ = "LIST" Then
  838.             DummyS = DummyS & Format$(FileLen(Full_Name), " @@@@@@@@@") _
  839.              & " " & Format$(FileDateTime(Full_Name), " mmm dd hh:nn ") & File_Name
  840.           ElseIf Typ = "NLST" Then
  841.             DummyS = File_Name
  842.             'DummyS = Format$(FileLen(Full_Name), " @@@@@@@@@") & " " & File_Name
  843.           End If
  844.         End If
  845.         Buffer = Buffer & DummyS & vbCrLf
  846.         File_Name = Dir$
  847.         If Left(File_Name, 1) = "p" Then
  848.           File_Name = Dir$
  849.         End If
  850.       Debug.Print "File Name = " & File_Name
  851.               If File_Name = "" Then Exit Do
  852.               Full_Name = PathName & "" & File_Name
  853.       Else
  854.         File_Name = Dir$
  855.       End If
  856.       Loop
  857.       SendBuffer ID_User, Buffer
  858.       'close data connection
  859.       retf = send_reply("226 " & Typ & " command completed.", ID_User)
  860.       retf = close_data_connect(ID_User)
  861.     ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  862.       retf = send_reply("450 " & Typ & " command not executed: " & Error$, ID_User)
  863.       retf = close_data_connect(ID_User)
  864.     Else
  865.    '   frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  866.       retf = close_data_connect(ID_User)
  867.       retf = logoff(ID_User)
  868.       'End
  869.     End If
  870.   ElseIf users(ID_User).State = Service_Commands Then '2
  871.     retf = send_reply("425 Can't open data connection.", ID_User)
  872.   Else
  873.     retf = send_reply("530 User not logged in.", ID_User)
  874.   End If
  875. End Sub