hpupdate.tcl

Go to the documentation of this file.
00001 /* ! /bin/sh*/
00002 /*  -*- tcl -*- \*/
00003 exec tclsh "$0" ${1+"$@"}
00004 
00005 /*   - homepage update program using FTP -*/
00006 /* */
00007 /*    Required:   tcl/tk8.2*/
00008 /* */
00009 /*    Created:    12/96 */
00010 /*    Changed:    7/2000*/
00011 /*    Version:    2.0*/
00012 /* */
00013 /*    Copyright (C) 1998 Steffen Traeger*/
00014 /*  EMAIL:  Steffen.Traeger@t-online.de*/
00015 /*  URL:    http://home.t-online.de/home/Steffen.Traeger*/
00016 /* */
00017 /*    This program is free software; you can redistribute it and/or modify*/
00018 /*    it under the terms of the GNU General Public License as published by*/
00019 /*    the Free Software Foundation; either version 2 of the License, or*/
00020 /*    (at your option) any later version.*/
00021 /* */
00022 /*    This program is distributed in the hope that it will be useful,*/
00023 /*    but WITHOUT ANY WARRANTY; without even the implied warranty of*/
00024 /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the*/
00025 /*    GNU General Public License for more details.*/
00026 /* */
00027 /*    You should have received a copy of the GNU General Public License*/
00028 /*    along with this program; if not, write to the Free Software*/
00029 /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/
00030 /* */
00031 /* */
00032 
00033 /*  load required FTP package library */
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 /*  LED Colors*/
00042  status = (off) "/* 006666"*/
00043  status = (on)  "/* 00ff00"*/
00044  ftp = (Mode) passive
00045 
00046 /*  set palette under X*/
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 /*  main window*/
00062 wm title . "hpupdate 2.0"
00063 wm iconname . hpupdate
00064 wm minsize . 1 1
00065 
00066 /*  Menue*/
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 /* menu .menu.edit -tearoff 0*/
00076 /* .menu add cascade -label "Bearbeiten" -menu .menu.edit -underline 0*/
00077 /* .menu.edit add command -label "Alle Löschen" -underline 0 -state disabled -command {*/
00078 /*  .view.remote.list selection set 0 end; BusyCommand DeleteremoteFiles}*/
00079 /* .menu.edit add command -label "Alle Übertragen" -underline 0 -state disabled -command Quit*/
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 /*  View area*/
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 /*  Status*/
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 /*  Connection status*/
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 /*  Separator*/
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 /*  Dummy*/
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 /*  Remote directory*/
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 /* 0000ff*/
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 /* ff0000*/
00153  pack .view.remote.list -in .view.remote -side left -expand 1 -fill both
00154 
00155 /*  Local directory*/
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 /* 0000ff*/
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 /* 000080*/
00178  pack .view.local.list -in .view.local -side left -expand 1 -fill both
00179 
00180 /*  Shows selected files */
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 /*  Acc. Keys*/
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 /*  Syncron Scrollbars*/
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 /*  messages*/
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 /*  Procedures*/
00238 /* */
00239 /* */
00240 
00241 /*  hourglass*/
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 /*  read recursive the remote directory tree*/
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 /*  read remote directory*/
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 /*  shine a light */
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 /*  connect to ftp server*/
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 /*  Remove connection to file server*/
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 /*  Display connection status*/
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 /*  display used directory size */
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 /*  display selected directory size */
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 /*  read recursive the local directory tree*/
00483 ret  GetLocalTree (type dir) {
00484 global ftp
00485     foreach i [lsort [glob -nocomplain $dir/* $dir/.*]] {
00486         regsub {\./} $i "" i
00487         if { ([file tail $i] != ".") && ([file tail $i] != "..") } {
00488 
00489             # exist check
00490             if {![file exists $i]} {
00491                 continue
00492             }
00493 
00494             if {[file isdirectory $i]} {
00495                 lappend ftp(localFileList) $i
00496                 lappend ftp(localDirList) $i
00497                 GetLocalTree $i
00498             } else {
00499                 lappend ftp(localFileList) $i
00500             }
00501         }
00502     }
00503 }
00504 
00505 /*  read local directory*/
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 /*  delete files on remote site*/
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 /*  Progress bar displayed in status line*/
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 /*  upload local files to remote site*/
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 /*  Refresh*/
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     /*  update timestamp*/
00807     ret  Touch (type filename) {
00808     set file [open $filename w]
00809     puts -nonewline $file ""
00810     close $file
00811     }
00812 }
00813 
00814 
00815 /*  quit hpupdate*/
00816 ret  Quit () {
00817 global ftp
00818     Disconnect
00819     destroy .
00820     exit 0
00821 }
00822 
00823 
00824 /*  save current configuration*/
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 /*  accept new configuraion*/
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 /*  ftp configuration*/
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 /*  Help*/
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://tcl.sf.net/
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://home.t-online.de/home/Steffen.Traeger
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 /*  main ###################################################*/
01148 
01149 /*  determine working directory */
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 /*  init defaults*/
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 /*  load configuration file*/
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 /*  to compare older and newer files hpupdate creates*/
01181 /*  a new timesstamp on file "hpupdate.ts" after every update*/
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 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1