Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3701 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
4729 hidnplayr 3
;; Copyright (C) KolibriOS team 2013-2014. All rights reserved.    ;;
3701 hidnplayr 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
 
4918 hidnplayr 17
TIMEOUT                 = 3     ; seconds
18
 
3800 hidnplayr 19
BUFFERSIZE              = 4096
3701 hidnplayr 20
 
21
STATUS_CONNECTING       = 0
22
STATUS_CONNECTED        = 1
23
STATUS_NEEDPASSWORD     = 2
24
STATUS_LOGGED_IN        = 3
25
 
3821 hidnplayr 26
OPERATION_NONE          = 0
27
OPERATION_LIST          = 1
28
OPERATION_RETR          = 2
29
OPERATION_STOR          = 3
3800 hidnplayr 30
 
3701 hidnplayr 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:
4918 hidnplayr 52
; disable all events except network event
53
        mcall   40, EV_STACK
3701 hidnplayr 54
; load libraries
55
        stdcall dll.Load, @IMPORT
56
        test    eax, eax
57
        jnz     exit
58
; initialize console
3789 hidnplayr 59
        invoke  con_start, 1
3813 hidnplayr 60
        invoke  con_init, 80, 25, 80, 250, str_title
61
; Check for parameters, if there are some, resolve the address right away
3701 hidnplayr 62
        cmp     byte [s], 0
63
        jne     resolve
64
 
65
main:
3813 hidnplayr 66
; Clear screen
3789 hidnplayr 67
        invoke  con_cls
3701 hidnplayr 68
; Welcome user
3813 hidnplayr 69
        invoke  con_write_asciiz, str_welcome
70
; write prompt (in green color)
3789 hidnplayr 71
        invoke  con_set_flags, 0x0a
3813 hidnplayr 72
        invoke  con_write_asciiz, str_prompt
3701 hidnplayr 73
; read string
3813 hidnplayr 74
        invoke  con_gets, s, 256
3701 hidnplayr 75
; check for exit
76
        test    eax, eax
77
        jz      done
3813 hidnplayr 78
        cmp     byte [s], 10
3701 hidnplayr 79
        jz      done
3813 hidnplayr 80
; reset color back to grey and print newline
81
        invoke  con_set_flags, 0x07
82
        invoke  con_write_asciiz, str_newline
3701 hidnplayr 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
3813 hidnplayr 92
; Say to the user that we're resolving
93
        invoke  con_write_asciiz, str_resolve
3789 hidnplayr 94
        invoke  con_write_asciiz, s
3701 hidnplayr 95
; resolve name
96
        push    esp     ; reserve stack place
3789 hidnplayr 97
        invoke  getaddrinfo, s, 0, 0, esp
3701 hidnplayr 98
        pop     esi
99
; test for error
100
        test    eax, eax
3813 hidnplayr 101
        jnz     error_resolve
3701 hidnplayr 102
; write results
3800 hidnplayr 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
3701 hidnplayr 112
        mcall   socket, AF_INET4, SOCK_STREAM, 0
113
        cmp     eax, -1
3813 hidnplayr 114
        je      error_socket
3701 hidnplayr 115
        mov     [socketnum], eax
3800 hidnplayr 116
; connect to the server
3813 hidnplayr 117
        invoke  con_write_asciiz, str_connect
3701 hidnplayr 118
        mcall   connect, [socketnum], sockaddr1, 18
4918 hidnplayr 119
        cmp     eax, -1
120
        je      error_connect
3701 hidnplayr 121
        mov     [status], STATUS_CONNECTING
3813 hidnplayr 122
; Tell the user we're waiting for the server now.
123
        invoke  con_write_asciiz, str_waiting
3701 hidnplayr 124
 
3813 hidnplayr 125
; Reset 'offset' variable, it's used by the data receiver
3790 hidnplayr 126
        mov     [offset], 0
127
 
3789 hidnplayr 128
wait_for_servercommand:
3813 hidnplayr 129
; Any commands still in our buffer?
3790 hidnplayr 130
        cmp     [offset], 0
3813 hidnplayr 131
        je      .receive                        ; nope, receive some more
3790 hidnplayr 132
        mov     esi, [offset]
133
        mov     edi, s
134
        mov     ecx, [size]
135
        add     ecx, esi
136
        jmp     .byteloop
3701 hidnplayr 137
 
138
; receive socket data
3790 hidnplayr 139
  .receive:
4918 hidnplayr 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
3701 hidnplayr 154
 
4918 hidnplayr 155
  .got_data:
3790 hidnplayr 156
        mov     [offset], 0
3789 hidnplayr 157
 
3701 hidnplayr 158
; extract commands, copy them to "s" buffer
3789 hidnplayr 159
        lea     ecx, [eax + buffer_ptr]         ; ecx = end pointer
3701 hidnplayr 160
        mov     esi, buffer_ptr                 ; esi = current pointer
161
        mov     edi, s
162
  .byteloop:
