📄 ftp_lib.tcl
字号:
## tcl FTP package -- # # Required: tcl8.0b1## Created: 12/96 # Changed: 08/97 # Version: 0.81## core ftp support: FTP::Open <server> <user> <passwd># FTP::Close# FTP::Cd <directory># FTP::Pwd# FTP::Type <ascii|binary> # FTP::List <directory># FTP::NList <directory># FTP::Delete <file># FTP::Rename <from> <to># FTP::Put <local> <?remote?># FTP::Get <remote> <?local?># FTP::MkDir <directory># FTP::RmDir <directory>## Copyright (C) 1997, Steffen Traeger# EMAIL: Steffen.Traeger@t-online.de# URL: http://home.t-online.de/home/Steffen.Traeger## This package is free software; you can redistribute it and/or # modify it. # This library is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.## The description of the procedures are partly exerpted from RFC 959.# For more details see also RFC 959.#########################################################################package provide FTP [lindex {$Revision: 1.3 $} 1]namespace eval FTP {# namespace export DisplayMsg Open Close Cd Pwd Type List NList \# Delete Rename Put Get MkDir RmDir# CopyNext required export for callback on Windows NT# ZW, ver2 #namespace export DisplayMsg Open Close Cd Pwd Type List NList \# Delete Rename Put Get MkDir RmDir CopyNext SetLogFilenamespace export DisplayMsg Open Close Cd Pwd Type List NList FileSize\ ModTime Delete Rename Put Append Get Reget Newer\ Quote MkDir RmDir CopyNext SetLogFile set VERBOSE 0set DEBUG 0 global FTP_LIB_G############################################################################### SetLogFile --## This overrides the stdout stream with another stream (Not a file path).# Used by package users to overcome NT TCL/TK limitations on stdout # output (goes to console)## MK - 29 Nov 1997#proc SetLogFile {LOG_FILE} { global FTP_LIB_G set FTP_LIB_G(LOG_FILE) $LOG_FILE}############################################################################### DisplayMsg --## This is a simple procedure to display any messages on screen.# It must be overwritten by users source code in the form:# (exported)## namespace FTP {# proc DisplayMsg {msg} {# ......# }# }## Arguments:# msg - message stringproc DisplayMsg {msg {state ""}} {variable VERBOSE global FTP_LIB_G set OUT "" # Added by MK - 29 Nov 1997 catch { set OUT $FTP_LIB_G(LOG_FILE) } if { $OUT == "" } { set OUT "stdout" } puts $OUT $msg puts $msg}############################################################################### Timeout --## Handle timeouts# # Arguments:# -#proc Timeout {} {variable ftpupvar #0 finished state after cancel $ftp(Wait) set state(control) 1 DisplayMsg "Timeout of control connection after $ftp(Timeout) sec.!" error}############################################################################### WaitOrTimeout --## Blocks the running procedure and waits for a variable of the transaction # to complete. It continues processing procedure until a procedure or # StateHandler sets the value of variable "finished". # If a connection hangs the variable is setting instead of by this procedure after # specified seconds in $ftp(Timeout).# # # Arguments:# - #proc WaitOrTimeout {} {variable ftpupvar #0 finished state set retvar 1 if {[info exists state(control)]} { set ftp(Wait) [after [expr $ftp(Timeout) * 1000] [namespace current]::Timeout] vwait finished(control) set retvar $state(control) } return $retvar}############################################################################### WaitComplete --## Transaction completed.# Cancel execution of the delayed command declared in procedure WaitOrTimeout.# # Arguments:# value - result of the transaction# 0 ... Error# 1 ... OK#proc WaitComplete {value} {variable ftpupvar #0 finished state if {[info exists state(data)]} { vwait finished(data) } after cancel $ftp(Wait) set state(control) $value}############################################################################### PutsCtrlSocket --## Puts then specified command to control socket,# if DEBUG is set than it logs via DisplayMsg# # Arguments:# command - ftp command#proc PutsCtrlSock {{command ""}} {variable ftp variable DEBUG if {$DEBUG} { DisplayMsg "---> $command" } puts $ftp(CtrlSock) $command flush $ftp(CtrlSock)}############################################################################### StateHandler --## Implements a finite state handler and a fileevent handler# for the control channel# # Arguments:# sock - socket name# If called from a procedure than this argument is empty.# If called from a fileevent than this argument contains# the socket channel identifier.proc StateHandler {{sock ""}} {upvar #0 finished statevariable ftp variable DEBUG variable VERBOSE # disable fileevent on control socket, enable it at the and of the state machine # fileevent $ftp(CtrlSock) readable {} # there is no socket (and no channel to get) if called from a procedure set rc " " if { $sock != "" } { set number [gets $sock bufline] if { $number > 0 } { # get return code, check for multi-line text regexp "(^\[0-9\]+)( |-)?(.*)$" $bufline all rc multi_line msgtext set buffer $bufline # multi-line format detected ("-"), get all the lines # until the real return code while { $multi_line == "-" } { set number [gets $sock bufline] if { $number > 0 } { append buffer \n "$bufline" regexp "(^\[0-9\]+)( |-)?(.*)$" $bufline all rc multi_line } } } elseif [eof $ftp(CtrlSock)] { # remote server has closed control connection # kill control socket, unset State to disable all following command set rc 421 if {$VERBOSE} { DisplayMsg "C: 421 Service not available, closing control connection." control } DisplayMsg "Service not available!" error CloseDataConn WaitComplete 0 catch {unset ftp(State)} catch {close $ftp(CtrlSock); unset ftp(CtrlSock)} return } } if {$DEBUG} { DisplayMsg "-> rc=\"$rc\"\n-> state=\"$ftp(State)\"" } # system status replay if {$rc == "211"} {return} # use only the first digit regexp "^\[0-9\]?" $rc rc switch -- $ftp(State) { user { switch $rc { 2 { PutsCtrlSock "USER $ftp(User)" set ftp(State) passwd } default { set errmsg "Error connecting! $msgtext" set complete_with 0 } } } passwd { switch $rc { 2 { set complete_with 1 } 3 { PutsCtrlSock "PASS $ftp(Passwd)" set ftp(State) connect } default { set errmsg "Error connecting! $msgtext" set complete_with 0 } } } connect { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error connecting! $msgtext" set complete_with 0 } } } quit { PutsCtrlSock "QUIT" set ftp(State) quit_sent } quit_sent { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error disconnecting! $msgtext" set complete_with 0 } } } quote { PutsCtrlSock $ftp(Cmd) set ftp(State) quote_sent } quote_sent { set complete_with 1 set ftp(Quote) $buffer } type { if { $ftp(Type) == "ascii" } { PutsCtrlSock "TYPE A" } else { PutsCtrlSock "TYPE I" } set ftp(State) type_sent } type_sent { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error setting type \"$ftp(Type)\"!" set complete_with 0 } } } nlist_active { if {[OpenActiveConn]} { PutsCtrlSock "PORT $ftp(LocalAddr),$ftp(DataPort)" set ftp(State) nlist_open } else { set errmsg "Error setting port!" } } nlist_passive { PutsCtrlSock "PASV" set ftp(State) nlist_open } nlist_open { switch $rc { 2 { if {$ftp(Mode) == "passive"} { if ![OpenPassiveConn $buffer] { set errmsg "Error setting PASSIVE mode!" set complete_with 0 } } PutsCtrlSock "NLST$ftp(Dir)" set ftp(State) list_sent } default { if {$ftp(Mode) == "passive"} { set errmsg "Error setting PASSIVE mode!" } else { set errmsg "Error setting port!" } set complete_with 0 } } } list_active { if {[OpenActiveConn]} { PutsCtrlSock "PORT $ftp(LocalAddr),$ftp(DataPort)" set ftp(State) list_open } else { set errmsg "Error setting port!" } } list_passive { PutsCtrlSock "PASV" set ftp(State) list_open } list_open { switch $rc { 2 { if {$ftp(Mode) == "passive"} { if {![OpenPassiveConn $buffer]} { set errmsg "Error setting PASSIVE mode!" set complete_with 0 } } PutsCtrlSock "LIST$ftp(Dir)" set ftp(State) list_sent } default { if {$ftp(Mode) == "passive"} { set errmsg "Error setting PASSIVE mode!" } else { set errmsg "Error setting port!" } set complete_with 0 } } } list_sent { switch $rc { 1 { set ftp(State) list_close } default { if { $ftp(Mode) == "passive" } { unset state(data) } set errmsg "Error getting directory listing!" set complete_with 0 } } } list_close { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error receiving list!" set complete_with 0 } } } size { PutsCtrlSock "SIZE $ftp(File)" set ftp(State) size_sent } size_sent { switch $rc { 2 { regexp "^\[0-9\]+ (.*)$" $buffer all ftp(FileSize) set complete_with 1 } default { set errmsg "Error getting file size!" set complete_with 0 } } } modtime { PutsCtrlSock "MDTM $ftp(File)" set ftp(State) modtime_sent } modtime_sent { switch $rc { 2 { regexp "^\[0-9\]+ (.*)$" $buffer all ftp(DateTime) set complete_with 1 } default { set errmsg "Error getting modification time!" set complete_with 0 } } } pwd { PutsCtrlSock "PWD" set ftp(State) pwd_sent } pwd_sent { switch $rc { 2 { regexp "^.*\"(.*)\"" $buffer temp ftp(Dir) set complete_with 1 } default { set errmsg "Error getting working dir!" set complete_with 0 } } } cd { PutsCtrlSock "CWD$ftp(Dir)" set ftp(State) cd_sent } cd_sent { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error changing directory!" set complete_with 0 } } } mkdir { PutsCtrlSock "MKD $ftp(Dir)" set ftp(State) mkdir_sent } mkdir_sent { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error making dir \"$ftp(Dir)\"!" set complete_with 0 } } } rmdir { PutsCtrlSock "RMD $ftp(Dir)" set ftp(State) rmdir_sent } rmdir_sent { switch $rc { 2 { set complete_with 1 } default { set errmsg "Error removing directory!" set complete_with 0 } } } delete { PutsCtrlSock "DELE $ftp(File)" set ftp(State) delete_sent
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -