hpupdate.tcl
Go to the documentation of this file.00001
00002
00003 exec tclsh "$0" ${1+"$@"}
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 package require Tcl 8.3
00035 package require ftp 2.0
00036 package require Tk
00037 if {![llength [info commands tkButtonInvoke]]} {
00038 ::tk::unsupported::ExposePrivateCommand tkButtonInvoke
00039 }
00040
00041
00042 status = (off) "
00043 status = (on) "
00044 ftp = (Mode) passive
00045
00046
00047 if { [string range [winfo server .] 0 0] == "X" } {
00048 tk = _strictMotif 1
00049 tk_Palette = LightGray
00050 option add *font {Helvetica 12}
00051 option add *Text.foreground black
00052 option add *Text.background white
00053 option add *Listbox.background white
00054 option add *Listbox.selectForeground white
00055 option add *Entry.background white
00056 option add *Entry.selectBackground black
00057 option add *Entry.selectForeground white
00058 option add *Scrollbar.width 12
00059 }
00060
00061
00062 wm title . "hpupdate 2.0"
00063 wm iconname . hpupdate
00064 wm minsize . 1 1
00065
00066
00067 menu .menu -tearoff 0
00068 menu .menu.file -tearoff 0
00069 .menu add cascade -label "File" -menu .menu.file -underline 0
00070 .menu.file add command -label "Connect" -underline 0 -command {BusyCommand Connect} -accelerator Alt+C
00071 .menu.file add command -label "Disconnect" -underline 1 -state disabled -command {BusyCommand Disconnect} -accelerator Alt+I
00072 .menu.file add separator
00073 .menu.file add command -label "Exit" -underline 0 -command Quit -accelerator Alt+X
00074
00075
00076
00077
00078
00079
00080
00081 menu .menu.view -tearoff 0
00082 .menu add cascade -label "View" -menu .menu.view -underline 0
00083 .menu.view add command -label "Refresh" -underline 0 -command {BusyCommand Refresh} -accelerator Alt+R
00084
00085 menu .menu.options -tearoff 0
00086 .menu add cascade -label "Options" -menu .menu.options -underline 0
00087 .menu.options add command -label "Preferences" -underline 0 -command {BusyCommand Config} -accelerator Alt+P
00088
00089 menu .menu.help -tearoff 0
00090 .menu add cascade -label "Help" -menu .menu.help -underline 0
00091 .menu.help add command -label "Overview" -underline 0 -command {Help overview}
00092 .menu.help add command -label "Installation" -underline 0 -command {Help install}
00093 .menu.help add command -label "Usage" -underline 0 -command {Help usage}
00094 .menu.help add separator
00095 .menu.help add command -label "About" -underline 1 -command {Help about}
00096
00097 . configure -menu .menu
00098
00099
00100 frame .status -bd 1 -relief flat
00101 pack .status -in . -side bottom -fill x
00102 frame .view -bd 1 -relief flat
00103 pack .view -in . -side top -expand 1 -fill both
00104
00105
00106 frame .status.head -bd 1 -relief sunken
00107 pack .status.head -in .status -side top -fill x
00108 label .status.head.label -textvariable status(header) -relief raised -anchor w -bd 1
00109 pack .status.head.label -in .status.head -side left -expand 1 -fill x -ipadx 2 -ipady 2
00110
00111
00112 frame .view.conn -bd 1 -relief flat
00113 pack .view.conn -in .view -side top -fill both -padx 8
00114 frame .view.conn.led1 -bd 2 -relief raised -width 20 -height 10
00115 pack .view.conn.led1 -in .view.conn -side left -fill x -padx 3
00116 label .view.conn.lab1 -text "No Connection!" -relief flat -anchor w -bd 1 -font {Helvetica 8}
00117 pack .view.conn.lab1 -in .view.conn -side left -fill x -padx 3
00118 checkbutton .view.conn.check -text "syncronize scrollbars" -takefocus 0 -variable ftp(SyncScroll) \
00119 -command SyncScroll -relief flat -anchor w -bd 2 -font {Helvetica 12}
00120 pack .view.conn.check -in .view.conn -side right
00121
00122
00123 frame .view.line -bd 1 -height 2 -relief sunken
00124 pack .view.line -in .view -side top -fill x -padx 8 -pady 5
00125
00126
00127 frame .view.dummy -bd 1 -height 5 -relief flat
00128 pack .view.dummy -in .view -side bottom -fill x -padx 8 -pady 5
00129
00130
00131 frame .view.remote -bd 1
00132 pack .view.remote -in .view -side right -expand 1 -fill both -padx 5
00133 frame .view.remote.status -bd 0
00134 pack .view.remote.status -in .view.remote -side top -fill x
00135 label .view.remote.status.label -text "Remote: " -anchor w -relief flat -font {Helvetica 12 italic}
00136 pack .view.remote.status.label -in .view.remote.status -side left
00137 label .view.remote.status.mark -text "" -anchor w -relief flat -font {Helvetica 10}
00138 pack .view.remote.status.mark -in .view.remote.status -side right
00139 label .view.remote.status.use -text "0K" -anchor w -relief flat -fg
00140 pack .view.remote.status.use -in .view.remote.status -side left
00141
00142 frame .view.remote.buttons -bd 1
00143 pack .view.remote.buttons -in .view.remote -side bottom -fill x
00144 button .view.remote.buttons.delete -text "Delete" -under 0 -state disabled -command {BusyCommand DeleteRemoteFiles}
00145 pack .view.remote.buttons.delete -in .view.remote.buttons -side top -pady 1m
00146 scrollbar .view.remote.yscroll -relief sunken -takefocus 0 -command ".view.remote.list yview"
00147 pack .view.remote.yscroll -in .view.remote -side right -fill y
00148 scrollbar .view.remote.xscroll -relief sunken -orient horizontal -takefocus 0 -command ".view.remote.list xview"
00149 pack .view.remote.xscroll -in .view.remote -side bottom -fill x
00150 listbox .view.remote.list -relief sunken -xscroll ".view.remote.xscroll " -yscroll = ".view.remote.yscroll " \
00151 -width = 40 -height 24 -font {Courier 12} \
00152 -exportselection 0 -selectmode multiple -takefocus 0 -selectbackground
00153 pack .view.remote.list -in .view.remote -side left -expand 1 -fill both
00154
00155
00156 frame .view.local -bd 1
00157 pack .view.local -in .view -side left -expand 1 -fill both -padx 5
00158 frame .view.local.status -bd 0
00159 pack .view.local.status -in .view.local -side top -fill x
00160 label .view.local.status.label -text "Local: " -anchor w -relief flat -font {Helvetica 12 italic}
00161 pack .view.local.status.label -in .view.local.status -side left
00162 label .view.local.status.mark -text "" -anchor w -relief flat -font {Helvetica 10}
00163 pack .view.local.status.mark -in .view.local.status -side right
00164 label .view.local.status.use -text "0K" -anchor w -relief flat -fg
00165 pack .view.local.status.use -in .view.local.status -side left
00166
00167 frame .view.local.buttons -bd 1
00168 pack .view.local.buttons -in .view.local -side bottom -fill x
00169 button .view.local.buttons.transfer -text "Up
00170 pack .view.local.buttons.transfer -in .view.local.buttons -side top -pady 1m
00171 scrollbar .view.local.yscroll -relief sunken -takefocus 0 -command ".view.local.list yview"
00172 pack .view.local.yscroll -in .view.local -side right -fill y
00173 scrollbar .view.local.xscroll -relief sunken -orient horizontal -takefocus 0 -command ".view.local.list xview"
00174 pack .view.local.xscroll -in .view.local -side bottom -fill x
00175 listbox .view.local.list -relief sunken -xscroll ".view.local.xscroll " -yscroll = ".view.local.yscroll " \
00176 -width = 40 -height 24 -font {Courier 12} \
00177 -exportselection 0 -selectmode multiple -takefocus 0 -selectbackground
00178 pack .view.local.list -in .view.local -side left -expand 1 -fill both
00179
00180
00181 bindtags .view.local.list {Listbox . all .view.local.list}
00182 bindtags .view.remote.list {Listbox . all .view.remote.list}
00183 bind .view.local.list <ButtonRelease-1> {Showselected local}
00184 bind .view.remote.list <ButtonRelease-1> {Showselected remote}
00185
00186
00187 bind . <Meta-c> {BusyCommand Connect}
00188 bind . <Meta-i> {BusyCommand Disconnect}
00189 bind . <Meta-r> {BusyCommand Refresh}
00190 bind . <Meta-p> {BusyCommand Config}
00191 bind . <Meta-u> "tkButtonInvoke .view.local.buttons.transfer"
00192 bind . <Meta-d> "tkButtonInvoke .view.remote.buttons.delete"
00193 bind . <Meta-x> Quit
00194
00195 ret SyncY (type args) {
00196 eval .view.local.list yview $args
00197 eval .view.remote.list yview $args
00198 }
00199
00200 ret SyncX (type args) {
00201 eval .view.local.list xview $args
00202 eval .view.remote.list xview $args
00203 }
00204
00205
00206 ret SyncScroll () {
00207 global ftp
00208 if { $ftp(SyncScroll) == 1} {
00209 .view.local.yscroll configure -command SyncY
00210 .view.remote.yscroll configure -command SyncY
00211 .view.local.xscroll configure -command SyncX
00212 .view.remote.xscroll configure -command SyncX
00213 } else {
00214 .view.local.yscroll configure -command ".view.local.list yview"
00215 .view.remote.yscroll configure -command ".view.remote.list yview"
00216 .view.local.xscroll configure -command ".view.local.list xview"
00217 .view.remote.xscroll configure -command ".view.remote.list xview"
00218 }
00219 }
00220
00221
00222 ret ftp::DisplayMsg (type s , type msg , optional state =normal) {
00223 global status
00224
00225 switch -- $state {
00226 data {return}
00227 control {return}
00228 normal {.status.head.label configure -fg black}
00229 error {.status.head.label configure -fg red}
00230 }
00231 set status(header) $msg
00232 update idletasks
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242 ret BusyCommand (type args) {
00243 set command $args
00244 set busy {.menu .view .status}
00245 set window_list {.menu .view .status}
00246 while {$window_list != ""} {
00247 set next {}
00248 foreach w $window_list {
00249 set class [winfo class $w]
00250 set cursor [lindex [$w config -cursor] 4]
00251 if {[winfo toplevel $w] == $w || $cursor != ""} {
00252 lappend busy [list $w $cursor]
00253 }
00254 set next [concat $next [winfo children $w]]
00255 }
00256 set window_list $next
00257 }
00258 foreach w $busy {
00259 catch { grab set [lindex $w 0]}
00260 catch {[lindex $w 0] config -cursor watch}
00261 }
00262 update idletasks
00263 set error [catch {uplevel eval [list $command]} g]
00264 foreach w $busy {
00265 catch {grab release [lindex $w 0]}
00266 catch {[lindex $w 0] config -cursor [lindex $w 1]}
00267 }
00268 if { !$error } {
00269 return $g
00270 } else {
00271 bgerror $g
00272 }
00273 return ""
00274 }
00275
00276
00277 ret GetRemoteTree (optional dir ="") {
00278 global ftp
00279
00280 foreach i [ftp::List $ftp(conn) $dir] {
00281 set rc [scan $i "%s %s %s %s %s %s %s %s %s" perm l u g size d1 d2 d3 name]
00282 if {$rc == "9"} {
00283
00284 if { ($name == ".") || ($name == "..") } {
00285 continue
00286 }
00287
00288 set type [string range $perm 0 0]
00289 if { $dir != "" } {
00290 regsub {\./} [file join $dir $name] "" name
00291 }
00292 switch -- $type {
00293 d {
00294 lappend ftp(remoteDirList) $name
00295 lappend ftp(remoteFileList) "$name"
00296 lappend ftp(remoteSizeList) $size
00297 GetRemoteTree $name
00298 }
00299
00300 - {
00301 lappend ftp(remoteFileList) "$name"
00302 lappend ftp(remoteSizeList) $size
00303 }
00304
00305 default {
00306 lappend ftp(remoteFileList) "$name"
00307 lappend ftp(remoteSizeList) $size
00308 }
00309 }
00310 }
00311 }
00312 }
00313
00314
00315 ret ReadRemoteDir () {
00316 global ftp opt
00317
00318 # connected?
00319 if {(![info exists ftp(conn)]) ||
00320 (![info exists ftp::ftp${ftp(conn)}(State)])} {
00321 .view.remote.list delete 0 end
00322 return
00323 }
00324
00325 focus .view.remote.list
00326 .view.remote.list delete 0 end
00327 .view.remote.list insert end "Working..."
00328 update idletasks
00329
00330 set ftp(remoteDirList) {}
00331 set ftp(remoteFileList) {}
00332 set ftp(remoteSizeList) {}
00333 GetRemoteTree .
00334
00335 foreach name $ftp(remoteFileList) {
00336 if { [string length $name] > $ftp(MaxLength) } {
00337 set ftp(MaxLength) [string length $name]
00338 }
00339 }
00340
00341 set max_length $ftp(MaxLength)
00342 .view.remote.list delete 0 end
00343 update idletasks
00344 set index 0
00345 foreach i $ftp(remoteFileList) {
00346
00347 set name $i
00348 set size [lindex $ftp(remoteSizeList) $index ]
00349 set entry [format "%-${max_length}s %8s" $name $size]
00350 .view.remote.list insert end $entry
00351
00352 # If file doesn't exist on local location then mark it to delete
00353 set index [lsearch -regexp [.view.local.list get 0 end] "^$name "]
00354 if { $index == "-1" } {
00355 .view.remote.list selection set end end
00356 }
00357 incr index
00358
00359 }
00360
00361 ShowUsed remote
00362 Showselected remote
00363 ReadLocalDir
00364 }
00365
00366
00367 ret Blink (type mode) {
00368 global status
00369 switch -- $mode {
00370 on {
00371 .view.conn.led1 configure -bg $status(on)
00372 update idletasks
00373 }
00374 off {
00375 .view.conn.led1 configure -bg $status(off)
00376 update idletasks
00377 }
00378 }
00379 }
00380
00381
00382 ret Connect () {
00383 global ftp opt
00384 ftp::DisplayMsg "" " ftp> Trying connect to ftp server..."
00385 Blink on
00386 if {[set ftp(conn) [ftp::Open $opt(Server) $opt(Username) $opt(Password) -progress {ProgressBar update} ]] == -1} {
00387 Blink off
00388 ShowStatus
00389 return
00390 }
00391
00392 # remote homepage directory
00393 if {![ftp::Cd $ftp(conn) $opt(remoteDir)]} {
00394 tk_messageBox -parent . -title INFO -message "Directory $opt(remoteDir) on remote ftp server not found!" -type ok
00395 Disconnect
00396 return
00397 }
00398
00399 ftp::DisplayMsg $ftp(conn) "Connected to ftp service on $opt(Server)!"
00400 ReadRemoteDir
00401 .view.local.buttons.transfer configure -state normal
00402 .view.remote.buttons.delete configure -state normal
00403 .menu.file entryconfigure 0 -state disabled
00404 .menu.file entryconfigure 1 -state normal
00405 ShowStatus
00406 }
00407
00408
00409 ret Disconnect () {
00410 global ftp
00411
00412 # connected?
00413 if {([info exists ftp(conn)]) &&
00414 ([info exists ftp::ftp${ftp(conn)}(State)])} {
00415 ftp::Close $ftp(conn)
00416 ftp::DisplayMsg "" "Connection closed!"
00417 }
00418 if {[info exists ftp(conn)]} {
00419 unset ftp(conn)
00420 }
00421 set ftp(remoteSizeList) {}
00422 .view.remote.list delete 0 end
00423 .view.local.buttons.transfer configure -state disabled
00424 .view.remote.buttons.delete configure -state disabled
00425 .menu.file entryconfigure 0 -state normal
00426 .menu.file entryconfigure 1 -state disabled
00427 ShowStatus
00428 ShowUsed remote
00429 Showselected remote
00430 }
00431
00432
00433 ret ShowStatus () {
00434 global status
00435 if {([info exists ftp(conn)]) &&
00436 ([info exists ftp::ftp${ftp(conn)}(State)])} {
00437 .view.conn.led1 configure -bg $status(on)
00438 .view.conn.lab1 configure -text "connected"
00439 update idletasks
00440 } else {
00441 .view.conn.led1 configure -bg $status(off)
00442 .view.conn.lab1 configure -text "not connected"
00443 update idletasks
00444 }
00445 }
00446
00447
00448 ret ShowUsed (type mode) {
00449 global ftp
00450 set sum 0
00451 foreach i $ftp(${mode}SizeList) {
00452 incr sum $i
00453 }
00454
00455 # if { $sum > [ expr {1024 * 1024}] } {
00456 # set color #ff0000
00457 # } else {
00458 # set color #0000ff
00459 # }
00460
00461 set color #0000ff
00462 .view.$mode.status.use configure -text "[expr {round($sum / 1024.0)}] KB" -fg $color
00463 update idletasks
00464 }
00465
00466
00467 ret Showselected (type mode) {
00468 global ftp
00469 set sum 0
00470 set count 0
00471 if { ([info exists ftp(${mode}SizeList)]) && ([llength $ftp(${mode}SizeList)] != 0) } {
00472 foreach i [.view.$mode.list curselection] {
00473 incr sum [lindex $ftp(${mode}SizeList) $i]
00474 incr count
00475 }
00476 }
00477 .view.$mode.status.mark configure -text "[expr {round($sum / 1024.0)}] KB \[$count\]"
00478 update idletasks
00479 }
00480
00481
00482
00483 ret GetLocalTree (type dir) {
00484 global ftp
00485 foreach i [lsort [glob -nocomplain $dir
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 ret ReadLocalDir () {
00507 global opt ftp
00508
00509 .view.local.list delete 0 end
00510 .view.local.list insert end "Working..."
00511 update
00512
00513 # local homepage directory
00514 if {![file isdirectory $opt(localDir)]} {
00515 tk_messageBox -parent . -title INFO -message "Directory $opt(localDir) not found!" -type ok
00516 return
00517
00518 }
00519
00520 # read local homepage directory
00521 set ftp(localDirList) {}
00522 set ftp(localFileList) {}
00523 set ftp(localSizeList) {}
00524 cd $opt(localDir)
00525 GetLocalTree .
00526
00527 foreach name $ftp(localFileList) {
00528 if { [string length $name] > $ftp(MaxLength) } {
00529 set ftp(MaxLength) [string length $name]
00530 }
00531 }
00532
00533 set max_length $ftp(MaxLength)
00534 .view.local.list delete 0 end
00535 update idletask
00536 foreach i $ftp(localFileList) {
00537
00538 set name $i
00539 set size [file size $name]
00540 set entry [format "%-${max_length}s %8s" $name $size]
00541 .view.local.list insert end $entry
00542 lappend ftp(localSizeList) $size
00543
00544 # if updated then mark to upload
00545 if { [file mtime $name] > $opt(Timestamp) } {
00546 .view.local.list selection set end end
00547 }
00548
00549 # if not exist at remote machine then mark to upload
00550 if {([info exists ftp(conn)]) &&
00551 ([info exists ftp::ftp${ftp(conn)}(State)])} {
00552 set index [lsearch -regexp [.view.remote.list get 0 end] "^$name "]
00553 if { $index == "-1" } {
00554 .view.local.list selection set end end
00555 }
00556 }
00557 }
00558
00559 ShowUsed local
00560 Showselected local
00561 }
00562
00563
00564 ret DeleteRemoteFiles () {
00565 global ftp
00566
00567 # connected?
00568 if {(![info exists ftp(conn)]) ||
00569 (![info exists ftp::ftp${ftp(conn)}(State)])} {
00570 tk_messageBox -parent . -title INFO -message "No connection!" -type ok
00571 return
00572 }
00573 # nothing choosed
00574 if { [.view.remote.list curselection] == {} } {
00575 return
00576 }
00577 # ask user
00578 set count [llength [.view.remote.list curselection]]
00579 set rc [tk_messageBox -parent . -title DELETE -message "Do you really want to delete the $count selected file(s)?" -type yesno]
00580 if { $rc == "no" } {
00581 return
00582 }
00583
00584 # delete selected files
00585 focus .view.remote.list
00586 foreach i [lsort -integer -decreasing [.view.remote.list curselection]] {
00587 set filename [lindex [.view.remote.list get $i] 0]
00588 .view.remote.list see $i
00589 .view.remote.list activate $i
00590 update idletasks
00591
00592 # file or directory?
00593 set index [lsearch -exact $ftp(remoteDirList) $filename]
00594 if { $index == "-1" } {
00595 set command "ftp::Delete"
00596 } else {
00597 set command "ftp::RmDir"
00598 }
00599
00600 if {[eval $command $ftp(conn) $filename]} {
00601 .view.remote.list selection clear $i
00602 update idletasks
00603 set ftp(remoteSizeList) [lreplace $ftp(remoteSizeList) $i $i 0]
00604 ShowUsed remote
00605 Showselected remote
00606 Showselected local
00607 } else {
00608 tk_messageBox -parent . -title ERROR -message \
00609 "Error deleting $filename!" -icon error -type ok
00610 continue
00611 }
00612 }
00613 BusyCommand Refresh
00614 }
00615
00616
00617 ret ProgressBar (type state , optional bytes =0 , optional filename ="") {
00618 global ftp
00619 set w .progress
00620 switch -- $state {
00621 init {
00622 set ftp(Filename) ""
00623 set ftp(ProgressProz) "0%"
00624 toplevel $w -bd 0 -class Progressbar
00625 wm transient $w .
00626 wm title $w Upload
00627 wm iconname $w Upload
00628 wm resizable $w 0 0
00629 focus $w
00630 grab $w
00631
00632 frame $w.buttons
00633 pack $w.buttons -side bottom -fill x -pady 2m
00634 button $w.buttons.esc -text "Cancel" -command "set ftp(escaped) 1"
00635 pack $w.buttons.esc -in $w.buttons -side top
00636
00637 frame $w.frame -bd 4
00638 pack $w.frame -side top -fill both
00639 label $w.frame.label -textvariable ftp(Filename) -relief flat -anchor w -bd 1 -font {Helvetica 12}
00640 pack $w.frame.label -in $w.frame -side top -fill x -padx 10 -pady 5
00641 frame $w.frame.line -bd 1 -height 2 -relief sunken
00642 pack $w.frame.line -in $w.frame -side bottom -fill x -padx 2 -pady 5
00643 frame $w.frame.bar -bd 1 -relief sunken -bg #ffffff
00644 pack $w.frame.bar -in $w.frame -side left -padx 10 -pady 5
00645 frame $w.frame.bar.dummy -bd 0 -width 200 -height 0
00646 pack $w.frame.bar.dummy -in $w.frame.bar -side top -fill x
00647 frame $w.frame.bar.pbar -bd 0 -width 0 -height 20
00648 pack $w.frame.bar.pbar -in $w.frame.bar -side left
00649 label $w.frame.proz -textvariable ftp(ProgressProz) -width 5 -relief flat -anchor e -bd 1 -font {Helvetica 12}
00650 pack $w.frame.proz -in $w.frame -side right -padx 10 -pady 5
00651
00652 wm withdraw $w
00653 update idletasks
00654 set x [expr {[winfo x .] + ([winfo width .] / 3) - ([winfo reqwidth $w] / 2)}]
00655 set y [expr {[winfo y .] + ([winfo height .] / 3) - ([winfo reqheight $w] / 2)}]
00656 wm geometry $w +$x+$y
00657 wm deiconify $w
00658 update idletasks
00659 }
00660
00661 reset {
00662 set ftp(Filename) "Uploading $filename...."
00663 set index [lsearch $ftp(localFileList) $filename]
00664 if { $index != "-1" } {
00665 set ftp(progress_sum) [lindex $ftp(localSizeList) $index]
00666 if { $ftp(progress_sum) == 0 } {
00667 set ftp(progress_sum) 1
00668 }
00669 } else {
00670 set ftp(progress_sum) 1
00671 }
00672 ProgressBar update
00673 update idletasks
00674 }
00675
00676 update {
00677 if {![winfo exists $w]} {return}
00678 set ftp(ProgressProz) "[expr {round( $bytes * 100 / $ftp(progress_sum))}]%"
00679 set cur_width [expr {round($bytes * 200 / $ftp(progress_sum))}]
00680 $w.frame.bar.pbar configure -width $cur_width -bg #000080
00681 focus $w.buttons.esc
00682 update idletasks
00683 update
00684 }
00685
00686 done {
00687 set ftp(Filename) "Upload successful!"
00688 $w.buttons.esc configure -text "OK" -command "destroy $w"
00689 update idletasks
00690 tkwait window $w
00691 }
00692
00693 escape {
00694 destroy $w
00695 BusyCommand Refresh
00696 }
00697
00698 error {
00699 destroy $w
00700 }
00701 }
00702 }
00703
00704
00705 ret UpdateRemoteFiles () {
00706 global ftp opt status
00707 # connected?
00708 if {(![info exists ftp(conn)]) ||
00709 (![info exists ftp::ftp${ftp(conn)}(State)]) } {
00710 tk_messageBox -parent . -title INFO -message "No connection!" -type ok
00711 return 0
00712 }
00713
00714 # nothing selected
00715 if { [.view.local.list curselection] == {} } {
00716 return 0
00717 }
00718
00719 # ask user
00720 set count [llength [.view.local.list curselection]]
00721 set rc [tk_messageBox -parent . -title UPLOAD -message "Do you really want to upload the $count selected file(s)?" -type yesno]
00722 if { $rc == "no" } {
00723 return 0
00724 }
00725
00726 # create list of uploading files
00727 set upload_list {}
00728 foreach i [.view.local.list curselection] {
00729 lappend upload_list $i
00730 }
00731
00732 # empty list?
00733 if { $upload_list == {} } {
00734 tk_messageBox -parent . -title INFO -type ok -message "Nothing selected for upload!!"
00735 return 0
00736 }
00737 focus .view.local.list
00738
00739 # binary type for all files
00740 ftp::Type $ftp(conn) binary
00741
00742 # upload files
00743 set ftp(escaped) 0
00744 ProgressBar init
00745 set ftp(ProgressCount) 0
00746 foreach i $upload_list {
00747 set filename [lindex [.view.local.list get $i] 0]
00748 .view.local.list see $i
00749 .view.local.list activate $i
00750 update idletasks
00751
00752 # file or directory?
00753 set index [lsearch -exact $ftp(localDirList) $filename]
00754 if { $index == "-1" } {
00755 set command "ftp::Put"
00756 } else {
00757
00758 # directory already exists
00759 if { [lsearch -exact $ftp(remoteDirList) $filename] != "-1" } {
00760 continue
00761 }
00762 set command "ftp::MkDir"
00763 }
00764
00765 ProgressBar reset 0 $filename
00766 if {[eval $command $ftp(conn) $filename]} {
00767 incr ftp(ProgressCount)
00768 if {$ftp(escaped)} {
00769 ProgressBar escape
00770 return 1
00771 }
00772 .view.local.list selection clear $i
00773 } else {
00774 tk_messageBox -parent . -title ERROR -message "Error uploading $filename!" -icon error -type ok
00775 ProgressBar error
00776 continue
00777 }
00778 }
00779
00780 ProgressBar done
00781
00782 # new timestamp
00783 Touch $opt(TsFile)
00784 set opt(Timestamp) [file mtime $opt(TsFile)]
00785 Refresh
00786 set status(header) " last update: [clock format $opt(Timestamp) -format %d.%m.%Y\ %H:%M:%S\ Uhr -gmt 0]"
00787 return 0
00788 }
00789
00790
00791 ret Refresh () {
00792 global ftp
00793 set ftp(MaxLength) 0
00794 ReadLocalDir
00795 ReadRemoteDir
00796 ShowStatus
00797 update idletasks
00798 }
00799
00800
00801 if {[package vcompare [info tclversion] 8.4] >= 0} {
00802 ret Touch (type filename) {
00803 file mtime $filename [clock seconds]
00804 }
00805 } else {
00806
00807 ret Touch (type filename) {
00808 set file [open $filename w]
00809 puts -nonewline $file ""
00810 close $file
00811 }
00812 }
00813
00814
00815
00816 ret Quit () {
00817 global ftp
00818 Disconnect
00819 destroy .
00820 exit 0
00821 }
00822
00823
00824
00825 ret SaveConfig () {
00826 global opt
00827 set file [open $opt(ConfigFile) w]
00828 puts $file [array get opt]
00829 close $file
00830 }
00831
00832
00833 ret AcceptConfig (type w) {
00834 global opt ftp
00835
00836 # get ftp server options
00837 set opt(Server) [$w.mask.server.entry get]
00838 set opt(Username) [$w.mask.user.entry get]
00839 set opt(Password) [$w.mask.passwd.entry get]
00840 set opt(remoteDir) [$w.mask.remote.entry get]
00841
00842 # get local homepage direction
00843 set dir [$w.mask.local.entry get]
00844 if { ![file isdirectory $dir] } {
00845 tk_messageBox -parent . -title ERROR -message "Directory \"$dir\" not found!" -type ok
00846 return
00847 }
00848 set opt(localDir) [$w.mask.local.entry get]
00849 cd $opt(localDir)
00850
00851 SaveConfig
00852 tk_messageBox -parent . -title INFO -message "Configuration applied and saved!" -type ok
00853 destroy $w
00854 }
00855
00856
00857 ret Config () {
00858 global opt
00859
00860 # new window
00861 set w .config
00862
00863 catch {destroy $w}
00864 toplevel $w -bd 0 -class Config
00865 wm transient $w .
00866 wm title $w "options"
00867 wm iconname $w "options"
00868 wm transient $w .
00869 wm minsize $w 10 10
00870
00871 frame $w.mask -bd 1 -relief raised
00872 pack $w.mask -in $w -side top -expand 1 -fill both
00873 frame $w.control -bd 1 -relief raised
00874 pack $w.control -in $w -side bottom -fill x
00875
00876 frame $w.mask.server -bd 1
00877 pack $w.mask.server -in $w.mask -side top -expand 1 -fill both -padx 3m -pady 3m
00878 label $w.mask.server.label -text "ftp server name:" -under 0 -anchor w
00879 pack $w.mask.server.label -in $w.mask.server -side top -fill x
00880 entry $w.mask.server.entry -width 40
00881 pack $w.mask.server.entry -in $w.mask.server -expand 1 -side left -fill x
00882
00883 frame $w.mask.user -bd 1
00884 pack $w.mask.user -in $w.mask -side top -expand 1 -fill both -padx 3m -pady 3m
00885 label $w.mask.user.label -text "User:" -under 0 -anchor w
00886 pack $w.mask.user.label -in $w.mask.user -side top -fill x
00887 entry $w.mask.user.entry -width 40
00888 pack $w.mask.user.entry -in $w.mask.user -expand 1 -side left -fill x
00889
00890 frame $w.mask.passwd -bd 1
00891 pack $w.mask.passwd -in $w.mask -side top -expand 1 -fill both -padx 3m -pady 3m
00892 label $w.mask.passwd.label -text "Password:" -under 0 -anchor w
00893 pack $w.mask.passwd.label -in $w.mask.passwd -side top -fill x
00894 entry $w.mask.passwd.entry -show "*" -width 40
00895 pack $w.mask.passwd.entry -in $w.mask.passwd -expand 1 -side left -fill x
00896
00897 frame $w.mask.remote -bd 1
00898 pack $w.mask.remote -in $w.mask -side top -expand 1 -fill both -padx 3m -pady 3m
00899 label $w.mask.remote.label -text "Remote directory:" -under 0 -anchor w
00900 pack $w.mask.remote.label -in $w.mask.remote -side top -fill x
00901 entry $w.mask.remote.entry -width 40
00902 pack $w.mask.remote.entry -in $w.mask.remote -expand 1 -side left -fill x
00903
00904 frame $w.mask.local -bd 1
00905 pack $w.mask.local -in $w.mask -side top -expand 1 -fill both -padx 3m -pady 3m
00906 label $w.mask.local.label -text "Local directory:" -under 0 -anchor w
00907 pack $w.mask.local.label -in $w.mask.local -side top -fill x
00908 entry $w.mask.local.entry -width 40
00909 pack $w.mask.local.entry -in $w.mask.local -expand 1 -side left -fill x
00910
00911 button $w.control.accept -width 14 -text "Apply & Save" -under 0 -command "AcceptConfig $w"
00912 pack $w.control.accept -in $w.control -side left -expand 1 -padx 3m -pady 2m
00913 button $w.control.quit -width 14 -text "Cancel" -under 0 -command "destroy $w"
00914 pack $w.control.quit -in $w.control -side left -expand 1 -padx 3m -pady 2m
00915
00916
00917 # arrange window
00918 wm withdraw $w
00919 update idletasks
00920 set x [expr {[winfo x .] + ([winfo width .] / 3) - ([winfo reqwidth $w] / 2)}]
00921 set y [expr {[winfo y .] + ([winfo height .] / 3) - ([winfo reqheight $w] / 2)}]
00922 wm geometry $w +$x+$y
00923 wm deiconify $w
00924
00925 $w.mask.server.entry delete 0 end
00926 $w.mask.server.entry insert 0 $opt(Server)
00927 $w.mask.user.entry delete 0 end
00928 $w.mask.user.entry insert 0 $opt(Username)
00929 $w.mask.passwd.entry delete 0 end
00930 $w.mask.passwd.entry insert 0 $opt(Password)
00931 $w.mask.local.entry delete 0 end
00932 $w.mask.local.entry insert 0 $opt(localDir)
00933 $w.mask.remote.entry delete 0 end
00934 $w.mask.remote.entry insert 0 $opt(remoteDir)
00935
00936 bind $w <Meta-d> "tkButtonInvoke $w.mask.check.debug"
00937 bind $w <Meta-v> "tkButtonInvoke $w.mask.check.verbose"
00938 bind $w <Meta-f> "focus $w.mask.server.entry"
00939 bind $w <Meta-r> "focus $w.mask.remote.entry"
00940 bind $w <Meta-l> "focus $w.mask.local.entry"
00941 bind $w <Meta-s> "tkButtonInvoke $w.control.accept"
00942 bind $w <Meta-c> "tkButtonInvoke $w.control.cancel"
00943
00944 focus -force $w.mask.server.entry
00945 update idletasks
00946 }
00947
00948 ret Usage () {
00949 puts "\nusage hpupdate \[-h\] \[directory\]"
00950 puts " -h help"
00951 puts " directory local directory"
00952 puts " (default: current directory)\n"
00953 exit 0
00954 }
00955
00956
00957 ret Help (type mode) {
00958
00959 set help(overview) {
00960 OVERVIEW
00961 ---------
00962
00963 In order to simplify the transfer of the files of my homepage to the
00964 FTP server of my Internet Service Provider, I looked at the end of
00965 1996 for an useful tool. Linux offered only the
00966 abilities of the ftp command line utility. As fan of
00967 Tcl/Tk, my selection immediately fell on "expect", which was very suitable
00968 to automate interactive processes like FTP sessions. A little bit
00969 more Tcl source code and hpupdate 0.1 was finished, a script for
00970 automatic updating of my homepage files.
00971
00972 At the beginning of 1997, I was more intensively occupied with the
00973 FTP protocol. At the same time I played with Tcl's socket command.
00974 Thus the FTP library package for Tcl7.6 was developed.
00975 This forms the basis for hpupdate.
00976
00977 So far, the program runs under Linux with Tcl/Tk 8.0. I have once
00978 tested it on Windows 3.11 (with Win32s) and Windows 95 and it runs
00979 perfectly. Today I have no experiences with Windows NT and
00980 Macintosh. Perhaps somebody will be found who will test it in these
00981 environments. I would like to be informed of your experiences!
00982 Thank you!
00983
00984 usage: hpupdate <directoy>
00985
00986 example: hpupdate /home/user/hp
00987
00988 ***
00989 }
00990
00991 set help(install) {
00992 INSTALLATION
00993 ------------
00994
00995 The great advantage of hpupdate is its platform independence
00996 because of using Tcl/Tk.
00997
00998 If you do not have Tcl/Tk 8.0 installed already, at first you must
00999 install it. Get it from the known locations such as http:
01000 and follow the installation instructions.
01001
01002 If you have not already installed the ftp library package, you must
01003 install it. Get it from my homepage and follow the
01004 installation instructions.
01005
01006 Start up hpupdate and change the preferred options in option menu.
01007
01008 "ftp Server Name" - remote FTP server hostname
01009 "User" - valid username
01010 "Password" - valid password for user
01011 "Remote Directory" - remote root for homepage or empty (destination)
01012 "Local Directory" - local homepage directory (source)
01013
01014
01015 ***
01016 }
01017
01018 set help(usage) {
01019 USAGE
01020 -----
01021
01022 The hpupdate application is divided into 4 areas:
01023
01024 1.) menu
01025 2.) local file list (source)
01026 3.) remote file list (destination)
01027 4.) status line
01028
01029 1.) menu
01030
01031 File / Connect
01032 Opens a connection with the FTP server.
01033
01034 File / Disconnetc
01035 Closes an existing connection with the FTP server.
01036
01037 File / Exit
01038 Quits hpupdate, the connection to the FTP server will be
01039 closed automatically.
01040
01041 View / Refresh
01042 Reads new file data and refreshs it in the list.
01043
01044 Options / Preferences
01045 Interface to saving your login, password, ftp server, etc.
01046
01047 Help / * look there
01048
01049 2.) local file list
01050 This list contains the file names and sizes from the local
01051 homepage directory. The file name, date and time-of-day
01052 of the files are compared with the time stamp of the remote files.
01053 When getting the filename for this list, the date/time entry of each file
01054 is read and compared with the timestamp of the last update.
01055 Files which have a date and/or time newer than the remote file's timestamp
01056 are detected as updated and marked for upload.
01057 It is also possible to mark/unmark the files manually per mouse click.
01058 The capacity of all files in the directory is displayed in blue.
01059 Besides this, the capacity of the marked files, as well as the count of files
01060 (in parentheses) are shown.
01061
01062 By pressing the button "Upload", all selected files in the local
01063 homepage directory will be transfered to the remote FTP server.
01064
01065 3.) remote file list
01066 The files at the FTP site appear in this list after connection with
01067 the FTP server. The remote files will be compared with the local files.
01068 Files which are not in the local list are detected as superfluous
01069 and marked for deletion.
01070 It is also possible to mark/unmark files manually per mouse click.
01071 The number of marked files is displayed in an extra frame.
01072 Additionally, the summary disk space is shown.
01073 The capacity of all files in the directory is displayed in blue.
01074 Besides this, the capacity of all marked files as well as the count
01075 (in parentheses) is shown.
01076
01077 By pressing the button "Delete", all selected files in the remote homepage
01078 directory will be deleted.
01079
01080 NOTE: Synchronize the scrolling of both lists by pressing the checkbutton
01081 "sychronize scrollbars ".
01082
01083 4.) status line
01084 The status line shows when the last update of the remote system has taken place.
01085 This display is always updated after every file transfer.
01086 Internally, the file "hpupdate.ts" is provided with a new timestamp.
01087 After this moment, all modified local files are automatically detected
01088 with the next refresh and marked for upload.
01089
01090 Error and status messages for the FTP connection are also displayed in
01091 the status line.
01092
01093 EXTENSION:
01094 The green LED shows the connection status, a lighter green means an
01095 established connection.
01096
01097 ***
01098 }
01099
01100 set help(about) {
01101 - hpupdate
01102 homepage update program using FTP
01103
01104 Required: Tcl/Tk8.0x
01105
01106 Created: 12/96
01107 Changed: 04/2002
01108 Version: 2.1
01109
01110 Copyright (C) 1997,1998, Steffen Traeger
01111 EMAIL: Steffen.Traeger@t-online.de
01112 URL: http:
01113 }
01114
01115 set w .help
01116 catch {destroy $w}
01117 toplevel $w -bd 0 -class Help
01118 wm transient $w .
01119 wm title $w "Help - $mode"
01120 wm iconname $w Hilfe
01121 wm minsize $w 10 10
01122 frame $w.buttons -bd 1 -relief flat
01123 pack $w.buttons -side bottom -fill x -pady 2m
01124 button $w.buttons.close -text "OK" -command "destroy $w"
01125 pack $w.buttons.close -side left -expand 1
01126 frame $w.ftp -bd 1 -relief flat
01127 pack $w.ftp -side top -expand 1 -fill both
01128 scrollbar $w.ftp.yscroll -command "$w.ftp.text yview"
01129 pack $w.ftp.yscroll -in $w.ftp -side right -fill y
01130 scrollbar $w.ftp.xscroll -relief sunken -orient horizontal -command "$w.ftp.text xview"
01131 pack $w.ftp.xscroll -in $w.ftp -side bottom -fill x
01132 text $w.ftp.text -relief sunken -setgrid 1 -wrap none -height 15 -width 60 -bg white -fg black\
01133 -state normal -xscrollcommand "$w.ftp.xscroll set" \
01134 -yscrollcommand "$w.ftp.yscroll set"
01135 pack $w.ftp.text -in $w.ftp -side left -expand 1 -fill both
01136 wm withdraw $w
01137 update idletasks
01138 set x [expr {[winfo x .] + ([winfo width .] / 3) - ([winfo reqwidth $w] / 2)}]
01139 set y [expr {[winfo y .] + ([winfo height .] / 3) - ([winfo reqheight $w] / 2)}]
01140 wm geometry $w +$x+$y
01141 wm deiconify $w
01142 $w.ftp.text insert 0.0 $help($mode)
01143 $w.ftp.text configure -state disabled
01144 update idletasks
01145
01146 }
01147
01148
01149
01150 if { $argv != "" && $argv != "{}" } {
01151 if { [lindex $argv 0] == "-h" } {Usage}
01152 dir = [lindex $argv 0]
01153 if { [file exists $dir] && [file isdirectory $dir] } {
01154 opt = (localDir) $dir
01155 } else {
01156 puts "Directory \"$dir\" not found!"
01157 Usage
01158 }
01159 } else {
01160 opt = (localDir) [pwd]
01161 }
01162
01163
01164 opt = (Server) ""
01165 opt = (Username) "anonymous"
01166 opt = (Password) ""
01167 opt = (remoteDir) "."
01168 opt = (ConfigFile) $env(HOME)/hpupdate.cnf
01169 opt = (TsFile) $env(HOME)/hpupdate.ts
01170
01171
01172 if { [file exists $opt(ConfigFile)] } {
01173 file = [open $opt(ConfigFile) r]
01174 array opt = [read $file]
01175 close $file
01176 }
01177 ftp = ::DEBUG 0
01178 ftp = ::VERBOSE 0
01179
01180
01181
01182 if { ![file exists $opt(TsFile)] } {Touch $opt(TsFile)}
01183 opt = (Timestamp) [file mtime $opt(TsFile)]
01184 status = (header) " last update: [clock format $opt(Timestamp) -format %d.%m.%Y\ %H:%M:%S\ Uhr -gmt 0]"
01185
01186 BusyCommand Refresh
01187
01188