**Alie Tormusa Koroma** I come from a Telecoms support background, before that I was a Visual Basic programmer (I know...I'm not proud of it myself). Since entering the support and sys admin arena in 2000, I've scripted a lot and did a tinnie bit of Java along the way. While I can boast of being a Solaris Administrator, a seasoned programmer is definitely not one of my accolades. I've been a Tcl lover since accidentally bumping into a Tcl 8.5 tutorial four years ago. I say it's accidental because a friend who is not a developer by any means was merely passing some C++ documentations over for me to copy from her memory stick. Long story short, I asked about this Tcl tutorial document and she told me it was a programming language. My development skills were almost dead and was looking to revive it at that time (the reason why I wanted the C++ documents in the first place). I decided to learn Tcl instead of C++. I won't call it love at first touch but when I read the section of "list handling" and the power packed in them I knew I'd found the language to revive my programming past. It paid off, because shortly after I landed a job in which I programmed telecoms services using Tcl (for Mobile broadband and 4G/LTE services). Yep...Tcl is wild out there in the wild! Today, I am the self proclaimed biggest [Wub] fan in my opinion. I struggle with it but I'm new to web development all together and I can see its great potentials. I also dream to influence a Tcl/Tk conference in South Africa someday (dreams do come true I heard). The following is a ftp client program for fetching file from a remote server (fetchr). I used it in a cron job to regularly move nth server logs for post processing. It is based on tcllib::ftp package ====== #!/usr/bin/tcl #################################################################################### # author: alie_tormusa_koroma [datagnius at mail dot com] # # descpt: ftp client for fetching file type (defined pattern), certain date from # # a ftp server. this program is controlled by a config_file and is ideal for # internal networks as the config file has to contain the username & password # depend: tcllib::ftp # # release: fetchr verions 0.0.1 #################################################################################### #################################################################################### package require Tcl package require ftp set connState {false} set baseDir "/opt/fetchr" # the install directory or script home set lckFile "/var/tmp/.fetchr.lck" # name of the lock file set fetchList "$baseDir/conf/.fetchlist" # this is where files already fetched will be logged to avoid duplicate fetching set fetchConf "$baseDir/conf/fetchr.conf" # the configuration file set ftpSrv {} ; set ftpuser {} ; set ftppwd {} ; set getDir {} ; set putDir {} ; set getPat {} ; set getWhen {} # sample configuration file containing all hostnames and file pattern to fetch if 0 { ftpuser:ftppassword:remote_getfile_directory:local_putfile_directory:getfile_pattern:getWhen_file ftpuser=remote ftp username ftppassword=ftp user password remote_getfile_directory=remote directory containing files to get local_putfile_directory=local directory to put files getfile_pattern=files pattern to get (e.g 2015_*.sql) getWhen_file=file date to get (e.g today=now; yesterday=yesterday) } proc FtpConnect {ftpServer ftpUser ftpPasswd} { # open connection to ftp server puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FtpConnect(Connect)\ [info script]::FTP Connection request received. ConnectionString($ftpUser\@$ftpServer)" global connState {true} return [::ftp::Open $ftpServer $ftpUser $ftpPasswd -blocksize 8192 -timeout 7200] } ;#endOf::FtpConnect proc ApproveFileFetch {fileName} { global baseDir ; global fetchList ; set srhResult {yes} if {[file exists $fetchList]} { set srhResult {} set aff [open $fetchList r] set srhResult [lsearch -start 0 -inline [read $aff] $fileName*] close $aff if { $srhResult == {} } { set srhResult {yes} } else { set srhResult {no} } } else { set srhResult {no} } return $srhResult } ;#endOf::ApproveFileFetch proc LogGetFile {getFile} { if { $getFile != "" } { global fetchList set fls [open $fetchList a] puts $fls $getFile ; close $fls } } ;#LogGetFile proc FTPMain {} { global connState {false} global baseDir lckFile fetchList fetchConf global ftpSrv ftpuser ftppwd getDir putDir getPat getWhen set fls [open $fetchList a+] if {[file exists $fetchConf] && [file size $fetchConf] > 0 } { set cfg [open $fetchConf r] while {![eof $cfg]} { set cfgLine [gets $cfg] ; set ftpSrv [lindex [split $cfgLine :] 0] if { [string range $ftpSrv 0 0] != "#" } { set ftpuser [lindex [split $cfgLine :] 1] set ftppwd [lindex [split $cfgLine :] 2] set getDir [lindex [split $cfgLine :] 3] set putDir [lindex [split $cfgLine :] 4] set getPat [lindex [split $cfgLine :] 5] set getWhen [lindex [split $cfgLine :] 6] # set the session attributes on the ftp server if { $connState == {false} && $ftpuser != {} } { puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(FTPConnReq)\ [info script]::RequestingFTPConn ConnectionString::ftpSrv:$ftpSrv ftpuser:$ftpuser ftppwd:hidden" set ftp [FtpConnect $ftpSrv $ftpuser $ftppwd] } if { $ftp != -1 } { puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(FTPConnect) [info script]\ Established connection:: LocalHost:[info hostname] => RemoteHost:$ftpSrv" ::ftp::Cd $ftp $getDir ::ftp::Type $ftp binary foreach {iFile} [::ftp::NList $ftp $getDir] { if { [string match *$getPat* $iFile] } { set indxFile [join [lrange [split [lindex [split $iFile /] end] .] 0 2] .] switch -glob [string tolower $getWhen] { yes* { set ystDay [lindex [split [clock format [expr [clock seconds]-86400]]] 2] set filDay [lindex [split [clock format [::ftp::ModTime $ftp $iFile]]] 2] if { $filDay == $ystDay && [ApproveFileFetch $indxFile] == {yes} } { ::ftp::Get $ftp $iFile $putDir ; LogGetFile $indxFile puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] [info script] FTPMain(getYesterday) [info script]::$indxFile" } } now* { set fTime [clock format [clock seconds] -format %d] set mTime [clock format [lindex [split $indxFile .] 1] -format %d] if { $fTime == $mTime && [ApproveFileFetch $indxFile] == {yes} } { ::ftp::Get $ftp $iFile $putDir ; LogGetFile $indxFile #puts stdout "GetFile_NOW:: [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S}] $indxFile" puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(getNow)::$indxFile [info script]::Fetch success" } } default { set theFile [lindex [split $iFile /] end] set cDay [string range $getWhen 0 1] set cMth [string range $getWhen 2 end] set fMth [lindex [clock format [lindex [split $theFile .] 1]] 1] if { [string totitle $cMth] == [string totitle $fMth] } { set fDay [lindex [clock format [lindex [split $theFile .] 1]] 2] if { $fDay == $cDay && [ApproveFileFetch $indxFile] == {yes} } { ::ftp::Get $ftp $iFile $putDir ;# puts $fls $indxFile LogGetFile $indxFile puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] [info script] FTPMain(getDate$cDay$cMth) [info script]::$indxFile" } } } } ;#endOf::Switch_getWhen } ;#endOf::IfStringMatch } ;#endOf:Foreach } else { puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(Connect)\ [info script]:: Unable to connect to FTPServer($ftpSrv)" } ;#endOf::IfConnstateTrue } ;#endOf::IfStringRange } ;#endOf:WhileEOF close $cfg if {[catch {::ftp::Close $ftp} cerr]} { if {[file exists $lckFile]} {file delete $lckFile} set connState {false} } set connState {false} #if {[file exists $lckFile]} {file delete $lckFile} ::ftp::Close $ftp puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(::Exiting::) [info script]::Fetch complete CleanExit" ; exit 0 } else { puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(NoConfigFile) [info script]::$fetchConf ZeroBtyesOrMissing" } ;#endOf:IfFileExists ::ftp::Close $ftp if {[file exists $lckFile]} {file delete $lckFile} puts stdout "[clock format [clock seconds] -format {%d-%m-%Y %H:%M:%S}] FTPMain(::Exiting::) [info script]::Fetch complete CleanExit" ; exit 0 } #endOf::FTPMain FTPMain ======