Tcl Library Source Code

Changes On Branch ak-tkt-b41b6f76b0-ftp-eprt
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch ak-tkt-b41b6f76b0-ftp-eprt Excluding Merge-Ins

This is equivalent to a diff from 5dbaabe344 to eb27679053

2014-12-03
00:38
Draft work on EPSV support. Leaf check-in: eb27679053 user: andreask tags: ak-tkt-b41b6f76b0-ftp-eprt
2014-12-02
22:01
Ref tkt [b41b6f76b0]. Draft work on EPRT/EPSV support for the ftp client. check-in: ad53730d6b user: andreask tags: ak-tkt-b41b6f76b0-ftp-eprt
20:34
Updated online documentation. check-in: c4d3ec1eff user: aku tags: trunk
20:21
cmdline - Ticket [fef66e4953]. Extended to support the format --option=value on the commandline. Thanks to [email protected] for the request and patch. Version bumped to 1.4 Braced expressions. Testsuite extended, docs updated. check-in: 5dbaabe344 user: andreask tags: trunk
20:15
crc/sum - Fixed oops, missed update of package index check-in: 2acdfeb08c user: andreask tags: trunk

Changes to modules/ftp/ftp.man.

1
2
3
4
5
6
7
8
9
[comment {-*- tcl -*- doctools manpage}]
[vset PACKAGE_VERSION 2.4.13]
[manpage_begin ftp n [vset PACKAGE_VERSION]]
[see_also ftpd]
[see_also mime]
[see_also pop3]
[see_also smtp]
[keywords ftp]
[keywords internet]

|







1
2
3
4
5
6
7
8
9
[comment {-*- tcl -*- doctools manpage}]
[vset PACKAGE_VERSION 2.5]
[manpage_begin ftp n [vset PACKAGE_VERSION]]
[see_also ftpd]
[see_also mime]
[see_also pop3]
[see_also smtp]
[keywords ftp]
[keywords internet]

Changes to modules/ftp/ftp.tcl.

48
49
50
51
52
53
54

55
56
57
58
59
60
61
# PutData         Data to move when inline
# SourceCI        Channel to read from, "Put"
# ---------------------------------------------
#

package require Tcl 8.2
package require log     ; # tcllib/log, general logging facility.


namespace eval ::ftp {
    namespace export DisplayMsg Open Close Cd Pwd Type List NList \
	    FileSize ModTime Delete Rename Put Append Get Reget \
	    Newer Quote MkDir RmDir

    variable serial  0







>







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# PutData         Data to move when inline
# SourceCI        Channel to read from, "Put"
# ---------------------------------------------
#

package require Tcl 8.2
package require log     ; # tcllib/log, general logging facility.
package require ip      ; # tcllib/dns, ip address checking, classification, and manipulation.

namespace eval ::ftp {
    namespace export DisplayMsg Open Close Cd Pwd Type List NList \
	    FileSize ModTime Delete Rename Put Append Get Reget \
	    Newer Quote MkDir RmDir

