Subversion Repositories Kolibri OS

Rev

Rev 4729 | Rev 4922 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2013-2014. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  ftpc.asm - FTP client for KolibriOS                            ;;
  7. ;;                                                                 ;;
  8. ;;  Written by hidnplayr@kolibrios.org                             ;;
  9. ;;                                                                 ;;
  10. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  11. ;;             Version 2, June 1991                                ;;
  12. ;;                                                                 ;;
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14.  
  15. format binary as ""
  16.  
  17. TIMEOUT                 = 3     ; seconds
  18.  
  19. BUFFERSIZE              = 4096
  20.  
  21. STATUS_CONNECTING       = 0
  22. STATUS_CONNECTED        = 1
  23. STATUS_NEEDPASSWORD     = 2
  24. STATUS_LOGGED_IN        = 3
  25.  
  26. OPERATION_NONE          = 0
  27. OPERATION_LIST          = 1
  28. OPERATION_RETR          = 2
  29. OPERATION_STOR          = 3
  30.  
  31. use32
  32. ; standard header
  33.         db      'MENUET01'      ; signature
  34.         dd      1               ; header version
  35.         dd      start           ; entry point
  36.         dd      i_end           ; initialized size
  37.         dd      mem+0x1000      ; required memory
  38.         dd      mem+0x1000      ; stack pointer
  39.         dd      s               ; parameters
  40.         dd      0               ; path
  41.  
  42. include '../../macros.inc'
  43. purge mov,add,sub
  44. include '../../proc32.inc'
  45. include '../../dll.inc'
  46. include '../../network.inc'
  47.  
  48. include 'usercommands.inc'
  49. include 'servercommands.inc'
  50.  
  51. start:
  52. ; disable all events except network event
  53.         mcall   40, EV_STACK
  54. ; load libraries
  55.         stdcall dll.Load, @IMPORT
  56.         test    eax, eax
  57.         jnz     exit
  58. ; initialize console
  59.         invoke  con_start, 1
  60.         invoke  con_init, 80, 25, 80, 250, str_title
  61. ; Check for parameters, if there are some, resolve the address right away
  62.         cmp     byte [s], 0
  63.         jne     resolve
  64.  
  65. main:
  66. ; Clear screen
  67.         invoke  con_cls
  68. ; Welcome user
  69.         invoke  con_write_asciiz, str_welcome
  70. ; write prompt (in green color)
  71.         invoke  con_set_flags, 0x0a
  72.         invoke  con_write_asciiz, str_prompt
  73. ; read string
  74.         invoke  con_gets, s, 256
  75. ; check for exit
  76.         test    eax, eax
  77.         jz      done
  78.         cmp     byte [s], 10
  79.         jz      done
  80. ; reset color back to grey and print newline
  81.         invoke  con_set_flags, 0x07
  82.         invoke  con_write_asciiz, str_newline
  83.  
  84. resolve:
  85. ; delete terminating '\n'
  86.         mov     esi, s
  87.   @@:
  88.         lodsb
  89.         cmp     al, 0x20
  90.         ja      @r
  91.         mov     byte [esi-1], 0
  92. ; Say to the user that we're resolving
  93.         invoke  con_write_asciiz, str_resolve
  94.         invoke  con_write_asciiz, s
  95. ; resolve name
  96.         push    esp     ; reserve stack place
  97.         invoke  getaddrinfo, s, 0, 0, esp
  98.         pop     esi
  99. ; test for error
  100.         test    eax, eax
  101.         jnz     error_resolve
  102. ; write results
  103.         invoke  con_write_asciiz, str8          ; ' (',0
  104.         mov     eax, [esi+addrinfo.ai_addr]     ; convert IP address to decimal notation
  105.         mov     eax, [eax+sockaddr_in.sin_addr] ;
  106.         mov     [sockaddr1.ip], eax             ;
  107.         invoke  inet_ntoa, eax                  ;
  108.         invoke  con_write_asciiz, eax           ; print ip
  109.         invoke  freeaddrinfo, esi               ; free allocated memory
  110.         invoke  con_write_asciiz, str9          ; ')',10,0
  111. ; open the socket
  112.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  113.         cmp     eax, -1
  114.         je      error_socket
  115.         mov     [socketnum], eax
  116. ; connect to the server
  117.         invoke  con_write_asciiz, str_connect
  118.         mcall   connect, [socketnum], sockaddr1, 18
  119.         cmp     eax, -1
  120.         je      error_connect
  121.         mov     [status], STATUS_CONNECTING
  122. ; Tell the user we're waiting for the server now.
  123.         invoke  con_write_asciiz, str_waiting
  124.  
  125. ; Reset 'offset' variable, it's used by the data receiver
  126.         mov     [offset], 0
  127.  
  128. wait_for_servercommand:
  129. ; Any commands still in our buffer?
  130.         cmp     [offset], 0
  131.         je      .receive                        ; nope, receive some more
  132.         mov     esi, [offset]
  133.         mov     edi, s
  134.         mov     ecx, [size]
  135.         add     ecx, esi
  136.         jmp     .byteloop
  137.  
  138. ; receive socket data
  139.   .receive:
  140.         mcall   26, 9
  141.         add     eax, TIMEOUT*100
  142.         mov     [timeout], eax
  143.   .receive_loop:
  144.         mcall   23, 50          ; Wait for event with timeout
  145.         mcall   26, 9
  146.         cmp     eax, [timeout]
  147.         jge     error_timeout
  148.         mcall   recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT
  149.         test    eax, eax
  150.         jnz     .got_data
  151.         cmp     ebx, EWOULDBLOCK
  152.         jne     error_socket
  153.         jmp     .receive_loop
  154.  
  155.   .got_data:
  156.         mov     [offset], 0
  157.  
  158. ; extract commands, copy them to "s" buffer
  159.         lea     ecx, [eax + buffer_ptr]         ; ecx = end pointer
  160.         mov     esi, buffer_ptr                 ; esi = current pointer
  161.         mov     edi, s
  162.   .byteloop:
  163.         cmp     esi, ecx
  164.         jae     wait_for_servercommand
  165.         lodsb
  166.         cmp     al, 10                          ; excellent, we might have a command
  167.         je      .got_command
  168.         cmp     al, 13                          ; just ignore this byte
  169.         je      .byteloop
  170.         stosb
  171.         jmp     .byteloop
  172.   .got_command:                                 ; we have a newline check if its a command
  173.         cmp     esi, ecx
  174.         je      .no_more_data
  175.         mov     [offset], esi
  176.         sub     ecx, esi
  177.         mov     [size], ecx
  178.         jmp     .go_cmd
  179.   .no_more_data:
  180.         mov     [offset], 0
  181.   .go_cmd:
  182.         lea     ecx, [edi - s]                  ; length of command
  183.         xor     al, al
  184.         stosb
  185.  
  186.         invoke  con_set_flags, 0x03             ; change color
  187.         invoke  con_write_asciiz, s             ; print servercommand
  188.         invoke  con_write_asciiz, str_newline
  189.         invoke  con_set_flags, 0x07             ; reset color
  190.  
  191.         jmp     server_parser                   ; parse command
  192.  
  193.  
  194.  
  195. wait_for_usercommand:
  196.  
  197. ; change color to green for user input
  198.         invoke  con_set_flags, 0x0a
  199.  
  200. ; If we are not yet connected, request username/password
  201.         cmp     [status], STATUS_CONNECTED
  202.         je      .connected
  203.  
  204.         cmp     [status], STATUS_NEEDPASSWORD
  205.         je      .needpass
  206.  
  207. ; write prompt
  208.         invoke  con_write_asciiz, str_prompt
  209. ; read string
  210.         invoke  con_gets, s, 256
  211.  
  212. ; print a newline and reset the color back to grey
  213.         invoke  con_write_asciiz, str_newline
  214.         invoke  con_set_flags, 0x07
  215.  
  216.         cmp     dword[s], "cwd "
  217.         je      cmd_cwd
  218.  
  219.         cmp     dword[s], "mkd "
  220.         je      cmd_mkd
  221.  
  222.         cmp     dword[s], "rmd "
  223.         je      cmd_rmd
  224.  
  225.         cmp     dword[s], "pwd" + 10 shl 24
  226.         je      cmd_pwd
  227.  
  228.         cmp     dword[s], "bye" + 10 shl 24
  229.         je      cmd_bye
  230.  
  231.         cmp     byte[s+4], " "
  232.         jne     @f
  233.  
  234.         cmp     dword[s], "lcwd"
  235.         je      cmd_lcwd
  236.  
  237.         cmp     dword[s], "retr"
  238.         je      cmd_retr
  239.  
  240.         cmp     dword[s], "stor"
  241.         je      cmd_stor
  242.  
  243.         cmp     dword[s], "dele"
  244.         je      cmd_dele
  245.  
  246.   @@:
  247.         cmp     byte[s+4], 10
  248.         jne     @f
  249.  
  250.         cmp     dword[s], "list"
  251.         je      cmd_list
  252.  
  253.         cmp     dword[s], "help"
  254.         je      cmd_help
  255.  
  256.         cmp     dword[s], "cdup"
  257.         je      cmd_cdup
  258.  
  259.   @@:
  260. ; Uh oh.. unknown command, tell the user and wait for new input
  261.         invoke  con_write_asciiz, str_unknown
  262.         jmp     wait_for_usercommand
  263.  
  264.  
  265.   .connected:
  266. ; request username
  267.         invoke  con_write_asciiz, str_user
  268.         mov     dword[s], "USER"
  269.         mov     byte[s+4], " "
  270.         jmp     .send
  271.  
  272.  
  273.   .needpass:
  274. ; request password
  275.         invoke  con_write_asciiz, str_pass
  276.         mov     dword[s], "PASS"
  277.         mov     byte[s+4], " "
  278.         invoke  con_set_flags, 0x00     ; black text on black background for password
  279.  
  280.   .send:
  281. ; read string
  282.         mov     esi, s+5
  283.         invoke  con_gets, esi, 256
  284.  
  285. ; find end of string
  286.         mov     edi, s+5
  287.         mov     ecx, 256
  288.         xor     al, al
  289.         repne   scasb
  290.         lea     esi, [edi-s]
  291.         mov     word[edi-2], 0x0a0d
  292. ; and send it to the server
  293.         mcall   send, [socketnum], s, , 0
  294.  
  295.         invoke  con_write_asciiz, str_newline
  296.         invoke  con_set_flags, 0x07     ; reset color
  297.         jmp     wait_for_servercommand
  298.  
  299.  
  300.  
  301. open_dataconnection:                    ; only passive for now..
  302.         cmp     [status], STATUS_LOGGED_IN
  303.         jne     .fail
  304.  
  305.         mcall   send, [socketnum], str_PASV, str_PASV.length, 0
  306.         ret
  307.  
  308.   .fail:
  309.         invoke  con_get_flags
  310.         push    eax
  311.         invoke  con_set_flags, 0x0c                     ; print errors in red
  312.         invoke  con_write_asciiz, str_err_socket
  313.         invoke  con_set_flags                           ; reset color
  314.         ret
  315.  
  316. error_connect:
  317.         invoke  con_set_flags, 0x0c                     ; print errors in red
  318.         invoke  con_write_asciiz, str_err_connect
  319.         jmp     wait_for_keypress
  320.  
  321. error_timeout:
  322.         invoke  con_set_flags, 0x0c                     ; print errors in red
  323.         invoke  con_write_asciiz, str_err_timeout
  324.         jmp     wait_for_keypress
  325.  
  326. error_socket:
  327.         invoke  con_set_flags, 0x0c                     ; print errors in red
  328.         invoke  con_write_asciiz, str_err_socket
  329.         jmp     wait_for_keypress
  330.  
  331. error_resolve:
  332.         invoke  con_set_flags, 0x0c                     ; print errors in red
  333.         invoke  con_write_asciiz, str_err_resolve
  334.  
  335. wait_for_keypress:
  336.         invoke  con_set_flags, 0x07                     ; reset color to grey
  337.         invoke  con_write_asciiz, str_push
  338.         invoke  con_getch2
  339.         mcall   close, [socketnum]
  340.         jmp     main
  341.  
  342. done:
  343.         invoke  con_exit, 1
  344.  
  345. exit:
  346.         mcall   close, [socketnum]
  347.         mcall   -1
  348.  
  349.  
  350.  
  351. ; data
  352. str_title       db 'FTP client',0
  353. str_welcome     db 'FTP client for KolibriOS v0.12',10
  354.                 db 10
  355.                 db 'Please enter ftp server address.',10,0
  356.  
  357. str_prompt      db '> ',0
  358. str_resolve     db 'Resolving ',0
  359. str_newline     db 10,0
  360. str_err_resolve db 10,'Name resolution failed.',10,0
  361. str_err_socket  db 10,'Socket error.',10,0
  362. str_err_timeout db 10,'Timeout - no response from server.',10,0
  363. str_err_connect db 10,'Cannot connect to the server.',10,0
  364. str8            db ' (',0
  365. str9            db ')',10,0
  366. str_push        db 'Push any key to continue.',0
  367. str_connect     db 'Connecting...',10,0
  368. str_waiting     db 'Waiting for welcome message.',10,0
  369. str_user        db "username: ",0
  370. str_pass        db "password: ",0
  371. str_unknown     db "Unknown command or insufficient parameters - type help for more information.",10,0
  372. str_lcwd        db "Local working directory is now: ",0
  373.  
  374. str_open        db "opening data socket",10,0
  375. str_close       db "closing data socket",10,0
  376. str2b           db '.',0
  377.  
  378. str_help        db "available commands:",10
  379.                 db 10
  380.                 db "bye             - close the connection",10
  381.                 db "cdup            - change to parent of current directory on the server",10
  382.                 db "cwd <directory> - change working directoy on the server",10
  383.                 db "dele <file>     - delete file from the server",10
  384.                 db "list            - list files and folders in current server directory",10
  385.                 db "lcwd <path>     - change local working directory",10
  386.                 db "mkd <directory> - make directory on the server",10
  387.                 db "pwd             - print server working directory",10
  388.                 db "retr <file>     - retreive file from the server",10
  389.                 db "rmd <directory> - remove directory from the server",10
  390.                 db "stor <file>     - store file on the server",10
  391.                 db 10,0
  392.  
  393.  
  394. ; FTP strings
  395.  
  396. str_PASV        db 'PASV',13,10
  397. .length = $ - str_PASV
  398.  
  399. sockaddr1:
  400.         dw AF_INET4
  401. .port   dw 0x1500       ; 21
  402. .ip     dd 0
  403.         rb 10
  404.  
  405. sockaddr2:
  406.         dw AF_INET4
  407. .port   dw 0
  408. .ip     dd 0
  409.         rb 10
  410.  
  411. ; import
  412. align 4
  413. @IMPORT:
  414.  
  415. library network, 'network.obj', console, 'console.obj'
  416.  
  417. import  network,        \
  418.         getaddrinfo,    'getaddrinfo',  \
  419.         freeaddrinfo,   'freeaddrinfo', \
  420.         inet_ntoa,      'inet_ntoa'
  421.  
  422. import  console,        \
  423.         con_start,      'START',        \
  424.         con_init,       'con_init',     \
  425.         con_write_asciiz,'con_write_asciiz',     \
  426.         con_exit,       'con_exit',     \
  427.         con_gets,       'con_gets',\
  428.         con_cls,        'con_cls',\
  429.         con_getch2,     'con_getch2',\
  430.         con_set_cursor_pos, 'con_set_cursor_pos',\
  431.         con_write_string, 'con_write_string',\
  432.         con_get_flags,  'con_get_flags', \
  433.         con_set_flags,  'con_set_flags'
  434.  
  435.  
  436. i_end:
  437.  
  438. ; uninitialised data
  439.  
  440. status          db ?
  441. active_passive  db ?
  442.  
  443. socketnum       dd ?
  444. datasocket      dd ?
  445. offset          dd ?
  446. size            dd ?
  447. operation       dd ?
  448.  
  449. timeout         dd ?
  450.  
  451. filestruct:
  452. .subfn  dd ?
  453. .offset dd ?
  454.         dd ?
  455. .size   dd ?
  456. .ptr    dd ?
  457. .name   rb 1024
  458.  
  459. buffer_ptr      rb BUFFERSIZE+1
  460. buffer_ptr2     rb BUFFERSIZE+1
  461.  
  462. s               rb 1024
  463.  
  464. mem:
  465.