EnglishРусский  

   ..

   ftp.g

The project is closed! You can look at a new scripting language. It is available on GitHub.
Also, try our open source cross-platform automation software.

Ads

Installer and installation software
Commercial and Freeware installers.

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 	if *data == 1 : return 0
172 
173 	this.ni.head.split( lines, 0xA, 0 )	
174 	foreach cur, lines
175 	{
176 		if nodigit( cur[0] ) || nodigit( cur[1] ) || nodigit( cur[2] ) ||
177 			( cur[3] != ' ' && cur[3] != '-' )
178 		{
179          if cur[0] == ' ' : continue
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, uint 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 	if !*user || this.anonymous : user = "anonymous"
316  
317 	if !this.sendcmd( "USER \( user )" ) : return 0
318   
319    switch this.cmdresponse( )
320    {
321 		case $FTP_LOGINOK {}   
322       case $FTP_LOGINBAD
323 		{
324 			ineterror = $ERRFTP_BADUSER
325 			goto error	
326 		}
327 	   case $FTP_PASSWD
328 		{
329 	      if !this.sendcmd( "PASS \( password )" ) : return 0
330       
331 	      switch this.cmdresponse()
332 			{
333 				case $FTP_LOGINOK {}
334 				case $FTP_LOGINBAD
335 				{
336 					ineterror = $ERRFTP_BADPSW
337 					goto error	
338 				}
339 				default 
340  				{
341 					ineterror = $ERRFTP_RESPONSE
342 					goto error
343 				}
344 			}
345 	   }
346     	default
347 		{
348 			ineterror = $ERRFTP_RESPONSE
349 			goto error
350 		}
351    }
352 	return 1
353 
354 	label error
355    this.notify( $NFYINET_ERROR )
356    this.close( )
357    return 0
358 }
359 
360 method uint ftp.listen
361 {
362 	uint cmd sin addr port
363 	sockaddr in  
364 
365 	if this.passive
366    {
367       cmd = this.command( "PASV" )
368       if cmd == $FTP_PASSIVEOK
369 		{
370 			str   ports response 
371 			uint  off till
372 			arrstr   portval 
373 
374 			off = this.lastresponse( response ).findch( '(' ) + 1
375 			till = response.findchfrom( ')', off )
376 			ports.substr( response, off, till - off )
377 			ports.split( portval, ',', 0 )
378 			if *portval != 6 
379 			{
380 				ineterror = $ERRFTP_RESPONSE
381 				goto error
382 			}
383 			this.sockdata.host = "\(portval[0]).\(portval[1]).\(portval[2]).\(portval[3])"
384 			this.sockdata.port = (uint( portval[4] ) << 8) + uint( portval[5] )
385 			if this.sockdata.connect() : return 1
386 		}
387 		this.passive = 0
388 		this.notify( $NFYFTP_NOTPASV )
389 	}
390 
391 	this.sockserv.socket = createsocket( $AF_INET, $SOCK_STREAM, $IPPROTO_TCP ) 
392   
393    if this.sockserv.socket == $INVALID_SOCKET : return inet_seterror()
394 
395 	sin = sizeof( sockaddr )
396 	mcopy( &in, &this.local, sin )
397   	in->sockaddr_in.sin_port = 0
398   
399  	if bind( this.sockserv.socket, &in, sin ) ||
400 		listen( this.sockserv.socket, 1 ) ||
401 		getsockname( this.sockserv.socket, &in, &sin )
402    {
403 		inet_seterror()
404 		goto error
405    }
406 
407   	addr = ntohl( this.local->sockaddr_in.sin_addr )
408   	port = ntohs( in->sockaddr_in.sin_port )
409   
410 	if this.command( "PORT \((addr >> 24) & 0xFF ),\((addr >> 16) & 0xFF ),\((addr >> 8) & 0xFF ),\(addr & 0xFF ),\((port >> 8) & 0xFF ),\(port & 0xFF )") != $FTP_OK
411    {
412 		ineterror = $ERRFTP_PORT
413       goto error
414    }
415 	return 1
416 
417 	label error
418 	this.notify( $NFYINET_ERROR )
419 	return 0
420 }
421 
422 method uint ftp.accept
423 {
424 	if !this.passive && ( this.sockdata.socket = 
425                 accept( this.sockserv.socket, 0, 0 )) == $INVALID_SOCKET 
426 	{
427 		inet_seterror()
428 		this.notify( $NFYINET_ERROR )
429 		return 0
430 	}
431   	return this.sockdata.socket
432 }
433 
434 /*-----------------------------------------------------------------------------
435 * Id: ftp_list F2
436 *
437 * Summary: List of files. The method retrieves a list of files and 
438            directories from the FTP server. 
439 *
440 * Params: list - Result string. 
441           cmd - The command is used to retrieve a list of files.$$[ftplist]
442 *  
443 * Return: #lng/retf# 
444 *
445 -----------------------------------------------------------------------------*/
446 
447 method uint ftp.list( str data, str mode )
448 {
449 	uint i dif
450 
451 	if !this.listen() : return 0
452 
453 //	if this.command( "MLSD" ) != $FTP_OPENING : return 0
454 	if this.command( mode ) != $FTP_OPENING : return 0
455 
456 	if !this.accept() : return 0
457 
458 	data->buf.use = 0
459    do 
460    {
461       i = *data
462       this.sockdata.recv( data->buf )
463       dif = *data - i
464    } while dif
465 
466 	data->buf += byte( 0 )
467 
468 	this.sockdata.close()
469 
470 	// ? надо или нет закрывать
471 	if !this.passive : this.sockserv.close()
472  
473 	if this.cmdresponse() != $FTP_ENDTRAN
474    {
475 		ineterror = $ERRFTP_RESPONSE
476 		this.notify( $NFYINET_ERROR )
477 		return 0
478    }
479 	return 1
480 }
481 
482 /*-----------------------------------------------------------------------------
483 * Id: ftp_createdir F2
484 *
485 * Summary: Creates a new directory. The method creates a new directory on 
486            the FTP server.
487 *
488 * Params: dirname - The name of the directory      
489 *  
490 * Return: #lng/retf# 
491 *
492 -----------------------------------------------------------------------------*/
493 
494 method uint ftp.createdir( str dirname )
495 {
496 	return this.command("MKD \(dirname)") == $FTP_MKDIROK
497 }
498 
499 /*-----------------------------------------------------------------------------
500 * Id: ftp_deldir F2
501 *
502 * Summary: Deletes a directory. This method deletes a directory stored on 
503            the FTP server. 
504 *
505 * Params: dirname - The name of the required directory       
506 *  
507 * Return: #lng/retf# 
508 *
509 -----------------------------------------------------------------------------*/
510 
511 method uint ftp.deldir( str dirname )
512 {
513 	return this.command("RMD \(dirname)") == $FTP_CWDOK
514 }
515 
516 /*-----------------------------------------------------------------------------
517 * Id: ftp_delfile F2
518 *
519 * Summary: Deletes a file. The method deletes a file stored on the FTP server. 
520 *
521 * Params: filename - The name of the required file.      
522 *  
523 * Return: #lng/retf# 
524 *
525 -----------------------------------------------------------------------------*/
526 
527 method uint ftp.delfile( str filename )
528 {
529 	return this.command("DELE \(filename)") == $FTP_CWDOK
530 }
531 
532 /*-----------------------------------------------------------------------------
533 * Id: ftp_setcurdir F2
534 *
535 * Summary: Sets the current directory. This method sets a new current 
536            directory.
537 *
538 * Params: dirname - The name of a new directory.      
539 *  
540 * Return: #lng/retf# 
541 *
542 -----------------------------------------------------------------------------*/
543 
544 method uint ftp.setcurdir( str dirname )
545 {
546 	return this.command("CWD \(dirname)") == $FTP_CWDOK
547 }
548 
549 /*-----------------------------------------------------------------------------
550 * Id: ftp_getcurdir F2
551 *
552 * Summary: Retrieves the current directory. The method retrieves the current
553            directory name from the FTP server.
554 *
555 * Params: dirname - Result string.      
556 *  
557 * Return: #lng/retf# 
558 *
559 -----------------------------------------------------------------------------*/
560 
561 method uint ftp.getcurdir( str dirname )
562 {
563 	str   response 
564 	uint  off till
565 
566 	dirname.clear()
567 	if this.command("PWD") != $FTP_MKDIROK : return 0
568 
569 	off = this.lastresponse( response ).findch( '"' ) + 1
570 	till = response.findchfrom( '"', off )
571 	dirname.substr( response, off, till - off )
572 	if !*dirname : return 0
573 
574 	return 1
575 }
576 
577 /*-----------------------------------------------------------------------------
578 * Id: ftp_rename F2
579 *
580 * Summary: Renames a file. This method renames a file or directory stored 
581            on the FTP server.
582 *
583 * Params: from - The current name of the file or directory. 
584           to - A new name.  
585 *  
586 * Return: #lng/retf# 
587 *
588 -----------------------------------------------------------------------------*/
589 
590 method uint ftp.rename( str from, str to )
591 {
592 	if this.command("RNFR \(from)") != $FTP_FILEOK : return 0
593 	return this.command("RNTO \(to)") == $FTP_CWDOK 
594 }
595 
596 /*-----------------------------------------------------------------------------
597 * Id: ftp_getsize F2
598 *
599 * Summary: Retrieves the file size from the FTP server.
600 *
601 * Params: name - Filename. 
602           psize - A pointer to uint value is used to store the file size. 
603 *  
604 * Return: #lng/retf# 
605 *
606 -----------------------------------------------------------------------------*/
607 
608 method uint ftp.getsize( str name, uint psize )
609 {
610 	str size
611 
612 	psize->uint = 0
613 	if this.command("SIZE \(name)") != $FTP_FILESTAT : return 0
614 
615 	this.lastresponse( size ).del( 0, 4 )
616 	psize->uint = uint( size )
617 	return 1 
618 }
619 
620 /*-----------------------------------------------------------------------------
621 * Id: ftp_gettime F2
622 *
623 * Summary: Retrieves the file time. Retrieves last write times for the file 
624            on the FTP server. 
625 *
626 * Params: name - Filename. 
627           dt - The variable of #a( tdatetime ) type is used to retrieve the /
628                file time. 
629 *  
630 * Return: #lng/retf# 
631 *
632 -----------------------------------------------------------------------------*/
633 
634 method uint ftp.gettime( str name, datetime dt )
635 {
636 	str time year month day
637 
638 	mzero( &dt, sizeof( datetime ))
639 	if this.command("MDTM \(name)") != $FTP_FILESTAT : return 0
640 
641 	this.lastresponse( time ).del( 0, 4 )
642 	time.trimspace()
643 	year.substr( time, 0, 4 )
644 	month.substr( time, 4, 2 )
645 	day.substr( time, 6, 2 )
646 	dt.setdate( uint( day ), uint( month ), uint( year ))
647 	dt.hour = uint( year.substr( time, 8, 2 ))
648 	dt.minute = uint( month.substr( time, 10, 2 ))
649 	dt.second = uint( day.substr( time, 12, 2 ))
650 	
651 	return 1 
652 }
653 
654 /*-----------------------------------------------------------------------------
655 * Id: ftp_setattrib F2
656 *
657 * Summary: Sets the attributes. This method sets the attributes for the file 
658            or the directory.
659 *
660 * Params: name - The name of a file or directory. 
661           mode - The attributes for the file. 
662 *  
663 * Return: #lng/retf# 
664 *
665 -----------------------------------------------------------------------------*/
666 
667 method uint ftp.setattrib( str name, uint mode )
668 {
669 //	str  chmode
670 
671 	mode &= $S_IRWXU | $S_IRWXG | $S_IRWXO
672 	
673 	if this.command("SITE CHMOD \(hex2strl( mode)) \(name)") != $FTP_OK
674 	{ 
675  		return 0
676 	}
677 	return 1 
678 }
679 
680 /*-----------------------------------------------------------------------------
681 * Id: ftp_getfile F2
682 *
683 * Summary: Retrieves a file. The method retrieves files from the FTP server.
684 *
685 * Params: filename - The downloaded file name. 
686           databuf - The received data buffer. Data are not stored on a drive. 
687           flag - Additional flags. $$[ftpget]$$[ftpgetbuf]
688 *  
689 * Return: #lng/retf# 
690 *
691 -----------------------------------------------------------------------------*/
692 
693 method uint ftp.getfile( str filename, buf databuf, uint flag )
694 {
695 	uint       data dif i 
696    buf        fbuf
697    uint       ret range
698    file       fdwn
699 	uint       isfile = flag & $FTP_FILE
700 	finfo      fi 
701 
702 	if this.command( "TYPE \(?( flag & $FTP_BINARY, "I", "A" ))") != $FTP_OK
703 	{ 
704 		return 0	
705 	}
706 	if !this.listen() : return 0
707 
708 	this.ni.param = 0
709  
710 	if isfile && flag & $FTP_CONTINUE
711    {  
712       getfileinfo( databuf->str, fi )
713       if fi.sizelo
714 		{
715 			if this.command( "REST \(fi.sizelo)" ) != $FTP_FILEOK
716 			{
717 				flag &= ~$FTP_CONTINUE
718 			}
719 			else : this.ni.param = fi.sizelo
720 		}	 
721    }
722 	data = ?( isfile, &fbuf, &databuf )
723    data as buf
724 
725    if isfile
726    {
727       data.expand( 0x20000 )
728       if !( fdwn.open( databuf->str, ?( flag & $FTP_CONTINUE,
729                             $OP_ALWAYS, $OP_CREATE )))
730       {
731          this.ni.sparam = databuf->str
732          ineterror = $ERRINET_OPENFILE
733          this.notify( $NFYINET_ERROR )
734          goto end
735       }
736 		if this.ni.param : fdwn.setpos( 0, $FILE_END )
737    }
738    else 
739    {
740 		uint fullsize
741 
742 		data.clear()
743 		this.getsize( filename, &fullsize )
744       if uint( fullsize ) : data.expand( uint( fullsize ) + 0x7FFF )
745    }
746 
747   	if this.command( "RETR \(filename)" ) != $FTP_OPENING : return 0 
748   
749 	if !this.accept() : return 0
750 
751 	do 
752    {
753       i = *data
754       this.sockdata.recv( data )
755       
756 		dif = *data - i
757       this.ni.param += dif
758  
759       if isfile && ( *data >= 0x7FFF || !dif )
760       {
761          if !( fdwn.write( data ))
762          {
763             this.ni.sparam = databuf->str
764             ineterror = $ERRINET_WRITEFILE
765             this.notify( $NFYINET_ERROR )
766             goto end
767          }
768          if !this.notify( $NFYINET_GET )
769 		   {
770    			this.sockdata.close()
771 //	   		this.command("ABOR") 
772  	     		goto end
773    		}
774          data.use = 0
775       }
776    } while dif
777    
778    if flag & $FTP_STR : data += byte( 0 )
779    this.notify( $NFYINET_END )
780 	this.sockdata.close()
781 
782 	if this.cmdresponse() != $FTP_ENDTRAN
783 	{
784 		ineterror = $ERRFTP_RESPONSE
785 		goto end
786 	}
787 
788    ret = 1   
789    label end      
790    if fdwn.fopen 
791    {
792       if ret && flag & $FTP_SETTIME
793       {
794          filetime ft
795 			datetime dt
796          
797 			if this.gettime( filename, dt )
798 			{
799          	datetimetoftime( dt, ft )
800          	fdwn.settime( ft )
801 			}
802       }
803       fdwn.close( )
804    }
805    if !ret && ineterror : this.notify( $NFYINET_ERROR )
806    
807    return ret
808 }
809 
810 /*-----------------------------------------------------------------------------
811 * Id: ftp_getfile_1 FA
812 *
813 * Summary: The method retrieves files from the FTP server.
814 *
815 * Params: srcname - The downloaded file name. 
816           destname - A new file name on user's machine.  
817           flag - Flags.$$[ftpget]$$[ftpgetfile]
818 *  
819 * Return: #lng/retf# 
820 *
821 -----------------------------------------------------------------------------*/
822 
823 method uint ftp.getfile( str srcname, str destname, uint flag )
824 {
825    flag &= 0xF0FF
826    return this.getfile( srcname, destname->buf, flag | $FTP_FILE )
827 }
828 
829 /*-----------------------------------------------------------------------------
830 ** Id: ftp_putfile F2
831 *
832 * Summary: Stores a file on the FTP server. This method is used to upload 
833            the required file from the remote host to the FTP server. 
834 *
835 * Params: srcname - The name of the required source file. 
836           destname - The name of a file stored on the FTP server. 
837           flag - Flags. If the flag of the binary or text mode is not /
838                  specified, the method makes effort to determine a file /
839                  type. $$[ftpput]    
840 *  
841 * Return: #lng/retf# 
842 *
843 -----------------------------------------------------------------------------*/
844 
845 method uint ftp.putfile( str srcname, str destname, uint flag )
846 {
847 	uint  offset size cur ret i
848    file  fdwn
849 	buf   data
850 	str   tmode
851 
852 	subfunc uint nextread
853 	{
854 		cur = min( size, 0x20000 )
855 		data.use = 0
856 		if fdwn.read( data, cur ) != cur
857 		{
858    		this.ni.sparam = srcname
859       	ineterror = $ERRINET_READFILE
860       	return 0
861 		}
862 		size -= cur
863 		return 1
864 	}
865 
866    if !( fdwn.open( srcname, $OP_READONLY ))
867    {
868    	this.ni.sparam = srcname
869       ineterror = $ERRINET_OPENFILE
870       this.notify( $NFYINET_ERROR )
871       return 0
872    }
873 	size = fdwn.getsize( ) 
874 	if flag & $FTP_CONTINUE
875 	{ 
876 		if !this.getsize( destname, &offset ) || offset >= size
877 		{
878 			flag &= ~$FTP_CONTINUE
879 		}
880 		else
881 		{
882 			this.ni.param = offset
883 			size -= offset
884 			fdwn.setpos(  offset, $FILE_BEGIN )
885 		}
886 	}
887    data.expand( 0x20000 )
888 	if !nextread() : goto end
889 
890 	tmode = "TYPE A"	
891 	if flag & $FTP_BINARY : tmode = "TYPE I" 	
892 	elif !( flag & $FTP_TEXT )
893 	{
894 		fornum i = 0, *data - 1
895 		{
896 			if !data[i] || ( data[i] == 0xD && data[i + 1] != 0xA )
897 			{
898 				tmode = "TYPE I"
899 				break		
900 			}    
901 		}		
902 	}
903 	if this.command( tmode ) != $FTP_OK : goto close	
904 	if !this.listen() : goto close
905 	
906 	if this.command( "\(?( flag & $FTP_CONTINUE, "APPE", 
907                     "STOR")) \( destname )") != $FTP_OPENING : goto close  
908 
909 	if !this.accept() : goto close 
910 
911 	while 1
912 	{
913 		uint off last
914 	   uint sent
915 
916 	  	last = *data
917    
918 	   while last
919    	{   
920       	sent = send( this.sockdata.socket, data.ptr() + off, min( 0x7FFF, last ), 
921                       0  )
922 			if	sent == $SOCKET_ERROR 
923 			{
924 				inet_seterror()
925 				this.sockdata.close()
926 				goto close
927 			}
928 			else
929 			{
930 				this.ni.param += sent
931 				if !this.notify( $NFYINET_PUT )
932 				{
933 					this.sockdata.close()
934  					goto close
935 				}
936 			}
937       	last -= sent
938       	off += sent
939    	}
940 //		this.sockdata.send( data )
941 		if !size : break
942 		nextread()
943 	}
944    this.notify( $NFYINET_END )
945 	this.sockdata.close()
946 	if this.cmdresponse() != $FTP_ENDTRAN
947 	{
948 		ineterror = $ERRFTP_RESPONSE
949 		goto end
950 	}
951    ret = 1   
952    label end      
953    if !ret && ineterror : this.notify( $NFYINET_ERROR )
954 	label close
955    fdwn.close( )
956    
957    return ret
958 }
959