Rev 7465 | Rev 7507 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3701 | hidnplayr | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
7167 | nisargshah | 3 | ;; Copyright (C) KolibriOS team 2013-2018. 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 ;; |
||
6582 | nisargshah | 9 | ;; Modified by nisargshah323@gmail.com (2016) ;; |
3701 | hidnplayr | 10 | ;; ;; |
11 | ;; GNU GENERAL PUBLIC LICENSE ;; |
||
12 | ;; Version 2, June 1991 ;; |
||
13 | ;; ;; |
||
14 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
15 | |||
16 | format binary as "" |
||
17 | |||
4918 | hidnplayr | 18 | TIMEOUT = 3 ; seconds |
19 | |||
3800 | hidnplayr | 20 | BUFFERSIZE = 4096 |
3701 | hidnplayr | 21 | |
22 | STATUS_CONNECTING = 0 |
||
23 | STATUS_CONNECTED = 1 |
||
24 | STATUS_NEEDPASSWORD = 2 |
||
25 | STATUS_LOGGED_IN = 3 |
||
26 | |||
3821 | hidnplayr | 27 | OPERATION_NONE = 0 |
28 | OPERATION_LIST = 1 |
||
29 | OPERATION_RETR = 2 |
||
30 | OPERATION_STOR = 3 |
||
5011 | hidnplayr | 31 | OPERATION_RDIR = 4 |
32 | |||
3701 | hidnplayr | 33 | use32 |
34 | ; standard header |
||
35 | db 'MENUET01' ; signature |
||
36 | dd 1 ; header version |
||
37 | dd start ; entry point |
||
38 | dd i_end ; initialized size |
||
39 | dd mem+0x1000 ; required memory |
||
40 | dd mem+0x1000 ; stack pointer |
||
4922 | ashmew2 | 41 | dd buf_cmd ; parameters |
5011 | hidnplayr | 42 | dd path ; path |
3701 | hidnplayr | 43 | |
44 | include '../../macros.inc' |
||
6582 | nisargshah | 45 | macro ijmp reg, addr, method |
46 | { |
||
47 | mov reg, [addr] |
||
48 | add reg, [method] |
||
49 | jmp dword[reg] |
||
50 | } |
||
51 | macro icall reg, addr, method, [arg] |
||
52 | { |
||
53 | mov reg, [addr] |
||
54 | add reg, [method] |
||
55 | if ~ arg eq |
||
56 | pushd arg |
||
57 | end if |
||
58 | call dword[reg] |
||
59 | } |
||
60 | |||
3701 | hidnplayr | 61 | purge mov,add,sub |
6582 | nisargshah | 62 | |
3701 | hidnplayr | 63 | include '../../proc32.inc' |
64 | include '../../network.inc' |
||
7167 | nisargshah | 65 | include '../../KOSfuncs.inc' |
6582 | nisargshah | 66 | |
67 | include 'console.inc' |
||
68 | include 'gui.inc' |
||
69 | include 'login_gui.inc' |
||
3701 | hidnplayr | 70 | include 'usercommands.inc' |
71 | include 'servercommands.inc' |
||
6394 | nisargshah | 72 | include 'parser.inc' |
3701 | hidnplayr | 73 | |
6582 | nisargshah | 74 | ; TODO: Add Pasta support to FTPC |
75 | |||
76 | ;;================================================================================================;; |
||
77 | start: ;//////////////////////////////////////////////////////////////////////////////////////////;; |
||
78 | ;;------------------------------------------------------------------------------------------------;; |
||
79 | ;? Program entry point - initialize heap, load libraries and settings ;; |
||
80 | ;;------------------------------------------------------------------------------------------------;; |
||
81 | ;> ;; |
||
82 | ;;------------------------------------------------------------------------------------------------;; |
||
83 | ;< none ;; |
||
84 | ;;================================================================================================;; |
||
4922 | ashmew2 | 85 | ; initialize heap for using dynamic blocks |
6835 | hidnplayr | 86 | mcall 68, 11 |
87 | test eax, eax |
||
5011 | hidnplayr | 88 | je exit2 |
89 | |||
4918 | hidnplayr | 90 | ; disable all events except network event |
91 | mcall 40, EV_STACK |
||
3701 | hidnplayr | 92 | ; load libraries |
93 | stdcall dll.Load, @IMPORT |
||
94 | test eax, eax |
||
95 | jnz exit |
||
5011 | hidnplayr | 96 | ; find path to main settings file (ftpc.ini) |
97 | mov edi, path ; Calculate the length of zero-terminated string |
||
98 | xor al, al |
||
99 | mov ecx, 1024 |
||
100 | repne scasb |
||
101 | dec edi |
||
102 | mov esi, str_ini ; append it with '.ini', 0 |
||
103 | movsd |
||
104 | movsb |
||
105 | ; get settings from ini |
||
106 | invoke ini.get_str, path, str_active, str_ip, str_active_ip, 16, 0 |
||
107 | mov esi, str_active_ip |
||
108 | .ip_loop: |
||
109 | lodsb |
||
110 | test al, al |
||
111 | jz .ip_ok |
||
112 | cmp al, ' ' |
||
113 | je .ip_ok |
||
114 | cmp al, '.' |
||
115 | jne .ip_loop |
||
116 | mov byte[esi-1], ',' |
||
117 | jmp .ip_loop |
||
118 | .ip_ok: |
||
119 | mov byte[esi-1], 0 |
||
120 | |||
121 | invoke ini.get_int, path, str_active, str_port_start, 64000 |
||
122 | mov [acti_port_start], ax |
||
123 | |||
124 | invoke ini.get_int, path, str_active, str_port_stop, 65000 |
||
125 | mov [acti_port_stop], ax |
||
126 | |||
127 | invoke ini.get_str, path, str_general, str_dir, buf_buffer1, BUFFERSIZE, 0 |
||
128 | mcall 30, 1, buf_buffer1 ; set working directory |
||
129 | |||
6582 | nisargshah | 130 | ; initialize log file |
131 | invoke ini.get_str, path, str_general, str_logfile, log_file, 512, 0 |
||
132 | mov [filestruct2.subfn], 2 |
||
133 | mov [filestruct2.offset], 0 |
||
134 | mov [filestruct2.size], 0 |
||
135 | mov [filestruct2.ptr], 0 |
||
136 | mov [filestruct2.name], log_file |
||
137 | mcall 70, filestruct2 |
||
3701 | hidnplayr | 138 | |
6582 | nisargshah | 139 | ; Usage: ftpc [-cli] [ftp://username:password@server:port/path] |
3701 | hidnplayr | 140 | |
6582 | nisargshah | 141 | ; mov dword[buf_cmd], '-cli' ;;;; to test CLI ;;;;; |
5011 | hidnplayr | 142 | |
6582 | nisargshah | 143 | cmp byte[buf_cmd], 0 |
144 | jne @f |
||
145 | mov [interface_addr], gui |
||
146 | jmp .args_ok |
||
147 | @@: cmp dword[buf_cmd], '-cli' |
||
148 | jne .error |
||
149 | mov [interface_addr], console |
||
150 | jmp .args_ok |
||
151 | |||
152 | .args_ok: |
||
153 | |||
154 | icall eax, interface_addr, interface.init |
||
155 | ; check for ftp://username:pass@server:port/path urls |
||
156 | cmp dword[buf_cmd], 'ftp:' |
||
157 | je parse_args |
||
158 | cmp dword[buf_cmd+5], 'ftp:' |
||
159 | je parse_args |
||
160 | ijmp eax, interface_addr, interface.server_addr |
||
161 | |||
162 | .error: |
||
163 | call console.init |
||
164 | invoke con_write_asciiz, str_args_err |
||
165 | invoke con_getch2 |
||
166 | call console.exit |
||
167 | jmp exit |
||
168 | |||
169 | ;;================================================================================================;; |
||
170 | arg_handler: ;////////////////////////////////////////////////////////////////////////////////////;; |
||
171 | ;;------------------------------------------------------------------------------------------------;; |
||
172 | ;? Passes initial connection info from console/GUI to FTP core and the other way around ;; |
||
173 | ;;------------------------------------------------------------------------------------------------;; |
||
174 | ;> esp+4 = pointer to the argument passed to the function ;; |
||
175 | ;;------------------------------------------------------------------------------------------------;; |
||
176 | ;< none ;; |
||
177 | ;;================================================================================================;; |
||
178 | |||
179 | .get_username: |
||
180 | ; request username |
||
181 | ijmp eax, interface_addr, interface.get_username |
||
182 | |||
183 | .copy_user: |
||
184 | mov dword[buf_cmd], "USER" |
||
185 | mov byte[buf_cmd+4], " " |
||
186 | ; copy user name to buf_cmd (for command line args) |
||
187 | mov edi, buf_cmd+5 |
||
188 | mov esi, param_user |
||
3701 | hidnplayr | 189 | @@: |
6582 | nisargshah | 190 | movsb |
191 | cmp byte [esi-1], 0 |
||
192 | jne @b |
||
193 | mov word[edi-1], 0x0a0d |
||
194 | |||
195 | lea esi, [edi+1-buf_cmd] |
||
196 | jmp server_connect.send |
||
197 | |||
198 | .get_pass: |
||
199 | mov dword[buf_cmd], "PASS" |
||
200 | mov byte[buf_cmd+4], " " |
||
201 | ; copy password to buf_cmd (for command line args) |
||
202 | mov edi, buf_cmd+5 |
||
203 | mov esi, param_password |
||
204 | @@: |
||
205 | movsb |
||
206 | cmp byte[esi-1], 0 |
||
207 | jne @b |
||
208 | mov word[edi-1], 0x0a0d |
||
209 | |||
210 | lea esi, [edi+1-buf_cmd] |
||
211 | jmp server_connect.send |
||
212 | |||
213 | .get_path: |
||
214 | ; copy path from param_path to buf_cmd |
||
215 | mov dword[buf_cmd], "CWD " |
||
216 | mov edi, buf_cmd+4 |
||
217 | mov esi, param_path |
||
218 | @@: |
||
3701 | hidnplayr | 219 | lodsb |
6582 | nisargshah | 220 | stosb |
3701 | hidnplayr | 221 | cmp al, 0x20 |
6582 | nisargshah | 222 | ja @b |
223 | mov word[edi-1], 0x0a0d |
||
224 | |||
225 | lea esi, [edi+1-buf_cmd] |
||
226 | jmp server_connect.send |
||
227 | |||
228 | .connect: |
||
229 | ; copy server address to buf_cmd |
||
230 | mov esi, param_server_addr |
||
231 | mov edi, buf_cmd |
||
232 | @@: |
||
233 | lodsb |
||
234 | stosb |
||
235 | cmp al, 0x20 |
||
3701 | hidnplayr | 236 | ja @r |
6582 | nisargshah | 237 | mov byte[edi-1], 0 ; delete terminating '\n' |
5011 | hidnplayr | 238 | |
6582 | nisargshah | 239 | cmp [param_port], 0x20 |
240 | jbe server_connect.default_port |
||
241 | mov esi, param_port |
||
242 | jmp server_connect.do_port |
||
243 | |||
244 | |||
245 | ;;================================================================================================;; |
||
246 | server_connect: ;/////////////////////////////////////////////////////////////////////////////////;; |
||
247 | ;;------------------------------------------------------------------------------------------------;; |
||
248 | ;? Establishes a connection to the FTP server (common block for all interfaces) ;; |
||
249 | ;? .do_port - Port is specified by the user and needs to be converted from ASCII ;; |
||
250 | ;;------------------------------------------------------------------------------------------------;; |
||
251 | ;> esi = pointer to port no. ;; |
||
252 | ;;------------------------------------------------------------------------------------------------;; |
||
253 | ;< none ;; |
||
254 | ;;================================================================================================;; |
||
255 | |||
256 | .send: |
||
257 | ; send username/password/path to the server |
||
258 | mcall send, [controlsocket], buf_cmd, , 0 |
||
259 | icall eax, interface_addr, interface.print, str_newline |
||
260 | icall eax, interface_addr, interface.set_flags, 0x07 ; reset color |
||
261 | |||
262 | jmp wait_for_servercommand |
||
263 | |||
264 | ; resolve port if specified |
||
5011 | hidnplayr | 265 | .do_port: |
266 | xor eax, eax |
||
267 | xor ebx, ebx |
||
268 | .portloop: |
||
269 | lodsb |
||
270 | cmp al, 0x20 |
||
271 | jbe .port_done |
||
272 | sub al, '0' |
||
6436 | nisargshah | 273 | jnb @f |
274 | mov eax, str_err_host |
||
275 | jmp error |
||
276 | @@: cmp al, 9 |
||
277 | jna @f |
||
278 | mov eax, str_err_host |
||
279 | jmp error |
||
280 | @@: lea ebx, [ebx*4 + ebx] |
||
5011 | hidnplayr | 281 | shl ebx, 1 |
282 | add ebx, eax |
||
283 | jmp .portloop |
||
284 | |||
285 | .port_done: |
||
286 | xchg bl, bh |
||
287 | mov [sockaddr1.port], bx |
||
6582 | nisargshah | 288 | jmp .done |
5011 | hidnplayr | 289 | |
6582 | nisargshah | 290 | .default_port: |
291 | mov [sockaddr1.port], 21 shl 8 |
||
292 | |||
5011 | hidnplayr | 293 | .done: |
3813 | hidnplayr | 294 | ; Say to the user that we're resolving |
6582 | nisargshah | 295 | icall eax, interface_addr, interface.set_flags, 0x07 ; reset color |
296 | icall eax, interface_addr, interface.print, str_resolve, buf_cmd |
||
3701 | hidnplayr | 297 | ; resolve name |
298 | push esp ; reserve stack place |
||
4922 | ashmew2 | 299 | invoke getaddrinfo, buf_cmd, 0, 0, esp |
3701 | hidnplayr | 300 | pop esi |
301 | ; test for error |
||
302 | test eax, eax |
||
6436 | nisargshah | 303 | jz @f |
304 | mov eax, str_err_resolve |
||
305 | jmp error |
||
306 | @@: |
||
3701 | hidnplayr | 307 | ; write results |
6582 | nisargshah | 308 | icall eax, interface_addr, interface.print, str8 ; ' (',0 |
3800 | hidnplayr | 309 | mov eax, [esi+addrinfo.ai_addr] ; convert IP address to decimal notation |
310 | mov eax, [eax+sockaddr_in.sin_addr] ; |
||
311 | mov [sockaddr1.ip], eax ; |
||
312 | invoke inet_ntoa, eax ; |
||
6582 | nisargshah | 313 | icall ebx, interface_addr, interface.print, eax, str9 ; |
3800 | hidnplayr | 314 | invoke freeaddrinfo, esi ; free allocated memory |
315 | ; open the socket |
||
3701 | hidnplayr | 316 | mcall socket, AF_INET4, SOCK_STREAM, 0 |
317 | cmp eax, -1 |
||
6436 | nisargshah | 318 | jne @f |
319 | mov eax, str_err_socket |
||
320 | jmp error |
||
321 | @@: mov [controlsocket], eax |
||
3800 | hidnplayr | 322 | ; connect to the server |
6582 | nisargshah | 323 | icall eax, interface_addr, interface.print, str_connect |
5011 | hidnplayr | 324 | mcall connect, [controlsocket], sockaddr1, 18 |
4918 | hidnplayr | 325 | cmp eax, -1 |
6436 | nisargshah | 326 | jne @f |
327 | mov eax, str_err_connect |
||
328 | jmp error |
||
329 | @@: mov [status], STATUS_CONNECTING |
||
3813 | hidnplayr | 330 | ; Tell the user we're waiting for the server now. |
6582 | nisargshah | 331 | icall eax, interface_addr, interface.print, str_waiting |
3701 | hidnplayr | 332 | |
3813 | hidnplayr | 333 | ; Reset 'offset' variable, it's used by the data receiver |
3790 | hidnplayr | 334 | mov [offset], 0 |
335 | |||
6582 | nisargshah | 336 | |
337 | ;;================================================================================================;; |
||
338 | wait_for_servercommand: ;/////////////////////////////////////////////////////////////////////////;; |
||
339 | ;;------------------------------------------------------------------------------------------------;; |
||
340 | ;? Checks if any data received from the server is present in buffer. ;; |
||
341 | ;? If not, receives and processes it ;; |
||
342 | ;;------------------------------------------------------------------------------------------------;; |
||
343 | ;> ;; |
||
344 | ;;------------------------------------------------------------------------------------------------;; |
||
345 | ;< none ;; |
||
346 | ;;================================================================================================;; |
||
3813 | hidnplayr | 347 | ; Any commands still in our buffer? |
3790 | hidnplayr | 348 | cmp [offset], 0 |
3813 | hidnplayr | 349 | je .receive ; nope, receive some more |
3790 | hidnplayr | 350 | mov esi, [offset] |
4922 | ashmew2 | 351 | mov edi, buf_cmd |
3790 | hidnplayr | 352 | mov ecx, [size] |
353 | add ecx, esi |
||
354 | jmp .byteloop |
||
3701 | hidnplayr | 355 | |
356 | ; receive socket data |
||
3790 | hidnplayr | 357 | .receive: |
4918 | hidnplayr | 358 | mcall 26, 9 |
359 | add eax, TIMEOUT*100 |
||
360 | mov [timeout], eax |
||
361 | .receive_loop: |
||
362 | mcall 23, 50 ; Wait for event with timeout |
||
363 | mcall 26, 9 |
||
364 | cmp eax, [timeout] |
||
6436 | nisargshah | 365 | jl @f |
366 | mov eax, str_err_timeout |
||
367 | jmp error |
||
368 | @@: mcall recv, [controlsocket], buf_buffer1, BUFFERSIZE, MSG_DONTWAIT |
||
4918 | hidnplayr | 369 | test eax, eax |
370 | jnz .got_data |
||
371 | cmp ebx, EWOULDBLOCK |
||
6436 | nisargshah | 372 | je @f |
373 | mov eax, str_err_recv |
||
374 | jmp error |
||
375 | @@: jmp .receive_loop |
||
3701 | hidnplayr | 376 | |
4918 | hidnplayr | 377 | .got_data: |
3790 | hidnplayr | 378 | mov [offset], 0 |
3789 | hidnplayr | 379 | |
4922 | ashmew2 | 380 | ; extract commands, copy them to "buf_cmd" buffer |
381 | lea ecx, [eax + buf_buffer1] ; ecx = end pointer |
||
382 | mov esi, buf_buffer1 ; esi = current pointer |
||
383 | mov edi, buf_cmd |
||
3701 | hidnplayr | 384 | .byteloop: |
3789 | hidnplayr | 385 | cmp esi, ecx |
386 | jae wait_for_servercommand |
||
3701 | hidnplayr | 387 | lodsb |
388 | cmp al, 10 ; excellent, we might have a command |
||
389 | je .got_command |
||
3789 | hidnplayr | 390 | cmp al, 13 ; just ignore this byte |
3701 | hidnplayr | 391 | je .byteloop |
392 | stosb |
||
393 | jmp .byteloop |
||
3789 | hidnplayr | 394 | .got_command: ; we have a newline check if its a command |
3790 | hidnplayr | 395 | cmp esi, ecx |
396 | je .no_more_data |
||
397 | mov [offset], esi |
||
398 | sub ecx, esi |
||
399 | mov [size], ecx |
||
400 | jmp .go_cmd |
||
401 | .no_more_data: |
||
402 | mov [offset], 0 |
||
403 | .go_cmd: |
||
4922 | ashmew2 | 404 | lea ecx, [edi - buf_cmd] ; length of command |
3701 | hidnplayr | 405 | xor al, al |
406 | stosb |
||
407 | |||
6582 | nisargshah | 408 | icall eax, interface_addr, interface.set_flags, 0x03 ; change color |
409 | icall eax, interface_addr, interface.print, buf_cmd, str_newline |
||
410 | icall eax, interface_addr, interface.set_flags, 0x07 ; reset color |
||
3701 | hidnplayr | 411 | |
3789 | hidnplayr | 412 | jmp server_parser ; parse command |
3701 | hidnplayr | 413 | |
3813 | hidnplayr | 414 | |
415 | |||
6582 | nisargshah | 416 | ;;================================================================================================;; |
417 | wait_for_usercommand: ;///////////////////////////////////////////////////////////////////////////;; |
||
418 | ;;------------------------------------------------------------------------------------------------;; |
||
419 | ;? Reads the FTP command entered by the user and compares it with valid FTP commands. ;; |
||
420 | ;? Jumps to appropriate handling routine in usercommands.inc ;; |
||
421 | ;;------------------------------------------------------------------------------------------------;; |
||
422 | ;> status = socket connection status ;; |
||
423 | ;> buf_cmd = command entered by the user ;; |
||
424 | ;;------------------------------------------------------------------------------------------------;; |
||
425 | ;< none ;; |
||
426 | ;;================================================================================================;; |
||
3701 | hidnplayr | 427 | |
4922 | ashmew2 | 428 | ; Are there any files in the transfer queue? |
429 | |||
5011 | hidnplayr | 430 | cmp [queued], 0 |
4922 | ashmew2 | 431 | ja transfer_queued ; Yes, transfer those first. |
6582 | nisargshah | 432 | |
3813 | hidnplayr | 433 | ; change color to green for user input |
6582 | nisargshah | 434 | icall eax, interface_addr, interface.set_flags, 0x0a |
3701 | hidnplayr | 435 | |
3813 | hidnplayr | 436 | ; If we are not yet connected, request username/password |
6582 | nisargshah | 437 | |
3701 | hidnplayr | 438 | cmp [status], STATUS_CONNECTED |
6582 | nisargshah | 439 | je arg_handler.get_username |
3701 | hidnplayr | 440 | |
441 | cmp [status], STATUS_NEEDPASSWORD |
||
6582 | nisargshah | 442 | je arg_handler.get_pass |
3701 | hidnplayr | 443 | |
6582 | nisargshah | 444 | ijmp eax, interface_addr, interface.get_cmd |
3794 | hidnplayr | 445 | |
6582 | nisargshah | 446 | .parse_cmd: |
4922 | ashmew2 | 447 | cmp dword[buf_cmd], "cwd " |
3790 | hidnplayr | 448 | je cmd_cwd |
449 | |||
4922 | ashmew2 | 450 | cmp dword[buf_cmd], "mkd " |
3813 | hidnplayr | 451 | je cmd_mkd |
3793 | hidnplayr | 452 | |
4922 | ashmew2 | 453 | cmp dword[buf_cmd], "rmd " |
3813 | hidnplayr | 454 | je cmd_rmd |
455 | |||
4922 | ashmew2 | 456 | cmp dword[buf_cmd], "pwd" + 10 shl 24 |
3794 | hidnplayr | 457 | je cmd_pwd |
458 | |||
4922 | ashmew2 | 459 | cmp dword[buf_cmd], "bye" + 10 shl 24 |
3813 | hidnplayr | 460 | je cmd_bye |
461 | |||
4922 | ashmew2 | 462 | cmp dword[buf_cmd], "rdir" |
5011 | hidnplayr | 463 | je cmd_rdir |
464 | |||
4922 | ashmew2 | 465 | cmp byte[buf_cmd+4], " " |
3813 | hidnplayr | 466 | jne @f |
467 | |||
4922 | ashmew2 | 468 | cmp dword[buf_cmd], "lcwd" |
3813 | hidnplayr | 469 | je cmd_lcwd |
470 | |||
4922 | ashmew2 | 471 | cmp dword[buf_cmd], "retr" |
3813 | hidnplayr | 472 | je cmd_retr |
473 | |||
4922 | ashmew2 | 474 | cmp dword[buf_cmd], "stor" |
3800 | hidnplayr | 475 | je cmd_stor |
3793 | hidnplayr | 476 | |
4922 | ashmew2 | 477 | cmp dword[buf_cmd], "dele" |
3800 | hidnplayr | 478 | je cmd_dele |
479 | |||
3813 | hidnplayr | 480 | @@: |
4922 | ashmew2 | 481 | cmp byte[buf_cmd+4], 10 |
3813 | hidnplayr | 482 | jne @f |
3800 | hidnplayr | 483 | |
4922 | ashmew2 | 484 | cmp dword[buf_cmd], "list" |
3813 | hidnplayr | 485 | je cmd_list |
3802 | hidnplayr | 486 | |
4922 | ashmew2 | 487 | cmp dword[buf_cmd], "help" |
3813 | hidnplayr | 488 | je cmd_help |
3804 | hidnplayr | 489 | |
4922 | ashmew2 | 490 | cmp dword[buf_cmd], "cdup" |
3804 | hidnplayr | 491 | je cmd_cdup |
492 | |||
6582 | nisargshah | 493 | cmp dword[buf_cmd], "abor" |
494 | je cmd_abor |
||
495 | |||
3813 | hidnplayr | 496 | @@: |
497 | ; Uh oh.. unknown command, tell the user and wait for new input |
||
6582 | nisargshah | 498 | icall eax, interface_addr, interface.print, str_unknown |
3701 | hidnplayr | 499 | jmp wait_for_usercommand |
500 | |||
501 | |||
5011 | hidnplayr | 502 | ; files for rdir operation are queued |
503 | transfer_queued: |
||
3701 | hidnplayr | 504 | |
5011 | hidnplayr | 505 | mov esi, [ptr_queue] ; always pointing to current part of ptr_fname_start |
506 | mov edi, buf_cmd+5 ; always point to filename for retr command |
||
507 | .build_filename: |
||
508 | lodsb |
||
509 | stosb |
||
510 | cmp al, 10 |
||
511 | je .get_file ; filename ends with character 10 |
||
512 | test al, al |
||
513 | jnz .build_filename |
||
514 | |||
515 | ; Error occured, we reached the end of the buffer before [queued] reached 0 |
||
516 | mov [queued], 0 |
||
517 | mcall 68, 13, [ptr_fname] ; free buffer |
||
518 | test eax, eax |
||
519 | jz error_heap |
||
520 | jmp wait_for_usercommand |
||
521 | |||
522 | .get_file: |
||
523 | mov byte[edi], 0 ; end filename with 0 byte |
||
524 | mov [ptr_queue], esi |
||
525 | dec [queued] |
||
526 | jnz cmd_retr |
||
527 | |||
528 | mcall 68, 13, [ptr_fname] ; free buffer |
||
529 | test eax, eax |
||
530 | jz error_heap |
||
531 | jmp cmd_retr |
||
532 | |||
533 | |||
534 | |||
535 | open_dataconnection: |
||
536 | |||
537 | test [mode], 1 |
||
538 | jnz .active |
||
539 | |||
540 | mcall send, [controlsocket], str_PASV, str_PASV.length, 0 |
||
3701 | hidnplayr | 541 | ret |
542 | |||
5011 | hidnplayr | 543 | .active: |
544 | mcall socket, AF_INET4, SOCK_STREAM, 0 |
||
545 | cmp eax, -1 |
||
6436 | nisargshah | 546 | jne @f |
547 | mov eax, str_err_socket |
||
548 | jmp error |
||
549 | @@: mov [datasocket], eax |
||
5011 | hidnplayr | 550 | |
551 | mov ax, [acti_port_start] |
||
552 | xchg al, ah |
||
553 | mov [sockaddr2.port], ax |
||
554 | |||
555 | mcall bind, [datasocket], sockaddr2, 18 |
||
556 | cmp eax, -1 |
||
6436 | nisargshah | 557 | jne @f |
558 | mov eax, str_err_bind |
||
559 | jmp error |
||
560 | @@: |
||
5011 | hidnplayr | 561 | |
562 | mcall listen, [datasocket], 1 |
||
563 | cmp eax, -1 |
||
6436 | nisargshah | 564 | jne @f |
565 | mov eax, str_err_listen |
||
566 | jmp error |
||
567 | @@: |
||
5011 | hidnplayr | 568 | |
569 | mov dword[buf_buffer1], 'PORT' |
||
570 | mov byte[buf_buffer1+4], ' ' |
||
571 | mov edi, buf_buffer1+5 |
||
572 | mov esi, str_active_ip |
||
573 | .loop: |
||
574 | lodsb |
||
575 | test al, al |
||
576 | jz .ip_ok |
||
577 | stosb |
||
578 | jmp .loop |
||
579 | .ip_ok: |
||
580 | mov al, ',' |
||
581 | stosb |
||
582 | movzx eax, byte[sockaddr2.port+0] |
||
583 | call dword_ascii |
||
584 | mov al, ',' |
||
585 | stosb |
||
586 | movzx eax, byte[sockaddr2.port+1] |
||
587 | call dword_ascii |
||
588 | mov ax, 0x0a0d |
||
589 | stosw |
||
590 | lea esi, [edi - buf_buffer1] |
||
591 | mcall send, [controlsocket], buf_buffer1, , 0 |
||
592 | |||
593 | mcall accept, [datasocket], sockaddr2, 18 ; time to accept the awaiting connection.. |
||
594 | cmp eax, -1 |
||
6436 | nisargshah | 595 | jne @f |
596 | mov eax, str_err_accept |
||
597 | jmp error |
||
598 | @@: push eax |
||
5011 | hidnplayr | 599 | mcall close, [datasocket] |
600 | pop [datasocket] |
||
601 | |||
602 | mcall recv, [controlsocket], buf_buffer1, BUFFERSIZE, 0 |
||
603 | |||
3701 | hidnplayr | 604 | ret |
605 | |||
5011 | hidnplayr | 606 | ; eax = input |
607 | ; edi = ptr where to write |
||
608 | dword_ascii: |
||
609 | |||
610 | push edx ebx ecx |
||
611 | mov ebx, 10 |
||
612 | xor ecx, ecx |
||
613 | |||
614 | @@: |
||
615 | xor edx, edx |
||
616 | div ebx |
||
617 | add edx, '0' |
||
618 | push dx |
||
619 | inc ecx |
||
620 | test eax, eax |
||
621 | jnz @r |
||
622 | |||
623 | @@: |
||
624 | pop ax |
||
625 | stosb |
||
626 | dec ecx |
||
627 | jnz @r |
||
628 | |||
629 | pop ecx ebx edx |
||
630 | ret |
||
631 | |||
6582 | nisargshah | 632 | |
633 | ;;================================================================================================;; |
||
634 | write_to_file: ;//////////////////////////////////////////////////////////////////////////////////;; |
||
635 | ;;------------------------------------------------------------------------------------------------;; |
||
636 | ;? Writes input buffer to log file ;; |
||
637 | ;;------------------------------------------------------------------------------------------------;; |
||
638 | ;> eax = pointer to buffer ;; |
||
639 | ;> ecx = size of buffer ;; |
||
640 | ;;------------------------------------------------------------------------------------------------;; |
||
641 | ;< eax = status of SF 70.3 ;; |
||
642 | ;;================================================================================================;; |
||
7201 | nisargshah | 643 | cmp [logfile_offset], -1 ; if offset == -1 => logging disabled |
644 | jne @f |
||
645 | mov eax, 0 |
||
646 | ret |
||
647 | @@: |
||
6582 | nisargshah | 648 | mov [filestruct2.subfn], 3 |
649 | m2m [filestruct2.offset], [logfile_offset] |
||
650 | mov [filestruct2.size], ecx |
||
651 | mov [filestruct2.ptr], eax |
||
652 | mov [filestruct2.name], log_file |
||
653 | mcall 70, filestruct2 |
||
654 | test eax, eax |
||
655 | jz @f |
||
656 | mov [logfile_offset], -1 ; disable logging |
||
657 | call error_fs |
||
658 | icall ebx, interface_addr, interface.print, str_no_logging |
||
659 | ret |
||
660 | @@: |
||
661 | mov eax, [logfile_offset] |
||
662 | add eax, ecx |
||
663 | mov [logfile_offset], eax |
||
664 | ret |
||
665 | |||
666 | ;;================================================================================================;; |
||
667 | error: ;//////////////////////////////////////////////////////////////////////////////////////////;; |
||
668 | ;;------------------------------------------------------------------------------------------------;; |
||
669 | ;? Generic error routine. Prints the error string passed to it. ;; |
||
670 | ;;------------------------------------------------------------------------------------------------;; |
||
671 | ;> eax = pointer to the error string ;; |
||
672 | ;;------------------------------------------------------------------------------------------------;; |
||
673 | ;< none ;; |
||
674 | ;;================================================================================================;; |
||
6436 | nisargshah | 675 | push eax |
6582 | nisargshah | 676 | icall ebx, interface_addr, interface.set_flags, 0x0c ; print errors in red |
6436 | nisargshah | 677 | pop eax |
6582 | nisargshah | 678 | icall ebx, interface_addr, interface.print, eax |
5011 | hidnplayr | 679 | jmp wait_for_keypress |
680 | |||
6582 | nisargshah | 681 | |
682 | ; Error handling block for filesystem errors |
||
683 | error_fs: |
||
684 | |||
685 | cmp eax, 12 |
||
686 | jne @f |
||
687 | mov ebx, str_fs_err_12 |
||
688 | @@: |
||
689 | cmp eax, 11 |
||
690 | jne @f |
||
691 | mov ebx, str_fs_err_11 |
||
692 | @@: |
||
693 | cmp eax, 10 |
||
694 | jne @f |
||
695 | mov ebx, str_fs_err_10 |
||
696 | @@: |
||
697 | cmp eax, 9 |
||
698 | jne @f |
||
699 | mov ebx, str_fs_err_9 |
||
700 | @@: |
||
701 | cmp eax, 8 |
||
702 | jne @f |
||
703 | mov ebx, str_fs_err_8 |
||
704 | @@: |
||
705 | cmp eax, 7 |
||
706 | jne @f |
||
707 | mov ebx, str_fs_err_7 |
||
708 | @@: |
||
709 | cmp eax, 6 |
||
710 | jne @f |
||
711 | mov ebx, str_fs_err_6 |
||
712 | @@: |
||
713 | cmp eax, 5 |
||
714 | jne @f |
||
715 | mov ebx, str_fs_err_5 |
||
716 | @@: |
||
717 | cmp eax, 3 |
||
718 | jne @f |
||
719 | mov ebx, str_fs_err_3 |
||
720 | @@: |
||
721 | cmp eax, 2 |
||
722 | jne @f |
||
723 | mov ebx, str_fs_err_2 |
||
724 | @@: |
||
725 | mov edi, fs_error_code |
||
726 | call dword_ascii ; convert error code in eax to ascii |
||
727 | icall eax, interface_addr, interface.set_flags, 0x0c ; print errors in red |
||
728 | icall eax, interface_addr, interface.print, str_err_fs, fs_error_code, ebx |
||
729 | mov word[fs_error_code], ' ' ; clear error code for next time |
||
730 | icall eax, interface_addr, interface.set_flags, 0x0a |
||
731 | |||
732 | ret |
||
733 | |||
4922 | ashmew2 | 734 | error_heap: |
6582 | nisargshah | 735 | icall eax, interface_addr, interface.set_flags, 0x0c ; print errors in red |
736 | icall eax, interface_addr, interface.print, str_err_heap |
||
5011 | hidnplayr | 737 | |
3813 | hidnplayr | 738 | wait_for_keypress: |
5011 | hidnplayr | 739 | mcall close, [controlsocket] |
6582 | nisargshah | 740 | icall eax, interface_addr, interface.set_flags, 0x07 ; reset color to grey |
741 | icall eax, interface_addr, interface.print, str_push |
||
742 | ijmp eax, interface_addr, interface.error |
||
3701 | hidnplayr | 743 | |
744 | exit: |
||
5011 | hidnplayr | 745 | mcall close, [controlsocket] |
746 | exit2: |
||
3701 | hidnplayr | 747 | mcall -1 |
748 | |||
749 | |||
750 | |||
751 | ; data |
||
7464 | leency | 752 | str_title db 'FTP client for KolibriOS',0 |
7489 | leency | 753 | str_welcome db 'FTP client for KolibriOS v0.15',10 |
6582 | nisargshah | 754 | db 10,0 |
755 | str_srv_addr db 'Please enter ftp server address.',10,0 |
||
3800 | hidnplayr | 756 | |
3813 | hidnplayr | 757 | str_prompt db '> ',0 |
758 | str_resolve db 'Resolving ',0 |
||
759 | str_newline db 10,0 |
||
760 | str_err_resolve db 10,'Name resolution failed.',10,0 |
||
6436 | nisargshah | 761 | str_err_socket db 10,'[75,0 socket]: Error creating a socket',10,0 |
762 | str_err_bind db 10,'[75,2 bind]: Error binding to socket',10,0 |
||
763 | str_err_listen db 10,'[75,3 listen]: Cannot accept incoming connections',10,0 |
||
764 | str_err_accept db 10,'[75,5 accept]: Error accepting a connection',10,0 |
||
765 | str_err_recv db 10,'[75,7 recv]: Error receiving data from server',10,0 |
||
5011 | hidnplayr | 766 | str_err_heap db 10,'Cannot allocate memory from heap.',10,0 |
4918 | hidnplayr | 767 | str_err_timeout db 10,'Timeout - no response from server.',10,0 |
6436 | nisargshah | 768 | str_err_connect db 10,'[75,4 connect]: Cannot connect to the server.',10,0 |
5011 | hidnplayr | 769 | str_err_host db 10,'Invalid hostname.',10,0 |
6436 | nisargshah | 770 | str_err_params db 10,'Invalid parameters',10,0 |
6582 | nisargshah | 771 | str_err_fs db 10,'File system error: code ',0 |
772 | fs_error_code db ' ',0 ; file system error code |
||
773 | str_fs_err_2 db ' [Function is not supported for the given file system]',10,0 |
||
774 | str_fs_err_3 db ' [Unknown file system]',10,0 |
||
775 | str_fs_err_5 db ' [File/Folder not found]',10,0 |
||
776 | str_fs_err_6 db ' [End of file, EOF]',10,0 |
||
777 | str_fs_err_7 db ' [Pointer lies outside of application memory]',10,0 |
||
778 | str_fs_err_8 db ' [Disk is full]',10,0 |
||
779 | str_fs_err_9 db ' [File system error]',10,0 |
||
780 | str_fs_err_10 db ' [Access denied]',10,0 |
||
781 | str_fs_err_11 db ' [Device error]',10,0 |
||
782 | str_fs_err_12 db ' [File system requires more memory]',10,0 |
||
3813 | hidnplayr | 783 | str8 db ' (',0 |
784 | str9 db ')',10,0 |
||
785 | str_push db 'Push any key to continue.',0 |
||
786 | str_connect db 'Connecting...',10,0 |
||
787 | str_waiting db 'Waiting for welcome message.',10,0 |
||
788 | str_user db "username: ",0 |
||
789 | str_pass db "password: ",0 |
||
6582 | nisargshah | 790 | str_port db "port (default 21): ",0 |
791 | str_path db "path (optional): ",0 |
||
3813 | hidnplayr | 792 | str_unknown db "Unknown command or insufficient parameters - type help for more information.",10,0 |
793 | str_lcwd db "Local working directory is now: ",0 |
||
6582 | nisargshah | 794 | str_bytes_done db ' ',0 |
795 | str_downloaded db 'Downloaded ',0 |
||
796 | str_bytes db ' bytes',13,0 |
||
797 | str_args_err db 'Invalid arguments. USAGE: ftpc [-cli] [ftp://username:password@server:port/path]',10,0 |
||
3701 | hidnplayr | 798 | |
3813 | hidnplayr | 799 | str_open db "opening data socket",10,0 |
4922 | ashmew2 | 800 | str_close db 10,"closing data socket",10,0 |
801 | str_dot db '.',0 |
||
3701 | hidnplayr | 802 | |
3813 | hidnplayr | 803 | str_help db "available commands:",10 |
804 | db 10 |
||
805 | db "bye - close the connection",10 |
||
806 | db "cdup - change to parent of current directory on the server",10 |
||
807 | db "cwd |
||
808 | db "dele |
||
809 | db "list - list files and folders in current server directory",10 |
||
810 | db "lcwd |
||
811 | db "mkd |
||
812 | db "pwd - print server working directory",10 |
||
813 | db "retr |
||
814 | db "rmd |
||
815 | db "stor |
||
6582 | nisargshah | 816 | db "rdir - retreive all files from current server dir",10 |
3813 | hidnplayr | 817 | db 10,0 |
818 | |||
5011 | hidnplayr | 819 | str_ini db '.ini', 0 |
820 | str_active db 'active', 0 |
||
821 | str_port_start db 'port_start', 0 |
||
822 | str_port_stop db 'port_stop', 0 |
||
823 | str_ip db 'ip', 0 |
||
824 | str_dir db 'dir', 0 |
||
825 | str_general db 'general', 0 |
||
6582 | nisargshah | 826 | str_logfile db 'logfile',0 |
827 | str_no_logging db 'Error writing to log file. Logging disabled',0 |
||
3821 | hidnplayr | 828 | |
5011 | hidnplayr | 829 | queued dd 0 |
830 | mode db 0 ; passive = 0, active = 1 |
||
831 | |||
6582 | nisargshah | 832 | |
3821 | hidnplayr | 833 | ; FTP strings |
834 | |||
835 | str_PASV db 'PASV',13,10 |
||
836 | .length = $ - str_PASV |
||
837 | |||
3701 | hidnplayr | 838 | sockaddr1: |
839 | dw AF_INET4 |
||
5011 | hidnplayr | 840 | .port dw ? |
841 | .ip dd ? |
||
3701 | hidnplayr | 842 | rb 10 |
843 | |||
844 | sockaddr2: |
||
845 | dw AF_INET4 |
||
5011 | hidnplayr | 846 | .port dw ? |
847 | .ip dd ? |
||
3701 | hidnplayr | 848 | rb 10 |
849 | |||
6582 | nisargshah | 850 | struc interface |
851 | { |
||
852 | .init dd 0 |
||
853 | .server_addr dd 4 |
||
854 | .get_username dd 8 |
||
855 | .get_cmd dd 12 |
||
856 | .print dd 16 |
||
857 | .set_flags dd 20 |
||
858 | .list dd 24 |
||
859 | .progress dd 28 |
||
860 | .error dd 32 |
||
861 | } |
||
862 | interface interface |
||
863 | |||
3701 | hidnplayr | 864 | ; import |
865 | align 4 |
||
866 | @IMPORT: |
||
867 | |||
6582 | nisargshah | 868 | library network, 'network.obj', libini, 'libini.obj' |
3701 | hidnplayr | 869 | |
6582 | nisargshah | 870 | import network, \ |
871 | getaddrinfo, 'getaddrinfo', \ |
||
3701 | hidnplayr | 872 | freeaddrinfo, 'freeaddrinfo', \ |
873 | inet_ntoa, 'inet_ntoa' |
||
874 | |||
6582 | nisargshah | 875 | import libini, \ |
876 | ini.get_str, 'ini_get_str', \ |
||
5011 | hidnplayr | 877 | ini.get_int, 'ini_get_int' |
3701 | hidnplayr | 878 | |
5011 | hidnplayr | 879 | |
3701 | hidnplayr | 880 | i_end: |
881 | |||
3813 | hidnplayr | 882 | ; uninitialised data |
883 | |||
6582 | nisargshah | 884 | interface_addr rd 1 |
885 | |||
3794 | hidnplayr | 886 | status db ? |
887 | |||
6582 | nisargshah | 888 | file_size dd ? |
889 | |||
5011 | hidnplayr | 890 | controlsocket dd ? |
3701 | hidnplayr | 891 | datasocket dd ? |
3790 | hidnplayr | 892 | offset dd ? |
893 | size dd ? |
||
3800 | hidnplayr | 894 | operation dd ? |
4918 | hidnplayr | 895 | timeout dd ? |
896 | |||
5011 | hidnplayr | 897 | ptr_fname dd ? |
898 | size_fname dd ? |
||
899 | ptr_queue dd ? |
||
900 | |||
901 | acti_port_start dw ? |
||
902 | acti_port_stop dw ? |
||
903 | acti_port dw ? |
||
904 | |||
905 | str_active_ip rb 16 |
||
906 | |||
3800 | hidnplayr | 907 | filestruct: |
5011 | hidnplayr | 908 | .subfn dd ? |
909 | .offset dd ? |
||
910 | dd ? |
||
911 | .size dd ? |
||
912 | .ptr dd ? |
||
913 | .name rb 1024 |
||
3800 | hidnplayr | 914 | |
6582 | nisargshah | 915 | filestruct2: |
916 | .subfn dd ? |
||
917 | .offset dd ? |
||
918 | dd 0 |
||
919 | .size dd ? |
||
920 | .ptr dd ? |
||
921 | db 0 |
||
922 | .name dd ? |
||
923 | |||
924 | folder_buf rb 40 |
||
925 | |||
926 | |||
4922 | ashmew2 | 927 | buf_buffer1 rb BUFFERSIZE+1 |
928 | buf_buffer2 rb BUFFERSIZE+1 |
||
5011 | hidnplayr | 929 | buf_cmd rb 1024 ; buffer for holding command string |
6582 | nisargshah | 930 | log_file rb 512 ; holds log file path |
931 | logfile_offset rd 1 |
||
3794 | hidnplayr | 932 | |
5011 | hidnplayr | 933 | path rb 1024 |
934 | |||
6582 | nisargshah | 935 | initial_login rb 1 |
6394 | nisargshah | 936 | param_user rb 1024 |
937 | param_password rb 1024 |
||
938 | param_server_addr rb 1024 |
||
939 | param_path rb 1024 |
||
6582 | nisargshah | 940 | param_port rb 6 |
6394 | nisargshah | 941 | |
6582 | nisargshah | 942 | sc system_colors |
943 | rb 1024 |
||
944 | |||
3701 | hidnplayr | 945 | mem:>>>>>>> |