    variable serial  0
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
	type_change {
	    set ftp(Type) $ftp(type:changeto)
	    set ftp(State) type
	    StateHandler $s
	}
        nlist_active {
            if { [OpenActiveConn $s] } {
                PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"
                set ftp(State) nlist_open
            } else {
                set errmsg "Error setting port!"
            }
        }
        nlist_passive {
            PutsCtrlSock $s "PASV"
            set ftp(State) nlist_open
        }
        nlist_open {
            switch -exact -- $rc {
                1 {}
		2 {
                    if { [string equal $ftp(Mode) "passive"] } {







|






|







472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
	type_change {
	    set ftp(Type) $ftp(type:changeto)
	    set ftp(State) type
	    StateHandler $s
	}
        nlist_active {
            if { [OpenActiveConn $s] } {
                OpenPort $s
                set ftp(State) nlist_open
            } else {
                set errmsg "Error setting port!"
            }
        }
        nlist_passive {
            RequestPort $s
            set ftp(State) nlist_open
        }
        nlist_open {
            switch -exact -- $rc {
                1 {}
		2 {
                    if { [string equal $ftp(Mode) "passive"] } {
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        list_active {
            if { [OpenActiveConn $s] } {
                PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"
                set ftp(State) list_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        list_passive {
            PutsCtrlSock $s "PASV"
            set ftp(State) list_open
        }
        list_open {
            switch -exact -- $rc {
                1 {}
		2 {
                    if { [string equal $ftp(Mode) "passive"] } {







|







|







509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        list_active {
            if { [OpenActiveConn $s] } {
                OpenPort $s
                set ftp(State) list_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        list_passive {
            RequestPort $s
            set ftp(State) list_open
        }
        list_open {
            switch -exact -- $rc {
                1 {}
		2 {
                    if { [string equal $ftp(Mode) "passive"] } {
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        put_active {
            if { [OpenActiveConn $s] } {
                PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"
                set ftp(State) put_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        put_passive {
            PutsCtrlSock $s "PASV"
            set ftp(State) put_open
        }
        put_open {
            switch -exact -- $rc {
                1 -
		2 {
                    if { [string equal $ftp(Mode) "passive"] } {







|







|







758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        put_active {
            if { [OpenActiveConn $s] } {
                OpenPort $s
                set ftp(State) put_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        put_passive {
            RequestPort $s
            set ftp(State) put_open
        }
        put_open {
            switch -exact -- $rc {
                1 -
		2 {
                    if { [string equal $ftp(Mode) "passive"] } {
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        append_active {
            if { [OpenActiveConn $s] } {
                PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"
                set ftp(State) append_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        append_passive {
            PutsCtrlSock $s "PASV"
            set ftp(State) append_open
        }
        append_open {
            switch -exact -- $rc {
		1 -
                2 {
                    if { [string equal $ftp(Mode) "passive"] } {







|







|







837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        append_active {
            if { [OpenActiveConn $s] } {
                OpenPort $s
                set ftp(State) append_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        append_passive {
            RequestPort $s
            set ftp(State) append_open
        }
        append_open {
            switch -exact -- $rc {
		1 -
                2 {
                    if { [string equal $ftp(Mode) "passive"] } {
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        reget_active {
            if { [OpenActiveConn $s] } {
                PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"
                set ftp(State) reget_restart
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        reget_passive {
            PutsCtrlSock $s "PASV"
            set ftp(State) reget_restart
        }
        reget_restart {
            switch -exact -- $rc {
                2 { 
                    if { [string equal $ftp(Mode) "passive"] } {
                        if { ![OpenPassiveConn $s $buffer] } {







|







|







909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        reget_active {
            if { [OpenActiveConn $s] } {
                OpenPort $s
                set ftp(State) reget_restart
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        }
        reget_passive {
            RequestPort $s
            set ftp(State) reget_restart
        }
        reget_restart {
            switch -exact -- $rc {
                2 { 
                    if { [string equal $ftp(Mode) "passive"] } {
                        if { ![OpenPassiveConn $s $buffer] } {
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        get_active {
            if { [OpenActiveConn $s] } {
                PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"
                set ftp(State) get_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        } 
        get_passive {
            PutsCtrlSock $s "PASV"
            set ftp(State) get_open
        }
        get_open {
            switch -exact -- $rc {
                1 -
		2 -
                3 {







|







|







1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
                    set complete_with 0
		    Command $ftp(Command) error $errmsg
                }
            }
        }
        get_active {
            if { [OpenActiveConn $s] } {
                OpenPort $s
                set ftp(State) get_open
            } else {
                set errmsg "Error setting port!"
		Command $ftp(Command) error $errmsg
            }
        } 
        get_passive {
            RequestPort $s
            set ftp(State) get_open
        }
        get_open {
            switch -exact -- $rc {
                1 -
		2 -
                3 {
2084
2085
2086
2087
2088
2089
2090


2091
2092
2093
2094
2095
2096
2097
2098
	    set dest $source
	} else {
	    if {[file isdirectory $dest]} {
		set dest [file join $dest [file tail $source]]
	    }
	}
	if {![file exists [file dirname $dest]]} {


	    return -code error "ftp::Get, directory \"[file dirname $dest]\" for destination \"$dest\" does not exist"
	}
	set ftp(LocalFilename) $dest
    }

    set ftp(RemoteFilename) $source

    if {$ftp(inline) == 2} {







>
>
|







2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
	    set dest $source
	} else {
	    if {[file isdirectory $dest]} {
		set dest [file join $dest [file tail $source]]
	    }
	}
	if {![file exists [file dirname $dest]]} {
	    return -code error \
		-errorcode {FTP DESTINATION MISSING GET} \
		"ftp::Get, directory \"[file dirname $dest]\" for destination \"$dest\" does not exist"
	}
	set ftp(LocalFilename) $dest
    }

    set ftp(RemoteFilename) $source

    if {$ftp(inline) == 2} {
2167
2168
2169
2170
2171
2172
2173

2174
2175
2176
2177
2178
2179
2180
2181
    }

    if { $dest == "" } {
        set dest $source
    }
    if {![file exists [file dirname $dest]]} {
	return -code error \

	"ftp::Reget, directory \"[file dirname $dest]\" for destination \"$dest\" does not exist"
    }

    set ftp(RemoteFilename) $source
    set ftp(LocalFilename) $dest
    set ftp(From) $from_bytes









>
|







2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
    }

    if { $dest == "" } {
        set dest $source
    }
    if {![file exists [file dirname $dest]]} {
	return -code error \
	    -errorcode {FTP DESTINATION MISSING REGET} \
	    "ftp::Reget, directory \"[file dirname $dest]\" for destination \"$dest\" does not exist"
    }

    set ftp(RemoteFilename) $source
    set ftp(LocalFilename) $dest
    set ftp(From) $from_bytes


2250
2251
2252
2253
2254
2255
2256


2257
2258
2259
2260
2261
2262
2263


2264
2265
2266
2267
2268
2269
2270
2271

    if { ![info exists ftp(State)] } {
        DisplayMsg $s "Not connected!" error
        return 0
    }

    if {[string length $ftp(Command)]} {


	return -code error "unable to retrieve file asynchronously (not implemented yet)"
    }

    if { $dest == "" } {
        set dest $source
    }
    if {![file exists [file dirname $dest]]} {


	return -code error "ftp::Newer, directory \"[file dirname $dest]\" for destination \"$dest\" does not exist"
    }

    set ftp(RemoteFilename) $source
    set ftp(LocalFilename) $dest

    # get remote modification time
    set rmt [ModTime $s $ftp(RemoteFilename)]







>
>
|






>
>
|







2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279

    if { ![info exists ftp(State)] } {
        DisplayMsg $s "Not connected!" error
        return 0
    }

    if {[string length $ftp(Command)]} {
	return -code error \
	    -errorcode {FTP NOT-IMPLEMENTED ASYNC} \
	    "unable to retrieve file asynchronously (not implemented yet)"
    }

    if { $dest == "" } {
        set dest $source
    }
    if {![file exists [file dirname $dest]]} {
	return -code error \
	    -errorcode {FTP DESTINATION MISSING NEWER} \
	    "ftp::Newer, directory \"[file dirname $dest]\" for destination \"$dest\" does not exist"
    }

    set ftp(RemoteFilename) $source
    set ftp(LocalFilename) $dest

    # get remote modification time
    set rmt [ModTime $s $ftp(RemoteFilename)]
3003
3004
3005
3006
3007
3008
3009
3010
3011

3012
3013

3014
3015

3016
3017
3018
3019
3020
3021
3022



3023





3024
3025
3026
3027
3028












3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045


3046


3047
3048
3049












3050
3051
3052
3053
3054
3055
3056
3057
3058
3059

3060











3061
3062
















3063
3064
3065
3066
3067
3068
3069
    
    set rc [catch {set ftp(DummySock) [socket -server [list [namespace current]::InitDataConn $s] 0]} msg]
    if { $rc != 0 } {
        DisplayMsg $s "$msg" error
        return 0
    }

    # prepare local ip address for PORT command (convert pointed format
    # to comma format)


    set ftp(LocalAddr) [lindex [fconfigure $ftp(CtrlSock) -sockname] 0]

    set ftp(LocalAddr) [string map {. ,} $ftp(LocalAddr)]


    # get a new local port address for data transfer and convert it to a format
    # which is useable by the PORT command

    set p [lindex [fconfigure $ftp(DummySock) -sockname] 2]
    if { $VERBOSE } {
        DisplayMsg $s "D: Port is $p" data
    }



    set ftp(DataPort) "[expr {$p / 256}],[expr {$p % 256}]"






    # Marker for WaitDataConn
    set ftp(AC) 0
    return 1
}













#############################################################################
#
# OpenPassiveConn --
#
# Opens a ftp data connection
# 
# Arguments:
# buffer - returned line from server control connection 
# 
# Returns:
# 0 -			no connection
# 1 - 			connection established

proc ::ftp::OpenPassiveConn {s buffer} {
    upvar ::ftp::ftp$s ftp



    if { [regexp -- {([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+)} $buffer all a1 a2 a3 a4 p1 p2] } {


        set ftp(LocalAddr) "$a1.$a2.$a3.$a4"
        set ftp(DataPort) "[expr {$p1 * 256 + $p2}]"













        # establish data connection for passive mode

        set rc [catch {set ftp(DataSock) [socket $ftp(LocalAddr) $ftp(DataPort)]} msg]
        if { $rc != 0 } {
            DisplayMsg $s "$msg" error
            return 0
        }

        InitDataConn $s $ftp(DataSock) $ftp(LocalAddr) $ftp(DataPort)
        return 1

    } else {











        return 0
    }
















}

#############################################################################
#
# OpenControlConn --
#
# Opens a ftp control connection







|
|
>


>
|
|
>
|
|





>
>
>
|
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
















|
>
>
|
>
>
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
|

|
|
|
|
|

|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
    
    set rc [catch {set ftp(DummySock) [socket -server [list [namespace current]::InitDataConn $s] 0]} msg]
    if { $rc != 0 } {
        DisplayMsg $s "$msg" error
        return 0
    }

    # prepare local ip address for PORT command
    # (convert pointed format to comma format)
    # IPv6 addresses are not changed by this.

    set ftp(LocalAddr) [lindex [fconfigure $ftp(CtrlSock) -sockname] 0]
    if {[IpVersion $s $ftp(LocalAddr)] == 4} {
	set ftp(LocalAddr) [string map {. ,} $ftp(LocalAddr)]
    }

    # get a new local port address for data transfer and convert it to
    # a format which is useable by the PORT (or EPRT) command.

    set p [lindex [fconfigure $ftp(DummySock) -sockname] 2]
    if { $VERBOSE } {
        DisplayMsg $s "D: Port is $p" data
    }

    switch -exact -- $ftp(IpVersion) {
	4 {
	    set ftp(DataPort) "[expr {$p / 256}],[expr {$p % 256}]"
	}
	6 {
	    set ftp(DataPort) $p
	}
    }

    # Marker for WaitDataConn
    set ftp(AC) 0
    return 1
}

proc ::ftp::OpenPort {s} {
    upvar ::ftp::ftp$s ftp
    # The array elements "IpVersion", "LocalAddr" and "DataPort" are
    # prepared by "OpenActiveConn", see above.
    switch -exact -- $ftp(IpVersion) {
	4 { PutsCtrlSock $s "PORT $ftp(LocalAddr),$ftp(DataPort)"	}
	6 { PutsCtrlSock $s "EPRT |2|$ftp(LocalAddr)|$ftp(DataPort)|"	}
    }
    # Extended Port command as per RFC 2428.
    return
}

#############################################################################
#
# OpenPassiveConn --
#
# Opens a ftp data connection
# 
# Arguments:
# buffer - returned line from server control connection 
# 
# Returns:
# 0 -			no connection
# 1 - 			connection established

proc ::ftp::OpenPassiveConn {s buffer} {
    upvar ::ftp::ftp$s ftp
    switch -exact -- $ftp(IpVersion) {
	4 {
	    # Port command response as per RFC 959.
	    if {![regexp -- {([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+)} $buffer all a1 a2 a3 a4 p1 p2] } {
		return 0
	    }
	    set ftp(LocalAddr) "$a1.$a2.$a3.$a4"
	    set ftp(DataPort) "[expr {$p1 * 256 + $p2}]"
	}
	6 {
	    # Extended Port command response as per RFC 2428.
	    if {![regexp -- {\((.)(.)(.)([0-9]+)(.)\)} $buffer all s1 s2 s3 p s4] ||
		($s1 != $s2) || ($s1 != $s3) || ($s1 != $s4)
	    } {
		return 0
	    }
	    set ftp(LocalAddr) $ftp(RemoteAddr)
	    set ftp(DataPort) $p
	}
    }

    # establish data connection for passive mode

    set rc [catch {set ftp(DataSock) [socket $ftp(LocalAddr) $ftp(DataPort)]} msg]
    if { $rc != 0 } {
	DisplayMsg $s "$msg" error
	return 0
    }

    InitDataConn $s $ftp(DataSock) $ftp(LocalAddr) $ftp(DataPort)
    return 1
}

proc ::ftp::RequestPort {s} {
    upvar ::ftp::ftp$s ftp
    if {![info exists ftp(IpVersion)]} {
	set ftp(RemoteAddr) [lindex [fconfigure $ftp(CtrlSock) -peername] 0]
	IpVersion $s $ftp(RemoteAddr)
    }
    switch -exact -- $ftp(IpVersion) {
	4 { PutsCtrlSock $s "PASV" }
	6 { PutsCtrlSock $s "EPSV" }
    }
    # Extended Port command as per RFC 2428.
    return
}

proc ::ftp::IpVersion {s addr} {
    upvar ::ftp::ftp$s ftp
    set v [ip::version $addr]
    switch -exact -- $v {
	4 - 6 {
	    set ftp(IpVersion) $v
	}
	default {
	    DisplayMsg "" "Unknown type of IP-address $addr!" error
	    return -code error \
		-errorcode {FTP IP-ADDRESS BAD-VERSION} \
		"Unknown type of IP-address $addr!"
	}
    }
    return $v
}

#############################################################################
#
# OpenControlConn --
#
# Opens a ftp control connection
3152
3153
3154
3155
3156
3157
3158
3159
    set ::ftp::VERBOSE 1
    set ::ftp::DEBUG 0
}

# ==================================================================
# At last, everything is fine, we can provide the package.

package provide ftp [lindex {Revision: 2.4.13} 1]







|
3227
3228
3229
3230
3231
3232
3233
3234
    set ::ftp::VERBOSE 1
    set ::ftp::DEBUG 0
}

# ==================================================================
# At last, everything is fine, we can provide the package.

package provide ftp 2.5

Changes to modules/ftp/pkgIndex.tcl.

1
2
3
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded ftp         2.4.13 [list source [file join $dir ftp.tcl]]
package ifneeded ftp::geturl 0.2.1  [list source [file join $dir ftp_geturl.tcl]]

|

1
2
3
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded ftp         2.5    [list source [file join $dir ftp.tcl]]
package ifneeded ftp::geturl 0.2.1  [list source [file join $dir ftp_geturl.tcl]]