Subversion Repositories Kolibri OS

Rev

Rev 2581 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1.  
  2.  
  3. struct  thread_data
  4.                         rb 1024
  5.         stack           rb 0
  6.  
  7.         home_dir        rb 1024
  8.         work_dir        rb 1024
  9.         fpath           rb 1024*3
  10.  
  11.         type            db ?    ; ASCII/EBDIC/IMAGE/..
  12.         mode            db ?    ; active/passive
  13.         socketnum       dd ?    ; Commands socket
  14.         state           dd ?    ; disconnected/logging in/logged in/..
  15.         passivesocknum  dd ?    ; when in passive mode, this is the listening socket
  16.         datasocketnum   dd ?    ; socket used for data transfers
  17.  
  18.         datasock        sockaddr_in
  19.  
  20.         buffer          rb BUFFERSIZE
  21. ends
  22.  
  23.  
  24.  
  25.  
  26. align 4
  27. parse_cmd:                              ; esi must point to command
  28.  
  29.         cmp     byte [esi], 0x20        ; skip all leading characters
  30.         ja      .ok
  31.         inc     esi
  32.         dec     ecx
  33.         cmp     ecx, 3
  34.         ja      parse_cmd
  35.         ret
  36.   .ok:
  37.  
  38.         cmp     byte [esi+3], 0x20
  39.         jae     @f
  40.         mov     byte [esi+3], 0
  41.        @@:
  42.  
  43.         mov     eax, [esi]
  44.         and     eax, not 0x20202020     ; convert to upper case
  45.         mov     edi, commands           ; list of commands to scan
  46.   .scanloop:
  47.         cmp     eax, [edi]
  48.         jne     .try_next
  49.  
  50.         jmp     dword [edi+4]
  51.  
  52.   .try_next:
  53.         add     edi, 8
  54.         cmp     byte [edi], 0
  55.         jne     .scanloop
  56.  
  57.   .error:
  58.         mcall   send, [edx + thread_data.socketnum], str500, str500.length, 0
  59.  
  60.         ret
  61.  
  62.  
  63. align 4
  64. commands:               ; all commands must be in uppercase
  65.  
  66.         db 'ABOR'
  67.         dd cmdABOR
  68.         db 'CDUP'
  69.         dd cmdCDUP
  70.         db 'CWD', 0
  71.         dd cmdCWD
  72.         db 'DELE'
  73.         dd cmdDELE
  74.         db 'LIST'
  75.         dd cmdLIST
  76.         db 'NLST'
  77.         dd cmdNLST
  78.         db 'NOOP'
  79.         dd cmdNOOP
  80.         db 'PASS'
  81.         dd cmdPASS
  82.         db 'PASV'
  83.         dd cmdPASV
  84.         db 'PORT'
  85.         dd cmdPORT
  86.         db 'PWD', 0
  87.         dd cmdPWD
  88.         db 'QUIT'
  89.         dd cmdQUIT
  90.         db 'RETR'
  91.         dd cmdRETR
  92.         db 'STOR'
  93.         dd cmdSTOR
  94.         db 'SYST'
  95.         dd cmdSYST
  96.         db 'TYPE'
  97.         dd cmdTYPE
  98.         db 'USER'
  99.         dd cmdUSER
  100.         db 0            ; end marker
  101.  
  102.  
  103. align 4
  104. cmdABOR:
  105.  
  106.         ; TODO: abort the current filetransfer
  107.  
  108.         ret
  109.  
  110. align 4
  111. cmdCDUP:
  112.  
  113.         cmp     byte [edx + thread_data.work_dir+1], 0                          ; are we in "/" ?
  114.         je      .done
  115.  
  116.         mov     ecx, 1024
  117.         xor     al, al
  118.         lea     edi, [edx + thread_data.work_dir]
  119.         repne   scasb
  120.         std
  121.         dec     edi
  122.         dec     edi
  123.         dec     edi
  124.         mov     al,'/'
  125.         repne   scasb
  126.         cld
  127.         mov     byte[edi+1], 0
  128.  
  129.   .done:
  130. ; Print the new working dir on the console
  131.         lea     eax, [edx + thread_data.work_dir]
  132.         push    eax
  133.         call    [con_write_asciiz]
  134.         push    str_newline
  135.         call    [con_write_asciiz]
  136.  
  137.         mcall   send, [edx + thread_data.socketnum], str250, str250.length, 0   ; command successful
  138.         ret
  139.  
  140.  
  141. align 4
  142. cmdCWD:                 ; Change Working Directory
  143.  
  144.         sub     ecx, 4
  145.         jb      .err
  146.         add     esi, 4
  147.  
  148.   .scan:
  149.         lea     edi, [edx + thread_data.work_dir + 1]
  150.         push    ecx
  151.         mov     ecx, 1024
  152.   .find_zero:
  153.         cmp     byte [edi], 0
  154.         je      .found_zero
  155.         inc     edi
  156.         loop    .find_zero
  157.   .found_zero:
  158.         pop     ecx
  159.   .scan2:
  160.  
  161.         cmp     byte [esi], '/'
  162.         jne     @f
  163.         inc     esi
  164.         dec     ecx
  165.         jz      .done
  166.        @@:
  167.  
  168.   .loop:
  169.         lodsb
  170.         cmp     al, 0x20
  171.         jb      .done
  172.         cmp     al, '.'
  173.         je      .up
  174.   .continue:
  175.         stosb
  176.         loop    .loop
  177.   .done:
  178.         cmp     byte [edi-1], '/'
  179.         je      @f
  180.         mov     byte [edi], '/'
  181.         inc     edi
  182.        @@:
  183.         mov     byte [edi], 0
  184.  
  185. ; Print the new working dir on the console
  186.         lea     eax, [edx + thread_data.work_dir]
  187.         push    eax
  188.         call    [con_write_asciiz]
  189.         push    str_newline
  190.         call    [con_write_asciiz]
  191.  
  192.         mcall   send, [edx + thread_data.socketnum], str250, str250.length, 0
  193.  
  194.         ret
  195.  
  196.   .up:
  197.         lodsb
  198.         cmp     al, '.'
  199.         jne     .continue
  200.  
  201. ;;;;        TODO: find second last '\' in work_dir and make next char zero
  202. ;;;;        point edi to that 0
  203.  
  204.         jmp     .scan2
  205.  
  206.   .err:
  207.         ; TODO: print correct error message (550?)
  208.  
  209.         ret
  210.  
  211. align 4
  212. cmdDELE:
  213.  
  214.         ret
  215.  
  216.  
  217. align 4
  218. cmdLIST:
  219.  
  220. ; If we are in active mode, it's time to open a data socket..
  221.         cmp     [edx + thread_data.mode], MODE_ACTIVE
  222.         jne     @f
  223.         mov     ecx, [edx + thread_data.datasocketnum]
  224.         lea     edx, [edx + thread_data.datasock]
  225.         mov     esi, sizeof.thread_data.datasock
  226.         mcall   connect
  227.         mov     edx, [esp+4]                                    ; thread_data pointer
  228.         cmp     eax, -1
  229.         je      socketerror
  230.   @@:
  231.  
  232. ; Create fpath from home_dir and work_dir
  233.         call    create_path
  234.  
  235.         lea     eax, [edx + thread_data.fpath]
  236.         push    eax
  237.         call    [con_write_asciiz]
  238.         push    str_newline
  239.         call    [con_write_asciiz]
  240.  
  241. ; Start the search
  242.         push    FA_ANY
  243.         push    str_mask
  244.         lea     eax, [edx + thread_data.fpath]
  245.         push    eax
  246.         call    [file.find.first]
  247.  
  248.         test    eax, eax
  249.         jz      .nosuchdir
  250.  
  251.         lea     edi, [edx + thread_data.buffer]
  252.   .parse_file:
  253.  
  254.         test    eax, eax        ; did we find a file?
  255.         jz      .done
  256.         mov     ebx, eax        ; yes, save the descripter in ebx
  257.  
  258. ; first, convert the attributes
  259.         test    [ebx + FileInfoA.Attributes], FA_FOLDER
  260.         jnz     .folder
  261.  
  262.         test    [ebx + FileInfoA.Attributes], FA_READONLY
  263.         jnz     .readonly
  264.  
  265.         mov     eax, '-rw-'
  266.         stosd
  267.         jmp     .attr
  268.  
  269.   .folder:
  270.         mov     eax, 'drwx'
  271.         stosd
  272.         jmp     .attr
  273.  
  274.   .readonly:
  275.         mov     eax, '-r--'
  276.         stosd
  277.  
  278.   .attr:
  279.         mov     eax, 'rw-r'
  280.         stosd
  281.         mov     ax, 'w-'
  282.         stosw
  283.         mov     al, ' '
  284.         stosb
  285.  
  286. ; now..
  287.         mov     ax, '1 '
  288.         stosw
  289.  
  290. ; now write owner, everything is owned by FTP, woohoo!
  291.         mov     eax, 'FTP '
  292.         stosd
  293.         stosd
  294.  
  295. ; now the filesize in ascii
  296.         mov     eax, [ebx + FileInfoA.FileSizeLow]
  297.         call    dword_to_ascii
  298.  
  299.         mov     al, ' '
  300.         stosb
  301.  
  302. ; then date (month/day/year)
  303.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.month]
  304.         mov     eax, [months + 4*eax]
  305.         stosd
  306.  
  307.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.day]
  308.         call    dword_to_ascii
  309.  
  310.         mov     al, ' '
  311.         stosb
  312.  
  313.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.year]
  314.         call    dword_to_ascii
  315.  
  316.         mov     al, ' '
  317.         stosb
  318.  
  319. ; and last but not least, filename
  320.         lea     esi, [ebx + FileInfoA.FileName]
  321.         mov     ecx, 264
  322.   .nameloop:
  323.         lodsb
  324.         test    al, al
  325.         jz      .namedone
  326.         stosb
  327.         loop    .nameloop
  328.  
  329. ; insert a cr lf
  330.   .namedone:
  331.         mov     ax, 0x0a0d
  332.         stosw
  333.  
  334. ; check next file
  335.         push    ebx
  336.         call    [file.find.next]
  337.         jmp     .parse_file
  338.  
  339. ; close file desc
  340.   .done:
  341.         push    ebx
  342.         call    [file.find.close]
  343.  
  344. ; append the string with a 0
  345.         xor     al, al
  346.         stosb
  347.  
  348. ; Warn the client we're about to send the data
  349.         push    edi edx
  350.         mcall   send, [edx + thread_data.socketnum], str150, str150.length, 0    ; here it comes..
  351.         pop     edx esi
  352.  
  353. ; and send it to the client
  354.         mov     ecx, [edx + thread_data.datasocketnum]
  355.         lea     edx, [edx + thread_data.buffer]
  356.         sub     esi, edx
  357.         xor     edi, edi
  358.         mcall   send
  359.  
  360. ; close the data socket..
  361.         mov     edx, [esp+4]                                    ; thread_data pointer
  362.         mcall   close, [edx + thread_data.datasocketnum]
  363.         mov     [edx + thread_data.mode], MODE_NOTREADY
  364.  
  365. ; And send "transfer ok" on the base connection
  366.         mcall   send, [edx + thread_data.socketnum], str226, str226.length, 0
  367.  
  368.         ret
  369.  
  370.   .nosuchdir:
  371.         mcall   send, [edx + thread_data.socketnum], str550, str550.length, 0
  372.  
  373.         ret
  374.  
  375.  
  376. align 4
  377. cmdNLST:
  378.  
  379.         ; TODO: same as list but simpler output format
  380.  
  381.         ret
  382.  
  383. align 4
  384. cmdNOOP:
  385.  
  386.         ret
  387.  
  388. align 4
  389. cmdPASS:
  390.  
  391.         ; TODO: verify password
  392.  
  393.         mcall   send, [edx + thread_data.socketnum], str230, str230.length, 0
  394.  
  395.         push    str_pass_ok
  396.         call    [con_write_asciiz]
  397.  
  398.         mov     edx, [esp+4]                                    ; thread_data pointer
  399.         mov     [edx + thread_data.state], STATE_ACTIVE
  400.  
  401.         ret
  402.  
  403. align 4
  404. cmdPASV:
  405.  
  406. ; Open a new TCP socket
  407.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  408.         mov     edx, [esp+4]                                    ; thread_data pointer
  409.         cmp     eax, -1
  410.         je      socketerror
  411.         mov     [edx + thread_data.passivesocknum], eax
  412.  
  413. ; Bind it to a known local port
  414.         mov     [edx + thread_data.datasock.sin_family], AF_INET4
  415.         mov     [edx + thread_data.datasock.sin_port], 2000
  416.         mov     [edx + thread_data.datasock.sin_addr], 0
  417.  
  418.         mov     ecx, eax ;[edx + thread_data.passivesocknum]
  419.         lea     edx, [edx + thread_data.datasock]
  420.         mov     esi, sizeof.thread_data.datasock
  421.         mcall   bind
  422.         mov     edx, [esp+4]                                    ; thread_data pointer
  423.         cmp     eax, -1
  424.         je      bind_err
  425.  
  426. ; And set it to listen!
  427.         mcall   listen, [edx + thread_data.passivesocknum], 10    ;;;;; FIXME
  428.  
  429. ; Tell our thread we are ready to accept incoming calls
  430.         mov     edx, [esp+4]                                    ; thread_data pointer
  431.         mov     [edx + thread_data.mode], MODE_PASSIVE_WAIT
  432.  
  433. ; Now tell the client where to connect to in this format:
  434. ; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
  435. ; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
  436.         lea     edi, [edx + thread_data.buffer]
  437.         mov     eax, '227 '     ; FIXME (now hardcoded to 127.0.0.1:2000)
  438.         stosd
  439.         mov     eax, '(127'
  440.         stosd
  441.         mov     eax, ',0,0'
  442.         stosd
  443.         mov     eax, ',1,7'
  444.         stosd
  445.         mov     eax, ',208'
  446.         stosd
  447.         mov     al, ')'
  448.         stosb
  449.         mov     ax, 0x0a0d
  450.         stosw
  451.         xor     al, al
  452.         stosb
  453.  
  454.         lea     esi, [edi - thread_data.buffer]
  455.         sub     esi, edx
  456.         mov     ecx, [edx + thread_data.socketnum]
  457.         lea     edx, [edx + thread_data.buffer]
  458.         xor     esi, esi
  459.         mcall   send
  460.  
  461.         ret
  462.  
  463.  
  464. align 4
  465. cmdPWD:         ; Print Working Directory
  466.  
  467.         mov     dword [edx + thread_data.buffer], '257 '
  468.         mov     byte [edx + thread_data.buffer+4], '"'
  469.  
  470.         lea     edi, [edx + thread_data.buffer+5]
  471.         lea     esi, [edx + thread_data.work_dir]
  472.         mov     ecx, 1024
  473.   .loop:
  474.         lodsb
  475.         or      al, al
  476.         jz      .ok
  477.         stosb
  478.         dec     ecx
  479.         jnz     .loop
  480.  
  481.   .ok:
  482.         mov     dword [edi], '"' + 0x000a0d00    ; '"',13,10,0
  483.         lea     esi, [edi - thread_data.buffer + 4]
  484.         sub     esi, edx
  485.         mov     ecx, [edx + thread_data.socketnum]
  486.         lea     edx, [edx + thread_data.buffer]
  487.         xor     edi, edi
  488.         mcall   send
  489.  
  490.         mov     edx, [esp+4]
  491. ; Print the new working dir on the console
  492.         lea     eax, [edx + thread_data.work_dir]
  493.         push    eax
  494.         call    [con_write_asciiz]
  495.         push    str_newline
  496.         call    [con_write_asciiz]
  497.  
  498.         ret
  499.  
  500.  
  501. align 4
  502. cmdPORT:
  503.  
  504. ; PORT a1,a2,a3,a4,p1,p2
  505. ; IP address a1.a2.a3.a4, port p1*256+p2
  506.  
  507.         mov     [edx + thread_data.mode], MODE_ACTIVE
  508.  
  509.         lea     esi, [esi+5]
  510. ; Convert the IP
  511.         call    ascii_to_byte
  512.         mov     bl, al
  513.         inc     esi             ; skip past ','
  514.         call    ascii_to_byte
  515.         mov     bh, al
  516.         shl     ebx, 16
  517.         inc     esi
  518.         call    ascii_to_byte
  519.         mov     bl, al
  520.         inc     esi
  521.         call    ascii_to_byte
  522.         mov     bh, al
  523.         inc     esi
  524.         rol     ebx, 16
  525.  
  526. ; And put it in datasock
  527.         mov     [edx + thread_data.datasock.sin_addr], ebx
  528.  
  529. ; Now the same with portnumber
  530.         call    ascii_to_byte
  531.         mov     bh, al
  532.         inc     esi
  533.         call    ascii_to_byte
  534.         mov     bl, al
  535.  
  536. ; Save it in datasock too
  537.         mov     [edx + thread_data.datasock.sin_port], bx
  538.  
  539. ; We will open the socket, but do not connect yet!
  540.         mov     [edx + thread_data.datasock.sin_family], AF_INET4
  541.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  542.         mov     edx, [esp+4]                                    ; thread_data pointer
  543.         cmp     eax, -1
  544.         je      socketerror
  545.         mov     [edx + thread_data.datasocketnum], eax
  546.  
  547. ; Tell the client we are ready
  548.         mov     edx, [esp+4]                                    ; thread_data pointer
  549.         mcall   send, [edx + thread_data.socketnum], str225, str225.length, 0
  550.         ret
  551.  
  552.  
  553. align 4
  554. cmdQUIT:
  555.  
  556.         mcall   close, [edx + thread_data.datasocketnum]
  557.         mcall   send, [edx + thread_data.socketnum], str221, str221.length, 0    ; 221 - bye!
  558.         mcall   close;, [edx + thread_data.socketnum]
  559.  
  560.         add     esp, 4          ; get rid of call return address
  561.         jmp     thread_exit     ; now close this thread
  562.  
  563. align 4
  564. cmdRETR:
  565.  
  566.         sub     ecx, 5
  567.         jb      .cannot_open
  568.  
  569.         cmp     [edx + thread_data.mode], MODE_ACTIVE
  570.         jne     @f
  571.         push    esi
  572.         mov     ecx, [edx + thread_data.datasocketnum]
  573.         lea     edx, [edx + thread_data.datasock]
  574.         mov     esi, sizeof.thread_data.datasock
  575.         mcall   connect
  576.         pop     esi
  577.         mov     edx, [esp+4]                                    ; thread_data pointer
  578.         cmp     eax, -1
  579.         je      socketerror
  580.   @@:
  581.  
  582.         push    esi
  583.         call    create_path
  584.         pop     esi
  585.         dec     edi
  586.         add     esi, 5
  587.         mov     ecx, 1024
  588.   .loop:
  589.         lodsb
  590.         cmp     al, 0x20
  591.         jl      .done
  592.         stosb
  593.         loop    .loop
  594.   .done:
  595.         xor     al, al
  596.         stosb
  597.  
  598.         lea     eax, [edx + thread_data.fpath]
  599.         push    eax
  600.         call    [con_write_asciiz]
  601.         push    str_newline
  602.         call    [con_write_asciiz]
  603.  
  604.         push    O_READ
  605.         lea     eax, [edx + thread_data.fpath]
  606.         push    eax
  607.         call    [file.open]
  608.         test    eax, eax
  609.         jz      .cannot_open
  610.  
  611.         push    eax
  612.         mcall   send, [edx + thread_data.socketnum], str150, str150.length, 0    ; here it comes..
  613.         pop     ebx
  614.  
  615.         mov     edx, [esp+4]                                    ; thread_data pointer
  616.   .read_more:
  617.         push    BUFFERSIZE
  618.         lea     eax, [edx + thread_data.buffer]
  619.         push    eax
  620.         push    ebx
  621.         call    [file.read]
  622.         cmp     eax, -1
  623.         je      .cannot_open    ; fixme: this is not the correct error
  624.  
  625.         push    eax
  626.         push    ebx
  627.         mov     esi, eax
  628.         mov     ecx, [edx + thread_data.datasocketnum]
  629.         lea     edx, [edx + thread_data.buffer]
  630.         xor     esi, esi
  631.         mcall   send
  632.         pop     ebx
  633.         pop     ecx
  634.         mov     edx, [esp+4]                                    ; thread_data pointer
  635.         cmp     eax, -1
  636.         je      socketerror
  637.  
  638.         cmp     ecx, BUFFERSIZE
  639.         je      .read_more
  640.  
  641.         mcall   close, [edx + thread_data.datasocketnum]
  642.         mov     [edx + thread_data.mode], MODE_NOTREADY
  643.  
  644.         mcall   send, [edx + thread_data.socketnum], str226, str226.length, 0    ; transfer ok
  645.  
  646.         ret
  647.  
  648.   .cannot_open:
  649.         pushd   0x0c
  650.         call    [con_set_flags]
  651.         push    str_notfound
  652.         call    [con_write_asciiz]
  653.         pushd   0x07
  654.         call    [con_set_flags]
  655.  
  656.         mcall   send, [edx + thread_data.socketnum], str550, str550.length, 0    ; file not found
  657.  
  658.         ret
  659.  
  660. align 4
  661. cmdSTOR:
  662.  
  663.         ; TODO: check if user has write permission, and write file if so
  664.  
  665.         ret
  666.  
  667. align 4
  668. cmdSYST:
  669.  
  670.         mcall   send, [edx + thread_data.socketnum], str215, str215.length, 0
  671.  
  672.         ret
  673.  
  674. align 4
  675. cmdTYPE:
  676.  
  677.         cmp     ecx, 6
  678.         jb      parse_cmd.error
  679.  
  680.         mov     al, byte[esi+5]
  681.         and     al, not 0x20
  682.  
  683.         cmp     al, 'A'
  684.         je      .ascii
  685.         cmp     al, 'E'
  686.         je      .ebdic
  687.         cmp     al, 'I'
  688.         je      .image
  689.         cmp     al, 'L'
  690.         je      .local
  691.  
  692.         jmp     parse_cmd.error
  693.  
  694.   .ascii:
  695.         mov     [edx + thread_data.type], TYPE_ASCII
  696.         jmp     .subtype
  697.  
  698.   .ebdic:
  699.         mov     [edx + thread_data.type], TYPE_EBDIC
  700.  
  701.   .subtype:
  702.         cmp     ecx, 8
  703.         jb      .non_print
  704.  
  705.         mov     al, byte[esi+7]
  706.         and     al, not 0x20
  707.  
  708.         cmp     al, 'N'
  709.         je      .non_print
  710.         cmp     al, 'T'
  711.         je      .telnet
  712.         cmp     al, 'C'
  713.         je      .asacc
  714.  
  715.         jmp     parse_cmd.error
  716.  
  717.   .non_print:
  718.         or      [edx + thread_data.type], TYPE_NP
  719.         jmp     .ok
  720.  
  721.   .telnet:
  722.         or      [edx + thread_data.type], TYPE_TELNET
  723.         jmp     .ok
  724.  
  725.   .asacc:
  726.         or      [edx + thread_data.type], TYPE_ASA
  727.         jmp     .ok
  728.  
  729.   .image:
  730.         mov     [edx + thread_data.type], TYPE_IMAGE
  731.         jmp     .ok
  732.  
  733.   .local:
  734.         cmp     ecx, 8
  735.         jb      parse_cmd.error
  736.  
  737.         mov     al, byte[esi+7]
  738.         sub     al, '0'
  739.         jb      parse_cmd.error
  740.         cmp     al, 9
  741.         ja      parse_cmd.error
  742.         or      al, TYPE_LOCAL
  743.         mov     [edx + thread_data.type], al
  744.  
  745.   .ok:
  746.         mcall   send, [edx + thread_data.socketnum], str200, str200.length, 0
  747.  
  748.         ret
  749.  
  750.  
  751. align 4
  752. cmdUSER:
  753.  
  754.         ; TODO: check user and set home directory (and permissions)
  755.  
  756.         mov     [edx + thread_data.state], STATE_LOGIN
  757.         mov     word [edx + thread_data.home_dir], "/"          ; "/", 0
  758.         mov     word [edx + thread_data.work_dir], "/"          ; "/", 0
  759.  
  760.         push    str_logged_in
  761.         call    [con_write_asciiz]
  762.  
  763.         mcall   send, [edx + thread_data.socketnum], str331, str331.length, 0           ; Now send me the password!
  764.  
  765.         ret
  766.  
  767.  
  768.  
  769. align 4         ; esi = ptr to str, output in eax
  770. ascii_to_byte:
  771.  
  772.         xor     eax, eax
  773.         push    ebx
  774.  
  775.   .loop:
  776.         movzx   ebx, byte[esi]
  777.         sub     bl, '0'
  778.         jb      .done
  779.         cmp     bl, 9
  780.         ja      .done
  781.         lea     eax, [eax*4 + eax]      ;
  782.         shl     eax, 1                  ; eax = eax * 10
  783.         add     eax, ebx
  784.         inc     esi
  785.  
  786.         jmp     .loop
  787.  
  788.   .done:
  789.         pop     ebx
  790.         ret
  791.  
  792. align 4
  793. dword_to_ascii: ; edi = ptr where to write, eax is number
  794.  
  795.         mov     eax, '1'
  796.         stosb
  797.  
  798.         ret
  799.  
  800. align 4
  801. create_path:            ; combine home_dir and work_dir strings into fpath
  802.  
  803.         lea     edi, [edx + thread_data.fpath]
  804.         lea     esi, [edx + thread_data.home_dir]
  805.         mov     ecx, 1024
  806.   .loop1:
  807.         lodsb
  808.         or      al, al
  809.         jz      .next
  810.         stosb
  811.         loop    .loop1
  812.   .next:
  813.  
  814.         cmp     byte[edi-1], '/'
  815.         jne     @f
  816.         dec     edi
  817.        @@:
  818.  
  819.         lea     esi, [edx + thread_data.work_dir]
  820.         mov     ecx, 1024
  821.   .loop2:
  822.         lodsb
  823.         or      al, al
  824.         jz      .done
  825.         stosb
  826.         loop    .loop2
  827.  
  828.   .done:
  829.         stosb
  830.  
  831.         ret
  832.  
  833.  
  834. align 4
  835. socketerror:
  836.  
  837.         pushd   0x0c
  838.         call    [con_set_flags]
  839.         push    str_sockerr
  840.         call    [con_write_asciiz]
  841.         pushd   0x07
  842.         call    [con_set_flags]
  843.  
  844.         mcall   send, [edx + thread_data.socketnum], str425, str425.length, 0    ; data connection error
  845.  
  846.         ret
  847.  
  848.  
  849.  
  850.  
  851. str150  db '150 Here it comes...', 13, 10
  852. .length = $ - str150
  853. str200  db '200 Command OK.', 13, 10
  854. .length = $ - str200
  855. str215  db '215 UNIX type: L8', 13, 10
  856. .length = $ - str215
  857. str220  db '220 KolibriOS FTP Daemon 1.0', 13, 10
  858. .length = $ - str220
  859. str221  db '221 Bye!', 13, 10
  860. .length = $ - str221
  861. str225  db '225 Data connection open', 13, 10
  862. .length = $ - str225
  863. str226  db '226 Transfer OK, Closing connection', 13, 10
  864. .length = $ - str226
  865. str230  db '230 You are now logged in.', 13, 10
  866. .length = $ - str230
  867. str250  db '250 command successful', 13, 10
  868. .length = $ - str250
  869. str331  db '331 Please specify the password.', 13, 10
  870. .length = $ - str331
  871. str421  db '421 Timeout!', 13, 10
  872. .length = $ - str421
  873. str425  db '425 Cant open data connection.', 13, 10
  874. .length = $ - str425
  875. str500  db '500 Unsupported command', 13, 10
  876. .length = $ - str500
  877. str550  db '550 No such file', 13, 10
  878. .length = $ - str550