Subversion Repositories Kolibri OS

Rev

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

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