3789 hidnplayr 163
        cmp     esi, ecx
164
        jae     wait_for_servercommand
3701 hidnplayr 165
        lodsb
166
        cmp     al, 10                          ; excellent, we might have a command
167
        je      .got_command
3789 hidnplayr 168
        cmp     al, 13                          ; just ignore this byte
3701 hidnplayr 169
        je      .byteloop
170
        stosb
171
        jmp     .byteloop
3789 hidnplayr 172
  .got_command:                                 ; we have a newline check if its a command
3790 hidnplayr 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:
3818 hidnplayr 182
        lea     ecx, [edi - s]                  ; length of command
3701 hidnplayr 183
        xor     al, al
184
        stosb
185
 
3789 hidnplayr 186
        invoke  con_set_flags, 0x03             ; change color
187
        invoke  con_write_asciiz, s             ; print servercommand
3813 hidnplayr 188
        invoke  con_write_asciiz, str_newline
3800 hidnplayr 189
        invoke  con_set_flags, 0x07             ; reset color
3701 hidnplayr 190
 
3789 hidnplayr 191
        jmp     server_parser                   ; parse command
3701 hidnplayr 192
 
3813 hidnplayr 193
 
194
 
3789 hidnplayr 195
wait_for_usercommand:
3701 hidnplayr 196
 
3813 hidnplayr 197
; change color to green for user input
3789 hidnplayr 198
        invoke  con_set_flags, 0x0a
3701 hidnplayr 199
 
3813 hidnplayr 200
; If we are not yet connected, request username/password
3701 hidnplayr 201
        cmp     [status], STATUS_CONNECTED
202
        je      .connected
203
 
204
        cmp     [status], STATUS_NEEDPASSWORD
205
        je      .needpass
206
 
207
; write prompt
3813 hidnplayr 208
        invoke  con_write_asciiz, str_prompt
3701 hidnplayr 209
; read string
3813 hidnplayr 210
        invoke  con_gets, s, 256
3794 hidnplayr 211
 
3813 hidnplayr 212
; print a newline and reset the color back to grey
213
        invoke  con_write_asciiz, str_newline
3789 hidnplayr 214
        invoke  con_set_flags, 0x07
3701 hidnplayr 215
 
3790 hidnplayr 216
        cmp     dword[s], "cwd "
217
        je      cmd_cwd
218
 
3813 hidnplayr 219
        cmp     dword[s], "mkd "
220
        je      cmd_mkd
3793 hidnplayr 221
 
3813 hidnplayr 222
        cmp     dword[s], "rmd "
223
        je      cmd_rmd
224
 
3794 hidnplayr 225
        cmp     dword[s], "pwd" + 10 shl 24
226
        je      cmd_pwd
227
 
3813 hidnplayr 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
 
3800 hidnplayr 240
        cmp     dword[s], "stor"
241
        je      cmd_stor
3793 hidnplayr 242
 
3800 hidnplayr 243
        cmp     dword[s], "dele"
244
        je      cmd_dele
245
 
3813 hidnplayr 246
  @@:
247
        cmp     byte[s+4], 10
248
        jne     @f
3800 hidnplayr 249
 
3813 hidnplayr 250
        cmp     dword[s], "list"
251
        je      cmd_list
3802 hidnplayr 252
 
3813 hidnplayr 253
        cmp     dword[s], "help"
254
        je      cmd_help
3804 hidnplayr 255
 
256
        cmp     dword[s], "cdup"
257
        je      cmd_cdup
258
 
3813 hidnplayr 259
  @@:
260
; Uh oh.. unknown command, tell the user and wait for new input
3789 hidnplayr 261
        invoke  con_write_asciiz, str_unknown
3701 hidnplayr 262
        jmp     wait_for_usercommand
263
 
264
 
265
  .connected:
3813 hidnplayr 266
; request username
3789 hidnplayr 267
        invoke  con_write_asciiz, str_user
3701 hidnplayr 268
        mov     dword[s], "USER"
269
        mov     byte[s+4], " "
270
        jmp     .send
271
 
272
 
273
  .needpass:
3813 hidnplayr 274
; request password
3789 hidnplayr 275
        invoke  con_write_asciiz, str_pass
3701 hidnplayr 276
        mov     dword[s], "PASS"
277
        mov     byte[s+4], " "
3803 hidnplayr 278
        invoke  con_set_flags, 0x00     ; black text on black background for password
3701 hidnplayr 279
 
280
  .send:
281
; read string
282
        mov     esi, s+5
3789 hidnplayr 283
        invoke  con_gets, esi, 256
3701 hidnplayr 284
 
3800 hidnplayr 285
; find end of string
3701 hidnplayr 286
        mov     edi, s+5
287
        mov     ecx, 256
288
        xor     al, al
289
        repne   scasb
3814 hidnplayr 290
        lea     esi, [edi-s]
291
        mov     word[edi-2], 0x0a0d
