#!/bin/sh
# Executing wish #\
exec wish "$0" "$@"

#######################################################################
#
# SecPanel - Graphical user interface for managing ssh-connections
#
# Copyright (C) 2000 Steffen Leich <leich@wiwi.uni-marburg.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#######################################################################

#######################################################################
#
# This is version Beta 0.2 of SecPanel
#
# If you want to give any feedback about the program please send it to
# Steffen Leich <leich@wiwi.uni-marburg.de>
# Information about the program can be found on
# http://www2.wiwi.uni-marburg.de/~leich/soft/secpanel
#
#######################################################################

# The dir for the libs and helper-apps
set libdir "[file dirname [info script]]/../lib/secpanel"

global agentforward; 
global algo; 
global che28; 
global che46; 
global compress; 
global compressval; 
global fork; 
global gateway; 
global nopriv; 
global quiet; 
global sites; 
global verbose; 
global widget;
global x11forward; 

#################################
# USER DEFINED PROCEDURES
#
proc init {argc argv} {
    global env sites configs
    set secpaneldir "$env(HOME)/.secpanel"
    if {! [file exists $secpaneldir]} {
	puts "Creating my config-dir $secpaneldir (chmod 700)..."
	file mkdir $secpaneldir
	exec chmod 700 $secpaneldir
    }

    if {! [file exists "$secpaneldir/default.profile"]} {
	puts "Creating my default-profile $secpaneldir/default.profile ..."
	set dpf [open "$secpaneldir/default.profile" w]
	puts $dpf " #\n # SecPanel-Pofile\n # Do not edit, use SecPanel instead\n #\n set title \"Default Profile\"\n set host \"\"\n set user \"\"\n set port \"22\"\n set command \"\"\n set identity \"\"\n set agentforward \"0\"\n set x11forward \"0\"\n set nopriv \"0\"\n set verbose \"0\"\n set quiet \"0\"\n set fork \"0\"\n set gateway \"0\"\n set compress \"0\"\n set algo \"idea\"\n set compressval \"6\"\n set lfs \"\""
	close $dpf
    }

    set sitefile "$env(HOME)/.secpanel/sites"
    if [file exists $sitefile] {
	set sf [open $sitefile r]
	while {[gets $sf line] > 0} {
	    set els [split $line #]
	    set sites([lindex $els 0]) "[lindex $els 1]#[lindex $els 2]"
	}
	close $sf
    }
    
    set configfile "$env(HOME)/.secpanel/config"
    if [file exists $configfile] {
	source $configfile
	if {! [array exists configs]} {
	    set configs(sshbin) ssh1
	    set configs(xtermbin) xterm
	}
    } else {
	set configs(sshbin) ssh1
	set configs(xtermbin) xterm
    }
    
}

init $argc $argv

# Saving the global settings
proc save_globals {} {
    global widget env configs
    set conffile [open "$env(HOME)/.secpanel/config" w]
    foreach f {xterm ssh} {
	if {[$widget([set f]ent) get] != ""} {
	    puts $conffile "set configs([set f]bin) [$widget([set f]ent) get]"
	    set configs([set f]bin) [$widget([set f]ent) get]
	    $widget([set f]ent) delete 0 end
	} else {
	    puts $conffile "set configs([set f]bin) $configs([set f]bin)"
	}
    }
    close $conffile
}

proc updateDistLabel {} {
    .top17.fra35.fra17.lab39 config -text \
	    "Dist. to [.top17.fra35.fra17.cpd29.01 get active] as\
	    [.top17.fra35.fra17.fra17.01 get active]"
}

# inserting the binaries locations
proc browseprog {mode} {
    global widget
    choosefile $widget([set mode]ent) /usr
}

# bernahme der Forward-Eintrge aus den Eingabefeldern in die Liste
proc {add_forw} {} {
    global widget
    set lfin [$widget(lfin) get]
    set lfout [$widget(lfout) get]

    if {$lfin != "" && $lfout != ""} {
	$widget(lforwards) insert end "$lfin -> $lfout"
	$widget(lfin) delete 0 end
	$widget(lfout) delete 0 end
	focus $widget(lfin)
    }
}

# Umswitchen zwischen Panels im Hauptfenster
proc changetab {mode} {
    foreach f {21 35 44 46} {
	if {[grid info .top17.fra[set f]] != ""} {
	    grid remove .top17.fra[set f]
	}
    }
    array set frames {connect 46 terminal 44 key 35 ssh 21 scp 18}
    
    grid .top17.fra$frames($mode) -in .top17 \
	    -column 0 -row 1 -columnspan 1 -rowspan 1 \
	    -ipadx 2 -ipady 2 -padx 2 -pady 2 -sticky nesw
}

# Allgemeine Aufnahme aus tk_getOpenFile-Dialog in einen Entry
proc choosefile {entry startdir} {
    $entry delete 0 end
    $entry insert 0 [tk_getOpenFile -initialdir $startdir]
}

# Update of the Lists for distributing keys
proc clear_distmenu {} {
    global env widget sites

    $widget(keydisthost) delete 0 end
    $widget(keydistuser) delete 0 end

    set disthosts [list]
    set distusers [list]

    foreach s [array names sites] {
	set he [lindex [split $sites($s) '#'] 0]
	set ue [lindex [split $sites($s) '#'] 1]
	set hfound 0
	set ufound 0

	foreach hd $disthosts {
	    if {$he == $hd} {
		set hfound 1
		break
	    }
	}
	if {$hfound != 1} {
	    lappend disthosts $he
	}

	foreach ud $distusers {
	    if {$ue == $ud} {
		set ufound 1
		break
	    }
	}
	if {$ufound != 1} {
	    lappend distusers $ue
	}
    }

    set profiles [glob -nocomplain "$env(HOME)/.secpanel/*.profile"]
    foreach prof $profiles {
	if {[file rootname [file tail $prof]] == "default"} {
	    continue
	}
	source $prof

	set he $host
	set ue $user
	set hfound 0
	set ufound 0

	foreach hd $disthosts {
	    if {$he == $hd} {
		set hfound 1
		break
	    }
	}
	if {$hfound != 1} {
	    lappend disthosts $he
	}

	foreach ud $distusers {
	    if {$ue == $ud} {
		set ufound 1
		break
	    }
	}
	if {$ufound != 1} {
	    lappend distusers $ue
	}
    }

    foreach hent $disthosts {
	$widget(keydisthost) insert end $hent
    }
    foreach uent $distusers {
	$widget(keydistuser) insert end $uent
    }
}

proc {clear_prmenu} {} {
    global env widget
    $widget(profiles) delete 0 end
    foreach prof [glob -nocomplain "$env(HOME)/.secpanel/*.profile"] {
	$widget(profiles) insert end "[file rootname [file tail $prof]]"
    }
}

proc {clear_profiles} {} {
    global env widget agentforward x11forward nopriv lfs verbose quiet fork gateway compress algo compressval

    foreach b {agentforward x11forward nopriv  verbose quiet fork gateway compress} {
	set [set b] 0
    }
    
    set algo "idea"
    set compressval 6

    foreach e {host command title identity user port profile} {
	$widget([set e]ent) delete 0 end
    }
    
    if [info exists lfs] {
	unset lfs
    }

    $widget(userent) insert 0 "$env(USER)"
    $widget(portent) insert 0 "22"

    if {[winfo exists .top43]} {
	Window destroy .top43
	local_forwardings 1
    }
}

# Connection
proc connect {mode} {
    global widget sites env configs libdir

    if {$mode == "def"} {
	if {[$widget(defsites) index end] > 0} {
	    source "$env(HOME)/.secpanel/default.profile"
	    set actconn [$widget(defsites) get active]
	    set host [lindex [split $sites($actconn) #] 0]
	    set user [lindex [split $sites($actconn) #] 1]
	    set title $actconn
	} else {
	    showmessage "No conncections available, please use \"New\""
	    return
	}
    }

    if {$mode == "spec"} {
	if {[$widget(specsites) index end] > 0} {
	    set actconn [retprof [$widget(specsites) get active]]
	    source "$env(HOME)/.secpanel/$actconn.profile"
	} else {
	    showmessage "No conncections available, please use \"New\""
	    return
	}
    }

    if {$lfs != ""} {
	foreach lf $lfs {
	    append lf_tag  " -L [lindex [split $lf :] 0]:$host:[lindex [split $lf :] 1] "
	}
    } else {
	set lf_tag " "
    }

    if {$user != ""} {
	set user_tag "-l $user "
    } else {
	set user_tag " "
    }
    
    if {$port == 22 || $port == ""} {
	set port_tag " "
    } else {
	set port_tag "-p $port "
    }
    
    if {$algo != "idea" || $algo == ""} {
	set algo_tag "-c $algo "
    } else {
	set algo_tag " "
    }
    
    if {$identity != ""} {
	set ident_tag "-i $identity "
    } else {
	set ident_tag " "
    }
    
    if {$command != ""} {
	set command_tag "$command"
    } else {
	set command_tag ""
    }
    
    if $compress {
	set compressval_tag "-o CompressionLevel=$compressval "
    } else {
	set compressval_tag " "
    }
    
    array set bools {
	"agentforward" "-a"  "x11forward" "-x"   "nopriv" "-P"  "verbose" "-v"    "quiet" "-q"  "fork" "-f"  "gateway" "-g"  "compress" "-C"
    }
    
    foreach f {agentforward x11forward nopriv verbose  quiet fork gateway compress } {
	if [set $f] {
	    set [set f]_tag "$bools($f) "
	} else {
	    set [set f]_tag " "
	}
    }

    set actstring "exec $configs(xtermbin) -T \"SSH Connection - $title\" \
	    -e $libdir/secpanel.wait \"ssh1 $user_tag \
	    $agentforward_tag $x11forward_tag $algo_tag \
	    $ident_tag $nopriv_tag $verbose_tag $quiet_tag \
	    $fork_tag $gateway_tag $compress_tag $compressval_tag \
	    $lf_tag $host $command_tag\" &"
    
    eval $actstring
}

proc {defsiteupdate} {} {
    global widget sites
    $widget(defsites) delete 0 end
    foreach s [array names sites] {
	$widget(defsites) insert end $s
    }
}

proc {del_forw} {} {
    global widget
    if {[selection own] == $widget(lforwards)} {
	$widget(lforwards) delete active
    } else {
	showmessage "No local forward selected"
    }
    selection clear
}

proc {delconn} {mode} {
global widget env sites
    switch -exact $mode {
	def {
	    if {[selection own] == $widget(defsites)} {
		unset sites([$widget(defsites) get active])	    
		set sitefile [open "$env(HOME)/.secpanel/sites" w]
		foreach s [array names sites] {
		    puts $sitefile "$s#$sites($s)"
		}
		close $sitefile
		defsiteupdate
		clear_distmenu
		selection clear
	    } else {
		showmessage "No entry selected"
	    }
	}
	spec {
	    if {[selection own] == $widget(specsites)} {
		set delprof [retprof [$widget(specsites) get active]]
		if {$delprof == "default"} {
		    showmessage "You may not delete the default profile"
		    return
		} else {
		    file delete "$env(HOME)/.secpanel/$delprof.profile"
		    specsiteupdate
		    clear_prmenu
		    clear_distmenu
		    selection clear
		}    
	    } else {
		showmessage "No entry selected"
	    }
	}
    }
}

proc {delete_profile} {} {
global env widget
    set act [$widget(profileent) get]
    if {$act == ""} {
	showmessage "To delete a profile first load it"
	return
    }
    if {$act == "default"} {
	showmessage "You may not delete the default profile"
	return
    }
    file delete "$env(HOME)/.secpanel/$act.profile"
    clear_prmenu
    clear_profiles
    specsiteupdate
    clear_distmenu
}

# Distribute public-keys to remote hosts
proc distkey {} {
    global env widget libdir

    set user [$widget(keydistuser) get active]

    if {$user == ""} {
	set user $env(USER)
    }

    set host [$widget(keydisthost) get active]
    set identfile [$widget(keydistkey) get]

    if {$identfile == ""} {
	showmessage "No key for distribution selected"
	return
    }
    
    exec xterm -title "SecPanel Key-Distribution" \
	    -e $libdir/secpanel.dist $host $user $identfile &
}

proc {hostkey} {mode} {
    global env widget
    set khfile "$env(HOME)/.ssh/known_hosts"
    switch -exact $mode {
	edit {
	    if [file exists $khfile] {
		Window show .top50
		$widget(knownhosts) delete 0 end
		set hosts [open $khfile r]
		while {[gets $hosts line] > 0} {
		    $widget(knownhosts) insert end [lindex [split $line] 0]
		}
		close $hosts
		return
	    } else {
		showmessage "No $khfile found"
		return
	    }
	}
	view {
	    set actk [$widget(knownhosts) get active]
	    if [file exists $khfile] {
		Window show .top19
		set hosts [open $khfile r]
		while {[gets $hosts line] > 0} {
		    set kparts [split $line]
		    if {[lindex $kparts 0] == $actk} {
			$widget(viewkey) delete 1.0 end
			$widget(viewkey) insert end "[lindex $kparts 1] [lindex $kparts 2] [lindex $kparts 3]"
			break
		    }
		}
		close $hosts
		return
	    }
	}
	delete {
	    if {[selection own] != $widget(knownhosts)} {
		showmessage "No key selected!"
		return
	    }
	    set actk [$widget(knownhosts) get active]
	    if [file exists $khfile] {
		set hosts [open $khfile r]
		# read lines
		while {[gets $hosts line] > 0} {
		    lappend klines $line
		}
		close $hosts

		# write lines
		set hosts [open $khfile w]
		foreach line $klines {
		    set kparts [split $line]
		    if {[lindex $kparts 0] != $actk} {
			puts $hosts "[lindex $kparts 0] \
				[lindex $kparts 1] [lindex $kparts 2] \
				[lindex $kparts 3]"
		    }
		}
		close $hosts
		hostkey edit
		selection clear
		return	    
	    }
	}
    }
}

proc {insprot} {mode} {
    global widget
    $widget(lfout) delete 0 end
    $widget(lfout) insert 0 $mode
}

# Managing the keypair on the local host
proc keygen {mode} {
    global env widget configs pwtextmode libdir

    if {[$widget(identpath) get] == ""} {
	set kf "$env(HOME)/.ssh/identity"
    } else {
	set kf [$widget(identpath) get]
    }
    
    switch -exact $mode {
	gen {
	    # possible ways of giving the user a new key:
	    # - dialog incl. new passwords is a problem because listed in ps
	    # - complete textmode in an xshell most secure
	    # - dialog for file, password etc. and execute by expect
	    set actstring "exec $configs(xtermbin) -T \"SecPanel ssh-keygen\" \
		    -e $libdir/secpanel.wait \"ssh-keygen1 -f $kf\" &"
	    eval $actstring
	}
	1 {
	    if {[$widget(identpath) get] == ""} {
		if {! [file exist $env(HOME)/.ssh/identity]} {
		    showmessage "No key given and\n$env(HOME)/.ssh/identity not found"
		    return
		} else {
		    set kf "$env(HOME)/.ssh/identity"
		}
	    } else {
		set kf [$widget(identpath) get]
	    }
	    if [set pwtextmode] {
		set actstring "exec $configs(xtermbin) -T \"SecPanel - \
			change password for $kf\" \
			-e $libdir/secpanel.wait \"ssh-keygen1 -p -f $kf\" &"
		eval $actstring
	    } else {		
		Window show .top20
		$widget(proplabel) config -text $kf
	    }
	}
	chpwd {
	    set oldp [.top20.fra21.ent26 get]
	    set newp1 [.top20.fra21.ent30 get]
	    set newp2 [.top20.fra21.ent31 get]

	    if {$newp1 != $newp2} {
		showmessage "New password and repeated new password don't match"
		return
	    }

	    if [catch {exec ssh-keygen1 -p -f $kf \
		    -P $oldp -N $newp1} err] {
		showmessage $err
		return
	    }
	    Window destroy .top20
	}
	chpath {
	    choosefile $widget(identpath) $env(HOME)/.ssh
	}
    }
}

proc load_profile {mode} {
    global env widget agentforward x11forward nopriv \
	    verbose quiet fork gateway compress algo compressval lfs
    if {$mode == "ssh"} {
	set act [$widget(profiles) get active]
    } elseif {$mode == "connects"} {
	set act [retprof [$widget(specsites) get active]]
    }

    source $env(HOME)/.secpanel/$act.profile

    foreach f {title host user port command identity} {
	$widget([set f]ent) delete 0 end
	$widget([set f]ent) insert 0 [set $f]
    }

    $widget(profileent) delete 0 end
    $widget(profileent) insert 0 $act

    if {[winfo exists .top43]} {
	Window destroy .top43
	local_forwardings 1
    }
}

proc local_forwardings {mode} {
    global widget lfs
    switch -exact $mode {
	1 {
	    if [winfo exists .top43] {
		return
	    }
	    Window show .top43
	    if [info exists lfs] {
		foreach lf $lfs {
		    if [regsub : $lf { -> } out] {
			$widget(lforwards) insert end $out
		    }
		}
	    }
	}
    }
}

# Control the SSH-Agent
proc manage_agent {mode} {
    global env widget
    switch -exact $mode {
	launch {
	    # If agent exists, use it (anyway the xterms would use it)
	    if {[info exists env(SSH_AGENT_PID)] && [info exists env(SSH_AUTH_SOCK)]} {
		puts "Agent exists"
	    } else {
		puts "No agent found"
	    }

	    # Start ssh-agent and read envs
	    set agentout [open "| ssh-agent1 -c" r]
	    while {[gets $agentout line] > 0} {
		if [string match "setenv SSH*" $line] {
		    set env([lindex [split $line] 1]) [string trimright [lindex [split $line] 2] \;]
		}
	    }
	    close $agentout
	    $widget(statusagent) config -text "Agent active" -bg green -fg black
	}
	kill {
	    exec ssh-agent1 -k
	    # Envs are to be killed explicitly
	    unset env(SSH_AGENT_PID)
	    unset env(SSH_AUTH_SOCK)
	    $widget(statusagent) config -text "No Agent" -bg red -fg white
	    $widget(idents) delete 0 end
	}
	addident {
	    set fname [tk_getOpenFile -initialdir "$env(HOME)/.ssh/"]
	    if {$fname != ""} {
		catch {exec ssh-add1 $fname < /dev/null} err
		if [string match "Bad key file*" $err] {
		    showmessage "Bad key file"
		    return
		}
		set found 0
		foreach ent [$widget(idents) get 0 end] {
		    if {$ent == $fname} {
			set found 1
			break
		    }
		}
		if {! $found} {
		    $widget(idents) insert end $fname
		}
	    } else {
		return
	    }
	}
	remident {
	    if {[selection own] != $widget(idents)} {
		showmessage "No Identity selected"
		return
	    } else {
		catch {exec ssh-add1 -d [$widget(idents) get active]}
		$widget(idents) delete active
	    }
	}
    }
}

# General handling of one entries state by clicking a checkbox
proc managestate {checkbox entry} {
    global widget compress
    if {$compress} {
	$widget(comprlev) config -state normal
    } else {
	$widget(comprlev) config -state disabled
    }
}

# Adding one default connection
proc newconn {mode state} {
    global widget env sites
    switch -exact $mode {
	def {
	    switch -exact $state {
		1 {
		    Window show .top40
		    $widget(newuser) insert 0 $env(USER)
		    grab .top40
		}
		2 {
		    set newtit [$widget(newtit) get]
		    set newaddr [$widget(newaddr) get]
		    set newuser [$widget(newuser) get]
		    
		    if {$newtit != "" && $newaddr != ""} {
			set sites($newtit) "$newaddr#$newuser"
			
			set sitefile [open "$env(HOME)/.secpanel/sites" w]
			foreach s [array names sites] {
			    puts $sitefile "$s#$sites($s)"
			}
			close $sitefile
			
			defsiteupdate
			clear_distmenu
			
			Window destroy .top40
		    } else {
			showmessage "Please enter address and title"
		    }
		}
	    }
	}
	spec {
	    changetab ssh
	    clear_profiles
	}
    }
}

# Switch to edit-mode of one connection (defs and specs)
proc propconn {spec mode} {
    global widget env sites
    switch -exact $spec {
	def {
	    switch -exact $mode {
		1 {
		    if {[$widget(defsites) index end] > 0} {
			set act [$widget(defsites) get active]
			Window show .top40
			$widget(newtit) insert 0 $act
			$widget(newaddr) insert 0 [lindex [split $sites($act) #] 0]
			$widget(newuser) insert 0 [lindex [split $sites($act) #] 1]
			.top40.fra45.but47 config -command "propconn def 2"
			grab .top40
		    } else {
			showmessage "No conncections available, please use \"New\""
			return
		    }
		}
		2 {
		    unset sites([$widget(defsites) get active])
		    newconn def 2
		}
	    }
	}
	spec {
	    if {[$widget(specsites) index end] > 0} {
		changetab ssh
		load_profile connects
	    } else {
		showmessage "No conncections available, please use \"New\""
		return
	    }
	}
    }
}

# return profile-file by title in spec-list
proc {retprof} {tit} {
    global env
    foreach f [glob -nocomplain "$env(HOME)/.secpanel/*.profile"] {
	source $f
	if {$title == $tit} {
	    return "[file rootname [file tail $f]]"
	}
    }
}

proc {save_forwards} {mode} {
    global widget lfs
    set lfs [list]
    foreach line [$widget(lforwards) get 0 end] {
	if [regsub { -> } $line : out] {
	    lappend lfs $out
	}
    }
    Window destroy .top43
}

proc {save_profile} {} {
    global env widget agentforward x11forward  nopriv verbose \
	    quiet fork gateway compress algo compressval lfs

    set prname [$widget(profileent) get]
    if {$prname == ""} {
	showmessage "Enter a name for the profile"
	return
    }

    set title [$widget(titleent) get]
    set host [$widget(hostent) get]
    set user [$widget(userent) get]
    set port [$widget(portent) get]
    set command [$widget(commandent) get]
    
    if {$prname == "default"} {
	if {$title != "Default Profile" || $host != "" \
		|| $user != "" || $command != ""} {
	    showmessage "You may not enter host, user or command for the \
		    default profile and you may not change the title"
	    return
	}
    } else {
	if {$title == "" || $host == ""} {
	    showmessage "You must enter at least host and title"
	    return
	}
    }
    
    set identity [$widget(identityent) get]

    set prfile [open "$env(HOME)/.secpanel/$prname.profile" w]
    
    puts $prfile "#\n# SecPanel-Pofile\n# Do not edit, use SecPanel instead\n#"
    
    foreach ent {title host user port command identity} {
	puts $prfile "set [set ent] \"[set $ent]\""
    }
    foreach bool {agentforward x11forward nopriv verbose \
	    quiet fork gateway compress } {
	if [set $bool] {
	    puts $prfile "set [set bool] \"[set $bool]\""
	} else {
	    puts $prfile "set [set bool] \"[set $bool]\""
	}
    }
    foreach sel {algo compressval} {
	puts $prfile "set [set sel] \"[set $sel]\""
    }

    if [info exists lfs] {
	puts $prfile "set lfs \"$lfs\""
    } else {
	puts $prfile "set lfs \"\""
    }

    close $prfile

    specsiteupdate    
    clear_prmenu
    clear_profiles
    clear_distmenu
}

proc seldistkey {} {
    global env widget
    set ftypes {
	{{Public keys} {.pub}}
	{{All files} *}
    }
    $widget(keydistkey) delete 0 end
    $widget(keydistkey) insert 0 \
	    [tk_getOpenFile -initialdir "$env(HOME)/.ssh"  -filetypes $ftypes]
}

# Selection of the connections Identity
proc select_ident {} {
    global env widget
    choosefile $widget(identityent) $env(HOME)/.ssh
}

# Show one manual page
proc showman {man} {
    exec xterm -e man $man &
}

proc showmessage {text} {
    Window show .top18
    .top18.fra20.mes23 config -text $text
    grab .top18
    return
}

proc specsiteupdate {} {
    global widget env
    $widget(specsites) delete 0 end
    set profiles [glob -nocomplain "$env(HOME)/.secpanel/*.profile"]
    foreach prof $profiles {
	if {[file rootname [file tail $prof]] == "default"} {
	    continue
	}
	source $prof
	$widget(specsites) insert end $title
    }
}

# with single click in connect-lists show some data about profile
proc showstatus {mode} {
    global widget sites
    if {$mode == "def"} {
	set act [$widget(defsites) get active]
	$widget(status) config -text [lindex [split $sites($act) #] 0]
    } else {
	$widget(statusagent) config -text
    }
}

proc main {argc argv} {
    global widget sites env
    clear_prmenu
    clear_profiles
    defsiteupdate
    specsiteupdate
    clear_distmenu
}

puts "Sourcing GUI..."
source $libdir/gui.tcl
