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