3800 hidnplayr 292
; and send it to the server
3789 hidnplayr 293
        mcall   send, [socketnum], s, , 0
3701 hidnplayr 294
 
3813 hidnplayr 295
        invoke  con_write_asciiz, str_newline
3800 hidnplayr 296
        invoke  con_set_flags, 0x07     ; reset color
3789 hidnplayr 297
        jmp     wait_for_servercommand
3701 hidnplayr 298
 
299
 
300
 
3800 hidnplayr 301
open_dataconnection:                    ; only passive for now..
3701 hidnplayr 302
        cmp     [status], STATUS_LOGGED_IN
303
        jne     .fail
304
 
3821 hidnplayr 305
        mcall   send, [socketnum], str_PASV, str_PASV.length, 0
3701 hidnplayr 306
        ret
307
 
308
  .fail:
3818 hidnplayr 309
        invoke  con_get_flags
310
        push    eax
311
        invoke  con_set_flags, 0x0c                     ; print errors in red
3813 hidnplayr 312
        invoke  con_write_asciiz, str_err_socket
3818 hidnplayr 313
        invoke  con_set_flags                           ; reset color
3701 hidnplayr 314
        ret
315
 
4918 hidnplayr 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
3701 hidnplayr 320
 
4918 hidnplayr 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
3701 hidnplayr 325
 
3813 hidnplayr 326
error_socket:
3818 hidnplayr 327
        invoke  con_set_flags, 0x0c                     ; print errors in red
3813 hidnplayr 328
        invoke  con_write_asciiz, str_err_socket
329
        jmp     wait_for_keypress
3701 hidnplayr 330
 
3813 hidnplayr 331
error_resolve:
3818 hidnplayr 332
        invoke  con_set_flags, 0x0c                     ; print errors in red
3813 hidnplayr 333
        invoke  con_write_asciiz, str_err_resolve
334
 
335
wait_for_keypress:
3818 hidnplayr 336
        invoke  con_set_flags, 0x07                     ; reset color to grey
3813 hidnplayr 337
        invoke  con_write_asciiz, str_push
3789 hidnplayr 338
        invoke  con_getch2
3818 hidnplayr 339
        mcall   close, [socketnum]
3701 hidnplayr 340
        jmp     main
341
 
342
done:
3789 hidnplayr 343
        invoke  con_exit, 1
344
 
3701 hidnplayr 345
exit:
346
        mcall   close, [socketnum]
347
        mcall   -1
348
 
349
 
350
 
351
; data
3813 hidnplayr 352
str_title       db 'FTP client',0
4918 hidnplayr 353
str_welcome     db 'FTP client for KolibriOS v0.12',10
3813 hidnplayr 354
                db 10
355
                db 'Please enter ftp server address.',10,0
3800 hidnplayr 356
 
3813 hidnplayr 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
4918 hidnplayr 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
3813 hidnplayr 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
3701 hidnplayr 373
 
3813 hidnplayr 374
str_open        db "opening data socket",10,0
3967 hidnplayr 375
str_close       db "closing data socket",10,0
376
str2b           db '.',0
3701 hidnplayr 377
 
3813 hidnplayr 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  - change working directoy on the server",10
383
                db "dele      - delete file from the server",10
384
                db "list            - list files and folders in current server directory",10
385
                db "lcwd      - change local working directory",10
386
                db "mkd  - make directory on the server",10
387
                db "pwd             - print server working directory",10
388
                db "retr      - retreive file from the server",10
389
                db "rmd  - remove directory from the server",10
390
                db "stor      - store file on the server",10
391
                db 10,0
392
 
3821 hidnplayr 393
 
394
; FTP strings
395
 
396
str_PASV        db 'PASV',13,10
397
.length = $ - str_PASV
398
 
3701 hidnplayr 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',\
3789 hidnplayr 432
        con_get_flags,  'con_get_flags', \
433
        con_set_flags,  'con_set_flags'
3701 hidnplayr 434
 
435
 
436
i_end:
437
 
3813 hidnplayr 438
; uninitialised data
439
 
3794 hidnplayr 440
status          db ?
3701 hidnplayr 441
active_passive  db ?
3794 hidnplayr 442
 
3701 hidnplayr 443
socketnum       dd ?
444
datasocket      dd ?
3790 hidnplayr 445
offset          dd ?
446
size            dd ?
3800 hidnplayr 447
operation       dd ?
3701 hidnplayr 448
 
4918 hidnplayr 449
timeout         dd ?
450
 
3800 hidnplayr 451
filestruct:
452
.subfn  dd ?
453
.offset dd ?
454
        dd ?
455
.size   dd ?
456
.ptr    dd ?
457
.name   rb 1024
458
 
3794 hidnplayr 459
buffer_ptr      rb BUFFERSIZE+1
460
buffer_ptr2     rb BUFFERSIZE+1
461
 
3790 hidnplayr 462
s               rb 1024
3701 hidnplayr 463
 
464
mem: