Subversion Repositories Kolibri OS

Rev

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