EnglishРусский  

   ..

   ftp.g

Ads

Perfect Automation tool
All-In-One: Script editor, Launcher, Scheduler, Keyboard & Mouse Recorder. Try now!

CreateInstall
Freeware and commercial installers.

Cell Phone Batteries
Batteries Plus offers batteries for laptop, camcorder, cell phone, camera.

Gentee needs your help!
How to advertise with us
 
laptop battery

source\lib\ftp\ftp.g
  1 /******************************************************************************
  2 *
  3 * Copyright (C) 2004-2008, The Gentee Group. All rights reserved. 
  4 * This file is part of the Gentee open source project - http://www.gentee.com. 
  5 * 
  6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT"). 
  7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS 
  8 * ACCEPTANCE OF THE AGREEMENT.
  9 *
 10 * Author: Alexey Krivonogov ( gentee )
 11 *
 12 ******************************************************************************/
 13 
 14 /*-----------------------------------------------------------------------------
 15 * Id: ftp L "FTP"
 16 * 
 17 * Summary: FTP protocol. You must call 
 18            #a(inet_init) function before using this library. For using this
 19            library, it is
 20            required to specify the file ftp.g (from lib\ftp
 21            subfolder) with include command. #srcg[
 22 |include : $"...\gentee\lib\ftp\ftp.g"]   
 23 *
 24 * List: *,ftp_close,ftp_command,ftp_createdir,ftp_deldir,ftp_delfile,
 25           ftp_getcurdir,ftp_getfile,ftp_getsize,ftp_gettime,
 26           ftp_lastresponse,ftp_list,ftp_open,ftp_putfile,ftp_rename,
 27           ftp_setattrib,ftp_setcurdir,
 28         *@Common internet functions,inet_close,inet_error,inet_init,
 29          inet_proxy,inet_proxyenable,inetnotify_func,
 30         *@URL strings,str_iencoding,str_ihead,str_ihttpinfo,str_iurl, 
 31 * 
 32 -----------------------------------------------------------------------------*/
 33 
 34 include : $"..\socket\internet.g"
 35 
 36 type ftp
 37 {
 38    str        path        // Дополнительный путь при открытии
 39 	socket     sock        // Главный сокет
 40 	socket     sockdata    // Сокет передачи данных
 41 	socket     sockserv    // Сокет передачи данных PORT
 42 	sockaddr   local       // Локальный адрес
 43 	uint       notify      // Функция для уведомлений
 44 	inetnotify ni
 45 	uint       anonymous   // 1 если anonymous
 46 	uint       passive     // 1 если passive mode
 47 }
 48 
 49 define
 50 {
 51 	FTP_OPENING = 150   /* 150 Opening data connection*/
 52 	FTP_ENDTRAN = 226   /* 226 Transfer Complete */
 53 	FTP_OK      = 200   
 54    FTP_FILESTAT = 213  // File status.
 55 	FTP_HELLO   = 220
 56 	FTP_GOODBYE = 221
 57 	FTP_PASSIVEOK = 227 
 58 	FTP_LOGINOK = 230   
 59 	FTP_CWDOK   = 250    /* 250 CWD command successful. */
 60 	FTP_MKDIROK = 257
 61 	FTP_PASSWD  = 331
 62 	FTP_FILEOK  = 350    /* RNFR command successful */    
 63 	FTP_LOGINBAD = 530  
 64 	FTP_NOTFOUND = 550   /* 550 No such file or directory */
 65 }
 66 
 67 define <export>
 68 {
 69 /*-----------------------------------------------------------------------------
 70 * Id: ftpflag D
 71 * 
 72 * Summary: FTP flags.
 73 *
 74 -----------------------------------------------------------------------------*/
 75 	FTP_ANONYM   = 0x0001      // Anonymous connection.
 76 	FTP_PASV     = 0x0002      // Establishes a connection in passive mode.
 77    
 78 /*-----------------------------------------------------------------------------
 79 * Id: ftpget D
 80 * 
 81 * Summary: FTP flags.
 82 *
 83 -----------------------------------------------------------------------------*/
 84 	FTP_BINARY = 0x0004  // A binary file is downloaded.
 85 	FTP_TEXT   = 0x0008  // A text file is downloaded. This is a default mode.
 86    
 87 /*-----------------------------------------------------------------------------
 88 * Id: ftpgetbuf D
 89 * 
 90 * Summary: FTP flags.
 91 *
 92 -----------------------------------------------------------------------------*/
 93 	FTP_STR      = 0x0100      // Appends zero to the end of received data. 
 94 
 95 /*-----------------------------------------------------------------------------
 96 * Id: ftpgetfile D
 97 * 
 98 * Summary: FTP flags.
 99 *
100 -----------------------------------------------------------------------------*/
101   	FTP_CONTINUE = 0x0010   // Proceeds with retrieving.
102   	FTP_SETTIME  = 0x0020   // Sets the same file times as on the FTP server.
103     
104 //-----------------------------------------------------------------------------
105 	FTP_FILE     = 0x1000      // для метода get - закачка в файл 
106 
107 	S_IRWXU    = 0x0700
108 	S_IRUSR    = 0x0400
109 	S_IWUSR    = 0x0200
110 	S_IXUSR    = 0x0100
111 	S_IRWXG    = 0x0070
112 	S_IRGRP    = 0x0040
113 	S_IWGRP    = 0x0020
114 	S_IXGRP    = 0x0010
115 	S_IRWXO    = 0x0007
116 	S_IROTH    = 0x0004
117 	S_IWOTH    = 0x0002
118 	S_IXOTH    = 0x0001
119 }
120 
121 /*-----------------------------------------------------------------------------
122 * Id: ftpput D
123 * 
124 * Summary: FTP flags.
125 *
126 -----------------------------------------------------------------------------
127 	FTP_BINARY    // A binary file is uploaded.
128 	FTP_TEXT      // A text file is uploaded.
129    FTP_CONTINUE  // To proceed with file uploading. 
130 
131 //---------------------------------------------------------------------------*//*-----------------------------------------------------------------------------
132 * Id: ftplist D
133 * 
134 * Summary: FTP list.
135 *
136 -----------------------------------------------------------------------------
137 #define "LIST" // Returns a list of files in the format of the LIST command. 
138 #define "NLST" // Returns a list of filenames with no other information. 
139 #define "MLSD" // Returns a list of files in the format of the MLSD command. 
140 
141 //---------------------------------------------------------------------------*/
142 
143 method uint ftp.notify( uint code )
144 {
145    if !this.notify : return 1
146       
147    if !this.notify->func( code, this.ni )
148    {
149       ineterror = $ERRINET_USERBREAK
150 //      ret = 0
151       return 0
152    }
153 	if code == $NFYINET_ERROR : return 0 
154    return 1
155 }
156 
157 method uint ftp.cmdresponse
158 {
159 	uint ret i
160 	buf  data
161 	arrstr  lines 
162 
163 	subfunc uint nodigit( ubyte ch )
164 	{
165 		return ch < '0' || ch > '9'
166 	}
167 	label again
168 	this.sock.recv( data )
169 	data += byte( 0 )
170    this.ni.head = data->str
171 
172 	if *data == 1 : return 0
173 
174 	this.ni.head.split( lines, 0xA, 0 )	
175 	foreach cur, lines
176 	{
177 		if nodigit( cur[0] ) || nodigit( cur[1] ) || nodigit( cur[2] ) ||
178 			( cur[3] != ' ' && cur[3] != '-' )
179 		{
180 			ineterror = $ERRFTP_RESPONSE
181 			return 0						
182 		} 
183 		ret = uint( cur )
184 	}
185 	if (lines[ *lines - 1 ])[ 3 ] != ' '
186 	{
187 		data.use-- 
188  		goto again
189 	}
190 
191 	this.notify( $NFYFTP_RESPONSE )
192 	return ret	
193 }
194 
195 /*-----------------------------------------------------------------------------
196 * Id: ftp_lastresponse F2
197 *
198 * Summary: The last response from the FTP server. The method returns the 
199            last response from the FTP server.
200 *
201 * Params: out - Result string.     
202 *  
203 * Return: #lng/retpar( out ) 
204 *
205 -----------------------------------------------------------------------------*/
206 
207 method str ftp.lastresponse( str out )
208 {
209 	return out = this.ni.head
210 }
211 
212 method uint ftp.sendcmd( str cmd )
213 {
214 	this.ni.head = cmd
215 	if !this.ni.head.islast( 0xA ) : this.ni.head += "\l"
216 
217 	if !this.sock.send( this.ni.head ) : return this.notify( $NFYINET_ERROR )
218 	this.notify( $NFYFTP_SENDCMD )
219 
220 	return 1	
221 }
222 
223 /*-----------------------------------------------------------------------------
224 * Id: ftp_command F2
225 *
226 * Summary: Sends a command. This methos is used to send the specified 
227            command directly to an FTP server. The response from the server 
228            can be received with help of the #a(ftp_lastresponse) method.
229 *
230 * Params: cmd - The command text.     
231 *  
232 * Return: #lng/retf# 
233 *
234 -----------------------------------------------------------------------------*/
235 
236 method uint ftp.command( str cmd )
237 {
238 	if !this.sendcmd( cmd ) : return 0
239 	return this.cmdresponse()	
240 }
241 
242 /*-----------------------------------------------------------------------------
243 * Id: ftp_close F3
244 *
245 * Summary: Terminates the FTP connection. The method terminates the connection
246            on the FTP server.
247 *  
248 * Return: #lng/retf# 
249 *
250 -----------------------------------------------------------------------------*/
251 
252 method uint ftp.close()
253 {
254 	uint cmd ret = 1
255 
256 	if this.sock.socket
257 	{
258 		cmd = this.command( "QUIT" )
259 	  	if cmd && cmd != $FTP_GOODBYE
260 		{
261 			ineterror = $ERRFTP_QUIT
262 	      this.notify( $NFYINET_ERROR )
263 			ret = 0
264 		}
265 	  	this.sock.close( )
266 	}
267 	return ret
268 }
269 
270 /*-----------------------------------------------------------------------------
271 * Id: ftp_open F2
272 *
273 * Summary: Establishes an FTP connection. This method establishes an FTP
274            connection with the server. This method must be called before other
275            methods dealing with the FTP server are called. 
276 *
277 * Params: url - The name or address of the FTP server. 
278           user - A user name. If the string is empty, anonymous connections /
279                  are used. 
280           password - A user password. If the connection is anonymous, your /
281                      e-mail address is required. 
282           flag - Connection flags.$$[ftpflag]
283           notify - #a(inetnotify_func, Function ) is used to receive /
284                    notification messages. This parameter can be zero. 
285 *  
286 * Return: #lng/retf# 
287 *
288 -----------------------------------------------------------------------------*/
289 
290 method uint ftp.open( str url, str user, str password, uint flag, str notify )
291 {
292 	uint len
293 	str  host
294 
295 	this.notify = notify
296    ineterror = 0
297    this.ni.url = url
298 
299 	if flag & $FTP_ANONYM : this.anonymous = 1 
300 	if flag & $FTP_PASV : this.passive = 1 
301 
302    this.notify( $NFYINET_CONNECT )
303 
304 	this.sock.flag |= $SOCKF_FTP
305 
306    if !this.sock.urlconnect( url, host, this.path ) : goto error 
307 	if this.cmdresponse() != $FTP_HELLO : goto error
308 	len = sizeof( sockaddr )
309 
310    if getsockname( this.sock.socket, &this.local, &len )  
311    {
312 		inet_seterror()
313 		goto error
314    }
315 	
316 	if !*user || this.anonymous : user = "anonymous"
317  
318 	if !this.sendcmd( "USER \( user )" ) : return 0
319   
320    switch this.cmdresponse( )
321    {
322 		case $FTP_LOGINOK {}   
323       case $FTP_LOGINBAD
324 		{
325 			ineterror = $ERRFTP_BADUSER
326 			goto error	
327 		}
328 	   case $FTP_PASSWD
329 		{
330 	      if !this.sendcmd( "PASS \( password )" ) : return 0
331       
332 	      switch this.cmdresponse()
333 			{
334 				case $FTP_LOGINOK {}
335 				case $FTP_LOGINBAD
336 				{
337 					ineterror = $ERRFTP_BADPSW
338 					goto error	
339 				}
340 				default 
341  				{
342 					ineterror = $ERRFTP_RESPONSE
343 					goto error
344 				}
345 			}
346 	   }
347     	default
348 		{
349 			ineterror = $ERRFTP_RESPONSE
350 			goto error
351 		}
352    }
353 	return 1
354 
355 	label error
356    this.notify( $NFYINET_ERROR )
357    this.close( )
358    return 0
359 }
360 
361 method uint ftp.listen
362 {
363 	uint cmd sin addr port
364 	sockaddr in  
365 
366 	if this.passive
367    {
368       cmd = this.command( "PASV" )
369       if cmd == $FTP_PASSIVEOK
370 		{
371 			str   ports response 
372 			uint  off till
373 			arrstr   portval 
374 
375 			off = this.lastresponse( response ).findch( '(', 0 ) + 1
376 			till = response.findchfrom( ')', off )
377 			ports.substr( response, off, till - off )
378 			ports.split( portval, ',', 0 )
379 			if *portval != 6 
380 			{
381 				ineterror = $ERRFTP_RESPONSE
382 				goto error
383 			}
384 			this.sockdata.host = "\(portval[0]).\(portval[1]).\(portval[2]).\(portval[3])"
385 			this.sockdata.port = (uint( portval[4] ) << 8) + uint( portval[5] )
386 			if this.sockdata.connect() : return 1
387 		}
388 		this.passive = 0
389 		this.notify( $NFYFTP_NOTPASV )
390 	}
391 
392 	this.sockserv.socket = createsocket( $AF_INET, $SOCK_STREAM, $IPPROTO_TCP ) 
393   
394    if this.sockserv.socket == $INVALID_SOCKET : return inet_seterror()
395 
396 	sin = sizeof( sockaddr )
397 	mcopy( &in, &this.local, sin )
398   	in->sockaddr_in.sin_port = 0
399   
400  	if bind( this.sockserv.socket, &in, sin ) ||
401 		listen( this.sockserv.socket, 1 ) ||
402 		getsockname( this.sockserv.socket, &in, &sin )
403    {
404 		inet_seterror()
405 		goto error
406    }
407 
408   	addr = ntohl( this.local->sockaddr_in.sin_addr )
409   	port = ntohs( in->sockaddr_in.sin_port )
410   
411 	if this.command( "PORT \((addr >> 24) & 0xFF ),\((addr >> 16) & 0xFF ),\((addr >> 8) & 0xFF ),\(addr & 0xFF ),\((port >> 8) & 0xFF ),\(port & 0xFF )") != $FTP_OK
412    {
413 		ineterror = $ERRFTP_PORT
414       goto error
415    }
416 	return 1
417 
418 	label error
419 	this.notify( $NFYINET_ERROR )
420 	return 0
421 }
422 
423 method uint ftp.accept
424 {
425 	if !this.passive && ( this.sockdata.socket = 
426                 accept( this.sockserv.socket, 0, 0 )) == $INVALID_SOCKET 
427 	{
428 		inet_seterror()
429 		this.notify( $NFYINET_ERROR )
430 		return 0
431 	}
432   	return this.sockdata.socket
433 }
434 
435 /*-----------------------------------------------------------------------------
436 * Id: ftp_list F2
437 *
438 * Summary: List of files. The method retrieves a list of files and 
439            directories from the FTP server. 
440 *
441 * Params: list - Result string. 
442           cmd - The command is used to retrieve a list of files.$$[ftplist]
443 *  
444 * Return: #lng/retf# 
445 *
446 -----------------------------------------------------------------------------*/
447 
448 method uint ftp.list( str data, str mode )
449 {
450 	uint i dif
451 
452 	if !this.listen() : return 0
453 
454 //	if this.command( "MLSD" ) != $FTP_OPENING : return 0
455 	if this.command( mode ) != $FTP_OPENING : return 0
456 
457 	if !this.accept() : return 0
458 
459 	data->buf.use = 0
460    do 
461    {
462       i = *data
463       this.sockdata.recv( data->buf )
464       dif = *data - i
465    } while dif
466 
467 	data->buf += byte( 0 )
468 
469 	this.sockdata.close()
470 
471 	// ? надо или нет закрывать
472 	if !this.passive : this.sockserv.close()
473  
474 	if this.cmdresponse() != $FTP_ENDTRAN
475    {
476 		ineterror = $ERRFTP_RESPONSE
477 		this.notify( $NFYINET_ERROR )
478 		return 0
479    }
480 	return 1
481 }
482 
483 /*-----------------------------------------------------------------------------
484 * Id: ftp_createdir F2
485 *
486 * Summary: Creates a new directory. The method creates a new directory on 
487            the FTP server.
488 *
489 * Params: dirname - The name of the directory      
490 *  
491 * Return: #lng/retf# 
492 *
493 -----------------------------------------------------------------------------*/
494 
495 method uint ftp.createdir( str dirname )
496 {
497 	return this.command("MKD \(dirname)") == $FTP_MKDIROK
498 }
499 
500 /*-----------------------------------------------------------------------------
501 * Id: ftp_deldir F2
502 *
503 * Summary: Deletes a directory. This method deletes a directory stored on 
504            the FTP server. 
505 *
506 * Params: dirname - The name of the required directory       
507 *  
508 * Return: #lng/retf# 
509 *
510 -----------------------------------------------------------------------------*/
511 
512 method uint ftp.deldir( str dirname )
513 {
514 	return this.command("RMD \(dirname)") == $FTP_CWDOK
515 }
516 
517 /*-----------------------------------------------------------------------------
518 * Id: ftp_delfile F2
519 *
520 * Summary: Deletes a file. The method deletes a file stored on the FTP server. 
521 *
522 * Params: filename - The name of the required file.      
523 *  
524 * Return: #lng/retf# 
525 *
526 -----------------------------------------------------------------------------*/
527 
528 method uint ftp.delfile( str filename )
529 {
530 	return this.command("DELE \(filename)") == $FTP_CWDOK
531 }
532 
533 /*-----------------------------------------------------------------------------
534 * Id: ftp_setcurdir F2
535 *
536 * Summary: Sets the current directory. This method sets a new current 
537            directory.
538 *
539 * Params: dirname - The name of a new directory.      
540 *  
541 * Return: #lng/retf# 
542 *
543 -----------------------------------------------------------------------------*/
544 
545 method uint ftp.setcurdir( str dirname )
546 {
547 	return this.command("CWD \(dirname)") == $FTP_CWDOK
548 }
549 
550 /*-----------------------------------------------------------------------------
551 * Id: ftp_getcurdir F2
552 *
553 * Summary: Retrieves the current directory. The method retrieves the current
554            directory name from the FTP server.
555 *
556 * Params: dirname - Result string.      
557 *  
558 * Return: #lng/retf# 
559 *
560 -----------------------------------------------------------------------------*/
561 
562 method uint ftp.getcurdir( str dirname )
563 {
564 	str   response 
565 	uint  off till
566 
567 	dirname.clear()
568 	if this.command("PWD") != $FTP_MKDIROK : return 0
569 
570 	off = this.lastresponse( response ).findch( '"', 0 ) + 1
571 	till = response.findchfrom( '"', off )
572 	dirname.substr( response, off, till - off )
573 	if !*dirname : return 0
574 
575 	return 1
576 }
577 
578 /*-----------------------------------------------------------------------------
579 * Id: ftp_rename F2
580 *
581 * Summary: Renames a file. This method renames a file or directory stored 
582            on the FTP server.
583 *
584 * Params: from - The current name of the file or directory. 
585           to - A new name.  
586 *  
587 * Return: #lng/retf# 
588 *
589 -----------------------------------------------------------------------------*/
590 
591 method uint ftp.rename( str from, str to )
592 {
593 	if this.command("RNFR \(from)") != $FTP_FILEOK : return 0
594 	return this.command("RNTO \(to)") == $FTP_CWDOK 
595 }
596 
597 /*-----------------------------------------------------------------------------
598 * Id: ftp_getsize F2
599 *
600 * Summary: Retrieves the file size from the FTP server.
601 *
602 * Params: name - Filename. 
603           psize - A pointer to uint value is used to store the file size. 
604 *  
605 * Return: #lng/retf# 
606 *
607 -----------------------------------------------------------------------------*/
608 
609 method uint ftp.getsize( str name, uint psize )
610 {
611 	str size
612 
613 	psize->uint = 0
614 	if this.command("SIZE \(name)") != $FTP_FILESTAT : return 0
615 
616 	this.lastresponse( size ).del( 0, 4 )
617 	psize->uint = uint( size )
618 	return 1 
619 }
620 
621 /*-----------------------------------------------------------------------------
622 * Id: ftp_gettime F2
623 *
624 * Summary: Retrieves the file time. Retrieves last write times for the file 
625            on the FTP server. 
626 *
627 * Params: name - Filename. 
628           dt - The variable of #a( tdatetime ) type is used to retrieve the /
629                file time. 
630 *  
631 * Return: #lng/retf# 
632 *
633 -----------------------------------------------------------------------------*/
634 
635 method uint ftp.gettime( str name, datetime dt )
636 {
637 	str time year month day
638 
639 	mzero( &dt, sizeof( datetime ))
640 	if this.command("MDTM \(name)") != $FTP_FILESTAT : return 0
641 
642 	this.lastresponse( time ).del( 0, 4 )
643 	time.trimspace()
644 	year.substr( time, 0, 4 )
645 	month.substr( time, 4, 2 )
646 	day.substr( time, 6, 2 )
647 	dt.setdate( uint( day ), uint( month ), uint( year ))
648 	dt.hour = uint( year.substr( time, 8, 2 ))
649 	dt.minute = uint( month.substr( time, 10, 2 ))
650 	dt.second = uint( day.substr( time, 12, 2 ))
651 	
652 	return 1 
653 }
654 
655 /*-----------------------------------------------------------------------------
656 * Id: ftp_setattrib F2
657 *
658 * Summary: Sets the attributes. This method sets the attributes for the file 
659            or the directory.
660 *
661 * Params: name - The name of a file or directory. 
662           mode - The attributes for the file. 
663 *  
664 * Return: #lng/retf# 
665 *
666 -----------------------------------------------------------------------------*/
667 
668 method uint ftp.setattrib( str name, uint mode )
669 {
670 //	str  chmode
671 
672 	mode &= $S_IRWXU | $S_IRWXG | $S_IRWXO
673 	
674 	if this.command("SITE CHMOD \(hex2strl( mode)) \(name)") != $FTP_OK
675 	{ 
676  		return 0
677 	}
678 	return 1 
679 }
680 
681 /*-----------------------------------------------------------------------------
682 * Id: ftp_getfile F2
683 *
684 * Summary: Retrieves a file. The method retrieves files from the FTP server.
685 *
686 * Params: filename - The downloaded file name. 
687           databuf - The received data buffer. Data are not stored on a drive. 
688           flag - Additional flags. $$[ftpget]$$[ftpgetbuf]
689 *  
690 * Return: #lng/retf# 
691 *
692 -----------------------------------------------------------------------------*/
693 
694 method uint ftp.getfile( str filename, buf databuf, uint flag )
695 {
696 	uint       data dif i 
697    buf        fbuf
698    uint       ret range
699    file       fdwn
700 	uint       isfile = flag & $FTP_FILE
701 	finfo      fi 
702 
703 	if this.command( "TYPE \(?( flag & $FTP_BINARY, "I", "A" ))") != $FTP_OK
704 	{ 
705 		return 0	
706 	}
707 	if !this.listen() : return 0
708 
709 	this.ni.param = 0
710  
711 	if isfile && flag & $FTP_CONTINUE
712    {  
713       getfileinfo( databuf->str, fi )
714       if fi.sizelo
715 		{
716 			if this.command( "REST \(fi.sizelo)" ) != $FTP_FILEOK
717 			{
718 				flag &= ~$FTP_CONTINUE
719 			}
720 			else : this.ni.param = fi.sizelo
721 		}	 
722    }
723 	data = ?( isfile, &fbuf, &databuf )
724    data as buf
725 
726    if isfile
727    {
728       data.expand( 0x20000 )
729       if !( fdwn.open( databuf->str, ?( flag & $FTP_CONTINUE,
730                             $OP_ALWAYS, $OP_CREATE )))
731       {
732          this.ni.sparam = databuf->str
733          ineterror = $ERRINET_OPENFILE
734          this.notify( $NFYINET_ERROR )
735          goto end
736       }
737 		if this.ni.param : fdwn.setpos( 0, $FILE_END )
738    }
739    else 
740    {
741 		uint fullsize
742 
743 		data.clear()
744 		this.getsize( filename, &fullsize )
745       if uint( fullsize ) : data.expand( uint( fullsize ) + 0x7FFF )
746    }
747 
748   	if this.command( "RETR \(filename)" ) != $FTP_OPENING : return 0 
749   
750 	if !this.accept() : return 0
751 
752 	do 
753    {
754       i = *data
755       if !this.notify( $NFYINET_GET )
756 		{
757 			this.sockdata.close()
758 //			this.command("ABOR") 
759  			goto end
760 		}
761       this.sockdata.recv( data )
762       
763 		dif = *data - i
764       this.ni.param += dif
765  
766       if isfile && ( *data >= 0x7FFF || !dif )
767       {
768          if !( fdwn.write( data ))
769          {
770             this.ni.sparam = databuf->str
771             ineterror = $ERRINET_WRITEFILE
772             this.notify( $NFYINET_ERROR )
773             goto end
774          }
775          data.use = 0
776       }
777    } while dif
778    
779    if flag & $FTP_STR : data += byte( 0 )
780    this.notify( $NFYINET_END )
781 	this.sockdata.close()
782 
783 	if this.cmdresponse() != $FTP_ENDTRAN
784 	{
785 		ineterror = $ERRFTP_RESPONSE
786 		goto end
787 	}
788 
789    ret = 1   
790    label end      
791    if fdwn.fopen 
792    {
793       if ret && flag & $FTP_SETTIME
794       {
795          filetime ft
796 			datetime dt
797          
798 			if this.gettime( filename, dt )
799 			{
800          	datetimetoftime( dt, ft )
801          	fdwn.settime( ft )
802 			}
803       }
804       fdwn.close( )
805    }
806    if !ret && ineterror : this.notify( $NFYINET_ERROR )
807    
808    return ret
809 }
810 
811 /*-----------------------------------------------------------------------------
812 * Id: ftp_getfile_1 FA
813 *
814 * Summary: The method retrieves files from the FTP server.
815 *
816 * Params: srcname - The downloaded file name. 
817           destname - A new file name on user's machine.  
818           flag - Flags.$$[ftpget]$$[ftpgetfile]
819 *  
820 * Return: #lng/retf# 
821 *
822 -----------------------------------------------------------------------------*/
823 
824 method uint ftp.getfile( str srcname, str destname, uint flag )
825 {
826    flag &= 0xF0FF
827    return this.getfile( srcname, destname->buf, flag | $FTP_FILE )
828 }
829 
830 /*-----------------------------------------------------------------------------
831 ** Id: ftp_putfile F2
832 *
833 * Summary: Stores a file on the FTP server. This method is used to upload 
834            the required file from the remote host to the FTP server. 
835 *
836 * Params: srcname - The name of the required source file. 
837           destname - The name of a file stored on the FTP server. 
838           flag - Flags. If the flag of the binary or text mode is not /
839                  specified, the method makes effort to determine a file /
840                  type. $$[ftpput]    
841 *  
842 * Return: #lng/retf# 
843 *
844 -----------------------------------------------------------------------------*/
845 
846 method uint ftp.putfile( str srcname, str destname, uint flag )
847 {
848 	uint  offset size cur ret i
849    file  fdwn
850 	buf   data
851 	str   tmode
852 
853 	subfunc uint nextread
854 	{
855 		cur = min( size, 0x20000 )
856 		data.use = 0
857 		if fdwn.read( data, cur ) != cur
858 		{
859    		this.ni.sparam = srcname
860       	ineterror = $ERRINET_READFILE
861       	return 0
862 		}
863 		size -= cur
864 		return 1
865 	}
866 
867    if !( fdwn.open( srcname, $OP_READONLY ))
868    {
869    	this.ni.sparam = srcname
870       ineterror = $ERRINET_OPENFILE
871       this.notify( $NFYINET_ERROR )
872       return 0
873    }
874 	size = fdwn.getsize( ) 
875 	if flag & $FTP_CONTINUE
876 	{ 
877 		if !this.getsize( destname, &offset ) || offset >= size
878 		{
879 			flag &= ~$FTP_CONTINUE
880 		}
881 		else
882 		{
883 			this.ni.param = offset
884 			size -= offset
885 			fdwn.setpos(  offset, $FILE_BEGIN )
886 		}
887 	}
888    data.expand( 0x20000 )
889 	if !nextread() : goto end
890 
891 	tmode = "TYPE A"	
892 	if flag & $FTP_BINARY : tmode = "TYPE I" 	
893 	elif !( flag & $FTP_TEXT )
894 	{
895 		fornum i = 0, *data - 1
896 		{
897 			if !data[i] || ( data[i] == 0xD && data[i + 1] != 0xA )
898 			{
899 				tmode = "TYPE I"
900 				break		
901 			}    
902 		}		
903 	}
904 	if this.command( tmode ) != $FTP_OK : goto close	
905 	if !this.listen() : goto close
906 	
907 	if this.command( "\(?( flag & $FTP_CONTINUE, "APPE", 
908                     "STOR")) \( destname )") != $FTP_OPENING : goto close  
909 
910 	if !this.accept() : goto close 
911 
912 	while 1
913 	{
914 		uint off last
915 	   uint sent
916 
917 	  	last = *data
918    
919 	   while last
920    	{   
921       	sent = send( this.sockdata.socket, data.ptr() + off, min( 0x7FFF, last ), 
922                       0  )
923 			if	sent == $SOCKET_ERROR 
924 			{
925 				inet_seterror()
926 				this.sockdata.close()
927 				goto close
928 			}
929 			else
930 			{
931 				this.ni.param += sent
932 				if !this.notify( $NFYINET_PUT )
933 				{
934 					this.sockdata.close()
935  					goto close
936 				}
937 			}
938       	last -= sent
939       	off += sent
940    	}
941 //		this.sockdata.send( data )
942 		if !size : break
943 		nextread()
944 	}
945    this.notify( $NFYINET_END )
946 	this.sockdata.close()
947 	if this.cmdresponse() != $FTP_ENDTRAN
948 	{
949 		ineterror = $ERRFTP_RESPONSE
950 		goto end
951 	}
952    ret = 1   
953    label end      
954    if !ret && ineterror : this.notify( $NFYINET_ERROR )
955 	label close
956    fdwn.close( )
957    
958    return ret
959 }
Edit