FTP: Difference between revisions

From Rosetta Code
Content added Content deleted
(created page)
 
(alternative tcl implementation)
Line 23: Line 23:


=={{header|Tcl}}==
=={{header|Tcl}}==
===Using package ftp===
<lang Tcl>
<lang Tcl>
package require ftp
package require ftp
Line 33: Line 34:
::ftp::Type $conn binary
::ftp::Type $conn binary
::ftp::Get $conn README README
::ftp::Get $conn README README
</lang>

===Using a virtual file system===
An alternative approach that uses the package [http://sourceforge.net/projects/tclvfs/ TclVFS] to access ftp:// paths as a virtual file system.

<lang tcl>
package require vfs::urltype
vfs::urltype::Mount ftp

# Patch to enable FTP passive mode.
source vfsftpfix.tcl

set dir [pwd]
cd ftp://kernel.org/pub/linux/kernel
foreach line [glob -dir ftp://kernel.org/pub/linux/kernel *] {
puts $line
}
file copy README [file join $dir README]
</lang>

The file <tt>vfsftpfix.tcl</tt> with the passive mode patch (see http://wiki.tcl.tk/12837):
<lang tcl>
# Replace vfs::ftp::Mount to enable vfs::ftp to work in passive
# mode and make that the default.
package require vfs::ftp
proc vfs::ftp::Mount {dirurl local {mode passive}} {
set dirurl [string trim $dirurl]
::vfs::log "ftp-vfs: attempt to mount $dirurl at $local"
if {[string index $dirurl end] != "/"} {
::vfs::log "ftp-vfs: adding missing directory delimiter to mount point"
append dirurl "/"
}

set urlRE {(?:ftp://)?(?:([^@:]*)(?::([^@]*))?@)?([^/:]+)(?::([0-9]*))?/(.*/)?$}
if {![regexp $urlRE $dirurl - user pass host port path]} {
return -code error "Sorry I didn't understand\
the url address \"$dirurl\""
}

if {![string length $user]} {
set user anonymous
}

if {![string length $port]} {
set port 21
}

set fd [::ftp::Open $host $user $pass -port $port -output ::vfs::ftp::log -mode $mode]
if {$fd == -1} {
error "Mount failed"
}

if {$path != ""} {
if {[catch {
::ftp::Cd $fd $path
} err]} {
ftp::Close $fd
error "Opened ftp connection, but then received error: $err"
}
}

if {![catch {vfs::filesystem info $dirurl}]} {
# unmount old mount
::vfs::log "ftp-vfs: unmounted old mount point at $dirurl"
vfs::unmount $dirurl
}
::vfs::log "ftp $host, $path mounted at $fd"
vfs::filesystem mount $local [list vfs::ftp::handler $fd $path]
# Register command to unmount
vfs::RegisterMount $local [list ::vfs::ftp::Unmount $fd]
return $fd
}
</lang>
</lang>

Revision as of 20:05, 3 June 2014

Task
FTP
You are encouraged to solve this task according to the task description, using any language you may know.

Connect to a server, change directory and download a file as binary using the FTP protocol. Use passive mode if available.

Python 2

<lang Python> from ftplib import FTP ftp = FTP('kernel.org') ftp.login() ftp.cwd('/pub/linux/kernel') ftp.set_pasv(True) # Default since Python 2.1 print ftp.retrlines('LIST') print ftp.retrbinary('RETR README', open('README', 'wb').write) ftp.quit() </lang>

REBOL

<lang REBOL> system/schemes/ftp/passive: on print read ftp://kernel.org/pub/linux/kernel/ write/binary %README read/binary ftp://kernel.org/pub/linux/kernel/README </lang>

Tcl

Using package ftp

<lang Tcl> package require ftp

set conn [::ftp::Open kernel.org anonymous "" -mode passive]

ftp::Cd $conn /pub/linux/kernel

foreach line [ftp::NList $conn] {

   puts $line

}

ftp::Type $conn binary
ftp::Get $conn README README

</lang>

Using a virtual file system

An alternative approach that uses the package TclVFS to access ftp:// paths as a virtual file system.

<lang tcl> package require vfs::urltype vfs::urltype::Mount ftp

  1. Patch to enable FTP passive mode.

source vfsftpfix.tcl

set dir [pwd] cd ftp://kernel.org/pub/linux/kernel foreach line [glob -dir ftp://kernel.org/pub/linux/kernel *] {

   puts $line

} file copy README [file join $dir README] </lang>

The file vfsftpfix.tcl with the passive mode patch (see http://wiki.tcl.tk/12837): <lang tcl>

  1. Replace vfs::ftp::Mount to enable vfs::ftp to work in passive
  2. mode and make that the default.

package require vfs::ftp proc vfs::ftp::Mount {dirurl local {mode passive}} {

   set dirurl [string trim $dirurl]
   ::vfs::log "ftp-vfs: attempt to mount $dirurl at $local"
   if {[string index $dirurl end] != "/"} {
       ::vfs::log "ftp-vfs: adding missing directory delimiter to mount point"
       append dirurl "/"
   }
   set urlRE {(?:ftp://)?(?:([^@:]*)(?::([^@]*))?@)?([^/:]+)(?::([0-9]*))?/(.*/)?$}
   if {![regexp $urlRE $dirurl - user pass host port path]} {
       return -code error "Sorry I didn't understand\
         the url address \"$dirurl\""
   }
   if {![string length $user]} {
       set user anonymous
   }
   if {![string length $port]} {
       set port 21
   }
   set fd [::ftp::Open $host $user $pass -port $port -output ::vfs::ftp::log -mode $mode]
   if {$fd == -1} {
       error "Mount failed"
   }
   if {$path != ""} {
       if {[catch {
           ::ftp::Cd $fd $path
       } err]} {
           ftp::Close $fd
           error "Opened ftp connection, but then received error: $err"
       }
   }
   if {![catch {vfs::filesystem info $dirurl}]} {
       # unmount old mount
       ::vfs::log "ftp-vfs: unmounted old mount point at $dirurl"
       vfs::unmount $dirurl
   }
   ::vfs::log "ftp $host, $path mounted at $fd"
   vfs::filesystem mount $local [list vfs::ftp::handler $fd $path]
   # Register command to unmount
   vfs::RegisterMount $local [list ::vfs::ftp::Unmount $fd]
   return $fd

} </lang>