Subversion Repositories Kolibri OS

Rev

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

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