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

#######################################################################
#
# SecPanel - Graphical user interface for managing SSH- and
# SCP-connections
#
# Author: Steffen Leich <steffen.leich _at_ gmail.com>
# http://secpanel.net
#
# 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.
#
#######################################################################

set spversion 0.5.4

set libdir "[file dirname [info script]]/../lib/secpanel"
# set libdir "./lib"
set sshdir "$env(HOME)/.ssh"

set scpcode 0

global actdirsel;
global questres;
global userres;

proc init {argc argv} {
    global env configs tk_version launcher defident libdir agent wins platform

    if {! [info exists env(DISPLAY)] || $env(DISPLAY) == ""} {
	catch {exec "uname -a"} ver
	if {! [regexp -nocase "macintosh" $ver]} {
	    puts "No valid Xwindow DISPLAY environment or MacOSX platform -> exiting SecPanel"
	    exit
	} else {
	    set platform "macosx"
	}
    } else {
	set platform "linux"
    }
    
    set mintcl 8.0
    set mintk 8.0
    
    if {[info tclversion]<$mintcl || $tk_version<$mintk} {
	puts -nonewline stderr "For running SecPanel:\nTcl $mintcl/Tk $mintk minimum versions required. "
	puts stderr "You have Tcl [info tclversion]/Tk $tk_version"
	exit 1
    }

    set secpaneldir "$env(HOME)/.secpanel"
    if {! [file exists $secpaneldir]} {
	file mkdir $secpaneldir
	exec chmod 700 $secpaneldir
	puts "Created config-dir $secpaneldir (chmod 700)..."
    }


    if [file exists $secpaneldir/spdata.lck] {
	puts "Found protected secpanel data"
	# exec $libdir/protect.sh $libdir
	exec $libdir/dppw.tcl "de"
    }

    
    if {! [file exists $secpaneldir/.runfiles]} {
	file mkdir $secpaneldir/.runfiles
    }
    
    if {! [file exists $secpaneldir/profiles]} {
	file mkdir $secpaneldir/profiles
    }
    
    set configfile "$env(HOME)/.secpanel/config"
    if {! [file exists $configfile]} {
	file copy "$libdir/default.config" "$configfile"
    }
    source $configfile
    initconfigs
    
    array set gshorts {fore foreground back background}
    
    foreach gcolval [array names gshorts] {
	if [info exists configs($gcolval)] {
	    option add *$gshorts($gcolval) $configs($gcolval)
	}
    }
    
    array set shorts {entfore Entry.foreground entback Entry.background \
			  listfore Listbox.foreground listback Listbox.background}
    
    foreach colval [array names shorts] {
	if [info exists configs($colval)] {
	    option add *$shorts($colval) $configs($colval)
	    if {$colval == "listfore"} {
		option add *Text.foreground $configs($colval)		
	    }
	    if {$colval == "listback"} {
		option add *Text.background $configs($colval)		
	    }
	}
    }
    
    set fb ""
    set fi ""
    
    if {([info exists configs(sysfonts)] && ($configs(sysfonts) != 1)) || ! [info exists configs(sysfonts)]} {
	    if [info exists configs(fontbold)] {
		if $configs(fontbold) {
		    set fb "bold"
		}
	    }
	    
	    if [info exists configs(fontitalic)] {
		if $configs(fontitalic) {
		    set fi "italic"
		}
	    }
	    
	    if {[info exists configs(fontfam)] && [info exists configs(fontsize)]} {
		option add *Font "\"$configs(fontfam)\" $configs(fontsize) $fb $fi"
	    }
	}

    set agent 0
}

proc initconfigs {} {
    global configs
    foreach {bintag binprog} \
	{sshbin ssh keygenbin ssh-keygen agentbin ssh-agent \
	     addbin ssh-add askpassbin ssh-askpass scpbin scp termver Xterm browserbin firefox \
	     } {
		 if {! [info exists configs($bintag)]} {
		     set configs($bintag) $binprog
		 }
	     }
    if {! [info exists configs(sshver)]} {
	set configs(sshver) "OpenSSH"
    }
    
    if {! [info exists configs(termver)]} {
	set configs(termver) "Xterm"
    }

    if {! [info exists configs(lswait)]} {
	set configs(lswait) "1"
    }

    if {! [info exists configs(lsinterpret)]} {
	set configs(lsinterpret) "tcl"
    }

    if {! [info exists configs(scpguiport)]} {
	set configs(scpguiport) 8820
    }
    if {! [info exists configs(listserverport)]} {
	set configs(listserverport) 9920
    }
    if {! [info exists configs(controlremoteport)]} {
	set configs(controlremoteport) 9910
    }
    if {! [info exists configs(controllocalport)]} {
	set configs(controllocalport) 8810
    }

    if {! [info exists configs(protectdata)]} {
	set configs(protectdata) 0
    }
}

init $argc $argv

proc browsebin {which} {
    global widget
    choosefile $widget([set which]ent) "actdirsel" "Open" ""
}

proc manage_remote {mode} {
    global widget rfts configs libdir env termtype

    # <xterm selection and params>
    set defterm 1

    if $defterm {
	set usetermver "Xterm"
    } else {
	set usetermver $configs(termver)
    }

    set icontag ""
    
    set configs(xtermbin) $termtype([set usetermver]_path)
    set titlepar $termtype([set usetermver]_titlepar)
    set quotepar $termtype([set usetermver]_quotepar)
    set execpar $termtype([set usetermver]_execpar)
    if {[info exists termicon] && $termicon} {
	set icontag $termtype([set usetermver]_iconpar)
    }
    # </xterm selection and params>

    switch -regexp $mode {
	init {
	    if {[selection own] == $widget(specsites)} {
		set actentry [$widget(specsites) get active]
		set rmprof [retprof $actentry]

		source "$env(HOME)/.secpanel/profiles/$rmprof.profile"		
	    } else {
		showmessage "No entry selected" ""
		return
	    }

	    if {[winfo exists .top40]} {
		if [showconfirm\
			"There is another remote management session. Cancel this former session?"\
			.top40] {
		    manage_remote cancel
		} else {
		    return
		}
	    }

	    set rfts [clock clicks]

	    Window show .top40
	    .top40.lab51 config -text "Remote Account Manager for $title ($user@$host)"
	    
	    set connstring "$libdir/secpanel_remoteconf.sh $host $user $configs(scpbin) read $rfts"

	    set runstring "exec $configs(xtermbin) $execpar $quotepar <CONNFILE> $quotepar"

	    provrunfile term nobg $connstring $runstring

	    set shostsfile "$env(HOME)/.secpanel/.runfiles/ram.$rfts/.shosts"
	    set keysfile "$env(HOME)/.secpanel/.runfiles/ram.$rfts/authorized_keys"

	    if {[file exists $shostsfile]} {
		$widget(remoteshostsfile) insert end [exec cat $shostsfile]
	    }
	    if {[file exists $keysfile]} {
		$widget(remotekeysfile) insert end [exec cat $keysfile]
	    }

	    $widget(remotercfile) insert end "Not yet supported, breaks scp..."
	}
	cancel {
	    file delete -force "$env(HOME)/.secpanel/.runfiles/ram.$rfts"
	    unset rfts
	    Window destroy .top40
	}
	write {
	    if [showconfirm "Really write back remote configuration?" ".top40"] {

		set shostsfile [open "$env(HOME)/.secpanel/.runfiles/ram.$rfts/.shosts" w]
		puts -nonewline $shostsfile [$widget(remoteshostsfile) get 1.0 end]
		close $shostsfile

		set keysfile [open "$env(HOME)/.secpanel/.runfiles/ram.$rfts/authorized_keys" w]
		puts -nonewline $keysfile [$widget(remotekeysfile) get 1.0 end]
		close $keysfile

		set connstring "$libdir/secpanel_remoteconf.sh localhost freenet scp write $rfts"

		set runstring "exec $configs(xtermbin) $execpar $quotepar <CONNFILE> $quotepar"
		
		provrunfile term bg $connstring $runstring

		Window destroy .top40
	    }
	}
    }
}

proc save_globals {mode} {
    global widget env configs launcher defident wins
    set conffile [open "$env(HOME)/.secpanel/config" w]
    switch -regexp $mode {
	bins {
	    array set bindefs { \
		    ssh ssh keygen ssh-keygen agent ssh-agent add ssh-add \
		    askpass ssh-askpass scp scp browser firefox }

	    foreach f {ssh keygen agent add askpass scp browser} {
		if {[$widget([set f]ent) get] == ""} {
		    $widget([set f]ent) insert 0 $bindefs($f)
		}

		puts $conffile "set configs([set f]bin) \"[$widget([set f]ent) get]\""
		set configs([set f]bin) [$widget([set f]ent) get]
	    }
	    puts $conffile "set configs(sshver) \"$configs(sshver)\""
	    puts $conffile "set configs(termver) \"$configs(termver)\""
	    if [info exists defident] {
		puts $conffile "set defident \"$defident\""
	    }
	    puts $conffile "set launcher $launcher"
	}
	"geom|startsat|color|fonts|scp|agent|chdef|protectdata" {
	    foreach f {ssh keygen agent add askpass scp browser} {
		puts $conffile "set configs([set f]bin) \"$configs([set f]bin)\""
	    }
	    puts $conffile "set configs(sshver) \"$configs(sshver)\""
	    puts $conffile "set configs(termver) \"$configs(termver)\""
	    puts $conffile "set launcher $launcher"
	    if [info exists defident] {
		puts $conffile "set defident \"$defident\""
	    }
	}
    }

    foreach col {fore back entfore entback listfore listback} {
	if [info exists configs($col)] {
	    puts $conffile "set configs($col) $configs($col)"
	}
    }

    foreach font {fontfam fontsize fontbold fontitalic sysfonts} {
	if [info exists configs($font)] {
	    puts $conffile "set configs($font) \"$configs($font)\""
	}
    }

    if [info exists configs(wingeom)] {
	puts $conffile "set configs(wingeom) \"$configs(wingeom)\""
    }

    if [info exists configs(protectdata)] {
	puts $conffile "set configs(protectdata) \"$configs(protectdata)\""
    }

    foreach w [array names wins] {
	puts $conffile "set wins($w) \"$wins($w)\""
    }

    if [info exists configs(startsat)] {
	puts $conffile "set configs(startsat) \"$configs(startsat)\""
    }    

    foreach scpbool {scpstats scppres scpverb scpcomp scpshowhidden \
	    lswait lsverbose} {
	if [info exists configs($scpbool)] {
	    if $configs($scpbool) {
		puts $conffile "set configs($scpbool) \"$configs($scpbool)\""
	    } else {
		puts $conffile "set configs($scpbool) \"$configs($scpbool)\""
	    }
	}
    }

    if [info exists configs(scpport)] {
	regsub -all " " $configs(scpport) "" configs(scpport)
	puts $conffile "set configs(scpport) \"$configs(scpport)\""
    }

    if [info exists configs(lsinterpret)] {
	puts $conffile "set configs(lsinterpret) \"$configs(lsinterpret)\""
    }

    foreach port {scpgui listserver controlremote controllocal} {
	puts $conffile "set configs([set port]port) \"$configs([set port]port)\""
    }

    close $conffile
    showstatus "Global configs saved"
}

proc chbutton {var but} {
    global fgdef bgdef
    if {[set $var]} {
	$but config -state disabled
    } else {
	$but config -state normal
    }
}

proc chcol {var button title} {
    set ret [colorchoose ".top17" $title]
    if {$ret != ""} {
	$button config -background $ret
    }
}

proc colorchoose {parent title} {
    set col [tk_chooseColor -parent $parent -title "SecPanel - $title"]
    return $col
}

proc fontman {mode} {
    global configs

    set names .top23.fra36.cpd37.01
    set sizes .top23.fra36.cpd38.01
    
    switch -exact $mode {
	show {
	    Window show .top23
	    set names .top23.fra36.cpd37.01
	    set sizes .top23.fra36.cpd38.01
	    
	    foreach f [lsort [font families]] {
		$names insert end $f
	    }
	    
	    set fs 6
	    while {$fs <= 60} {
		$sizes insert end $fs
		incr fs
	    }

	    if $configs(fontbold) {
		set fb "bold"
	    } else {
		set fb ""
	    }
	    
	    if $configs(fontitalic) {
		set fi "italic"
	    } else {
		set fi ""
	    }
	    
	    if {! $configs(sysfonts)} {

		if {[info exists configs(fontfam)] && [info exists configs(fontsize)]} {
		    set label "$configs(fontfam) $configs(fontsize)"
		    .top23.lab30 config \
			-font "\"$configs(fontfam)\" $configs(fontsize) $fi $fb"
		} else {
		    set label ""
		}

 		.top23.lab30 config -text "$label"
	    } else {
 		.top23.lab30 config -text "Using external sysfonts"
	    }		
	    
	    set fc 0
	    if [info exists configs(fontfam)] {
		foreach fn [$names get 0 end] {
		    if {$fn =="$configs(fontfam)"} {
			$names activate $fc
			$names see $fc
		    }
		    incr fc		    
		}
	    }
	    
	    set sc 0
	    if [info exists configs(fontsize)] {
		foreach fs [$sizes get 0 end] {
		    if {$fs =="$configs(fontsize)"} {
			$sizes activate $sc
			$sizes see $sc
		    }
		    incr sc		    
		}
	    }

	    # activate listenelement in fontfam und size mit richtigen Werten
	    # font-ex.text mit eingestellten werten
	}
	
	save {
	    set configs(fontfam) [$names get active]
	    set configs(fontsize) [$sizes get active]
	    save_globals fonts
	    Window destroy .top23
	}

	ul {

	    if {! $configs(sysfonts)} {
		set name [$names get active]
		set size [$sizes get active]
		
		if $configs(fontbold) {
		    set fb "bold"
		} else {
		    set fb ""
		}
		
		if $configs(fontitalic) {
		    set fi "italic"
		} else {
		    set fi ""
		}
		.top23.lab30 config -text "[$names get active] [$sizes get active]" -font "\"$name\" $size $fi $fb"
	    } else {
 		.top23.lab30 config -text "Using external sysfonts"
	    }		
	}
    }
}

proc colorman {mode} {
    global env configs \
	    foredef backdef entforedef entbackdef listforedef listbackdef

    foreach {name widg} {fore 37 back 38 entfore 39 \
	    entback 40 listfore 41 listback 42} {
	set colbut[set name] ".top32.fra33.but[set widg]"
    }
    
    set colvals [list fore back entfore entback listfore listback];
    
    switch -exact $mode {
	1 {
	    Window show .top32
	    foreach colval $colvals {
		if [info exists configs($colval)] {
		    [set colbut[set colval]] configure -background $configs($colval)
		} else {
		    set [set colval]def 1
		}
	    }
	}
	save {
	    foreach colval $colvals {
		if {! [set [set colval]def]} {
		    set configs([set colval]) [[set colbut[set colval]] cget -background]
		} else {
		    if [info exists configs([set colval])] {
			unset configs([set colval])
		    }
		}
	    }
	    Window destroy .top32
	    save_globals color
	}
	default {
	    set col [colorchoose .top32 "Foreground Color"]
	    if {$col != ""} {
		[set colbut[set mode]] config \
			-background $col -activebackground $col
		return
	    } else {
		return
	    }
	}
    }
}

proc showmenu {} {
    if [winfo exists .pm1] {
	Window destroy .pm1
    }

    if [winfo exists .pm2] {
	Window destroy .pm2
    }

    menu .pm1 -tearoff 0 -borderwidth 1
    .pm1 add command -label "Connect" -command "connect"
    .pm1 add command -label "Edit" -command "propconn specsites"

    .pm1 add command -label "Delete" -command "delconn"
    .pm1 add command -label "Show info" -state "disabled"
    .pm1 add command -label "Manage remote account" -command "manage_remote init"
    .pm1 add cascade -label "Export as..." -menu .pm1.pm2
    .pm1 add separator
    .pm1 add command -label "New connection" -command "newconn 1"
    
    menu .pm1.pm2 -tearoff 0 -borderwidth 1
    .pm1.pm2 add command -label "Shellscript" -command "export sh" -state "disabled"
    .pm1.pm2 add command -label "SSH configfile" -command "export ssh" -state "disabled"
    .pm1.pm2 add command -label "GNOME icon" -command "export gnome" -state "disabled"
    .pm1.pm2 add command -label "KDE icon" -command "export kde" -state "disabled"
    
    tk_popup .pm1 [winfo pointerx .top17] [winfo pointery .top17]
}

proc historyman {mode "categ {}" "text {}"} {
    global env histjob configs wins
    switch -exact $mode {
	write {
	    set hf [open "$env(HOME)/.secpanel/history" a]
	    puts $hf "$categ#[clock seconds]#$text"
	    close $hf
	    if [winfo exists .top26] {
		historyman print
	    }
	}
	show {
	    Window show .top26

	    if {[info exists configs(wingeom)] && $configs(wingeom)} {
		if [info exists wins(hist)] {
		    wm geometry ".top26" $wins(hist)
		}
	    }

	    set histjob 1
	    historyman print
	}
	report {

	    set repdir "$env(HOME)/.secpanel/reports"
	    if {! [file exists "$repdir"]} {
		file mkdir "$repdir"
	    }

	    set index [open "$repdir/index.html" w]
	    puts $index "<!-- generated by SecPanel [exec date]-->\n<frameset border=0 frameborder=\"no\" rows=\"10%,90%\">\n<frame src=\"header.html\" name=\"header\">\n<frameset border=0 frameborder=\"no\" cols=\"20%,80%\">\n<frame src=\"panel.html\" name=\"panel\">\n<frame src=\"1.html\" name=\"content\">\n</frameset></frameset>"
	    close $index

	    set header [open "$repdir/header.html" w]
	    puts $header "<font size=\"+2\">Report of Secure Shell actions</font><br>Generated by SecPanel [exec date]"
	    close $header

	    set panel [open "$repdir/panel.html" w]
	    puts $panel "<b>Actions</b>\n<HR>\n<a target=\"content\" href=\"1.html\">SSH connect</a><br>\n<a target=\"content\" href=\"2.html\">SCP connect</a><br>\n<a target=\"content\" href=\"3.html\">SCP transfer</a><br>\n<a target=\"content\" href=\"4.html\">Keygen</a><br>\n<a target=\"content\" href=\"5.html\">Keydist</a><br>\n<a target=\"content\" href=\"6.html\">Agent</a><HR>"
	    close $panel

	    if {! [file exists "$env(HOME)/.secpanel/history"]} {
		showmessage "No history available" .top26
		return
	    }

	    foreach m {1 2 3 4 5 6} {
		set modef[set m] [open "$repdir/[set m].html" w]
		puts [set modef[set m]] "<table border=0 width=\"80%\">\n"
	    }

	    set hf [open "$env(HOME)/.secpanel/history" r]
	    while {[gets $hf line] >= 0} {
		set elems [split $line "#"]
		set actmode [set modef[lindex $elems 0]]
		puts $actmode "<tr><td>[clock format [lindex $elems 1]]<hr noshade></td><td>[lindex $elems 2]<hr noshade></td></tr>\n"
	    }

	    foreach m2 {1 2 3 4 5 6} {
		puts [set modef[set m2]] "</table>\n"
		close [set modef[set m2]]
	    }
	    showmessage "Report for actual history generated in ~/.secpanel/reports/index.html" .top26

	    exec $configs(browserbin) "file:$env(HOME)/.secpanel/reports/index.html" &
	}
	print {
	    set text .top26.cpd27.03
	    $text delete 1.0 end
	    if {! [file exists "$env(HOME)/.secpanel/history"]} {
		return
	    }
	    set hf [open "$env(HOME)/.secpanel/history" r]
	    while {[gets $hf line] >= 0} {
		set elems [split $line "#"]
		if {[lindex $elems 0] == $histjob} {
		    $text insert end "[clock format [lindex $elems 1]] - [lindex $elems 2]\n"
		}
	    }
	    $text see end
	    close $hf
	}
	clear {
	    if [showconfirm "Really clear the history?\n(Keeping $categ days)" ".top26"] {
		if {$categ != "0"} {
		    set hfile "$env(HOME)/.secpanel/history"
		    if {! [file exists $hfile]} {
			showmessage "No history available" .top26
			return
		    }
		    set now [clock seconds]
		    set hf [open "$hfile" r]
		    while {[gets $hf line] >= 0} {
			set elems [split $line "#"]

			if {[lindex $elems 1] >= [expr $now - ($categ * 24 * 60 * 60)]} {
			    lappend kept $line
			}

		    }
		    close $hf

		    set hf [open "$hfile" w]
		    foreach l $kept {
			puts $hf $l
		    }
		    close $hf
		} else {
		    file delete "$env(HOME)/.secpanel/history"
		}
		historyman print
	    } else {
		return
	    }
	}
    }
}

proc showcomm {mode} {
    global widget lfstemp rfstemp
    set actline [$widget([set mode]forwards) get active]
    if [regsub { -> } $actline : out] {
	$widget([set mode]fcomment) config -text [set [set mode]fstemp($out)]
    }
}

proc add_forw {mode} {
    global widget lfstemp rfstemp
    set fhost [$widget([set mode]fhost) get]
    set fin [$widget([set mode]fin) get]
    set fout [$widget([set mode]fout) get]
    set fcomment [$widget([set mode]fcommentent) get]

    set lhostname "<TARGET-HOST>"
    set rhostname "<LOCAL-HOST>"

    if {$fhost == ""} {
	set fht [set [set mode]hostname]
    } else {
	set fht $fhost
    }

    if {$fin != "" && $fout != ""} {

	$widget([set mode]fcomment) config -text ""	
	foreach an [array names [set mode]fstemp] {
	    if {$an == "$fin:$fht:$fout"} {
		$widget([set mode]fcomment) config -text "Forward exists"
		return
	    }
	}

	$widget([set mode]forwards) insert end "$fin -> $fht:$fout"
	set [set mode]fstemp($fin:$fht:$fout) $fcomment

	$widget([set mode]fin) delete 0 end
	$widget([set mode]fout) delete 0 end
	$widget([set mode]fhost) delete 0 end
	$widget([set mode]fcommentent) delete 0 end

	focus $widget([set mode]fin)
	$widget([set mode]forwards) see end
    }
}

proc del_forw {mode} {
    global widget lfstemp rfstemp
    set lwin .top43
    set rwin .top51

    if {[selection own] == $widget([set mode]forwards)} {
	set actline [$widget([set mode]forwards) get active]
	if [regsub { -> } $actline : out] {
	    unset [set mode]fstemp($out)
	    $widget([set mode]forwards) delete active
	}
    } else {
	showmessage "No forwarding selected" [set [set mode]win]
    }
    selection clear
}

proc save_forwards {mode} {
    global widget rfs rfstemp lfs lfstemp
    set lwin .top43
    set rwin .top51

    if [info exists [set mode]fs] {
	unset [set mode]fs
    }

    array set [set mode]fs [array get [set mode]fstemp]

    if [info exists [set mode]fstemp] {
	unset [set mode]fstemp
    }

    Window destroy [set [set mode]win]
}

proc open_forwardings {mode} {
    global widget lfs rfs lfstemp rfstemp
    set lwin .top43
    set rwin .top51
    
    Window show [set [set mode]win]
    $widget([set mode]forwards) delete 0 end

    if [info exists [set mode]fstemp] {
	unset [set mode]fstemp
    }

    if [info exists [set mode]fs] {
	array set [set mode]fstemp [array get [set mode]fs]
    }

    foreach fe [array names [set mode]fstemp] {
	if [regsub : $fe { -> } out] {
	    $widget([set mode]forwards) insert end $out
	}
    }
}

proc changetab {mode} {
    global libdir agent widget wins configs
    switch -exact $mode {
	"small" {

	    if {! [$widget(specsites) index end] > 0} {
		showmessage "No conncections available, please add one..." ""
		return
	    }

	    wm withdraw .top17
	    Window show .top27

	    if {[info exists configs(wingeom)] && $configs(wingeom)} {
		if [info exists wins(sat)] {
		    wm geometry ".top27" $wins(sat)
		}
	    }

	    .top27.but27 config -image [image create photo -file "$libdir/images/swinback_gr.gif"]

	    if {$agent == 1 || $agent == "ext"} {
		.top27.but27 config -bg green -fg black
	    } else {
		.top27.but27 config -bg red
	    }

	    specsiteupdate "ss"
	    bind .top27 <Destroy> {
		changetab big
	    }
	}
	"big" {
	    wm withdraw .top27
	    destroyfilter .top27
	    Window show .top17
	}
	"default" {
	    foreach f {21 27 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 27}
	    
	    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
	    showstatus ""
	}
    }
}

proc choosefile {{entry ""} {startdir ""} {mode ""} {task ""}} {
    global actdirsel env widget

    switch -exact $task {
	"identityent" {
	    set entry $widget(identityent)
	    set startdir $env(HOME)/.ssh
	    set mode "Open"
	}
	"cfgfileent" {
	    set entry $widget(cfgfileent)
	    set startdir $env(HOME)/.ssh
	    set mode "Open"	    
	}
	"keygen" {
	    set entry "$widget(identpath)"
	    set startdir "$env(HOME)/.ssh"
	    set mode "Save"
	}
	"*" {
	}
    }

    if {$startdir == "actdirsel"} {
	if [info exists actdirsel] {
	    set startdir $actdirsel
	} else {
	    set startdir "/usr/"
	}
    }

    set choice [tk_get[set mode]File -initialdir $startdir]
    if {$choice != ""} {
	$entry delete 0 end
	$entry insert 0 $choice
	set actdirsel [file dirname $choice]
    } else {
	return
    }
}

proc showmessage_wizard {text} {
    global widget
    $widget(messageline) config -text "$text"
}

proc distwizard {mode direct} {
    global widget key connectionprofiles
    switch -exact $mode {
	"key" {
	    switchtab_wizard "key"
	    update_keylist
	    $widget(contbutton) config -command "distwizard host f" -text "Continue" -state "active"
	    $widget(backbutton) config -state "disabled" -command ""
	    showmessage_wizard ""
	}
	"host" {
	    if {$direct == "f"} {
		set key [$widget(distkeyentry) get]
		if {$key == ""} {
		    showmessage_wizard "Please choose key!"
		    return
		}
	    }
	    switchtab_wizard "host"
	    $widget(contbutton) config -command "distwizard confirm f" -text "Continue" -state "active"
	    $widget(backbutton) config -command "distwizard key b" -state "active"
	    showmessage_wizard ""
	}
	"confirm" {
	    if {$direct == "f"} {
		if {[selection own] != $widget(distconnlist)} {
		    showmessage_wizard "Please choose connection!"
		    return
		}
		set connections [$widget(distconnlist) curselection]
	    }

	    set connectiontitles ""
	    set connectionprofiles ""
	    foreach connentry $connections {
		set connectiontitles [concat $connectiontitles [$widget(distconnlist) get $connentry]]
		lappend connectionprofiles [retprof [$widget(distconnlist) get $connentry]]
	    }

	    switchtab_wizard "confirm"
	    $widget(finishmessage) config -text "Distribute\n$key\nto connection\n[lsort $connectiontitles]"
	    $widget(contbutton) config -command "distwizard finish f" -text "Distribute key" -state "active"
	    $widget(backbutton) config -command "distwizard host b" -state "active"
	    showmessage_wizard ""
	}
	"finish" {
	    Window destroy .top53
	    distkey "\"$key\"" "$connectionprofiles"
	}
    }
}


proc distkey {key connectionprofiles} {
    global env widget libdir configs termtype

    set connstring ""

    foreach actconn $connectionprofiles {
	
	source "$env(HOME)/.secpanel/profiles/$actconn.profile"

	if {$user == "<ASKFORUSER>"} {
	    set user [askforuser]
	    if {$user == "#####"} {
		return
	    }
	}
    
	set singleactstring "$libdir/secpanel.dist $host $user $key $configs(sshbin)"
	set connstring "$connstring $singleactstring"
	set connstring "$connstring \n\n\necho ==============================================================\n\n"

	historyman write 5 "$key -> $user@$host"

    }
    set connstring "$connstring echo
    echo \"Key-Distribution finished\nPress <Return> to continue\"
    read out
    exit"


    # <xterm selection and params>
    set defterm 1

    if $defterm {
	set usetermver "Xterm"
    } else {
	set usetermver $configs(termver)
    }

    set icontag ""
    
    set configs(xtermbin) $termtype([set usetermver]_path)
    set titlepar $termtype([set usetermver]_titlepar)
    set quotepar $termtype([set usetermver]_quotepar)
    set execpar $termtype([set usetermver]_execpar)
    if {[info exists termicon] && $termicon} {
	set icontag $termtype([set usetermver]_iconpar)
    }
    # </xterm selection and params>

    set runstring "exec $configs(xtermbin) $titlepar \"SecPanel Key-Distribution\" $execpar $quotepar <CONNFILE> $quotepar"

    provrunfile term bg $connstring $runstring
}

proc command_trace {mode "text {}"} {
    global env configs wins

    set tracetext ".top24.cpd25.03"
    set tracefile "$env(HOME)/.secpanel/.runfiles/trace.log"

    switch -exact $mode {
	"view" {

	    if {! [winfo exists .top24]} {
		Window show .top24
		if {[info exists configs(wingeom)] && $configs(wingeom)} {
		    if [info exists wins(trace)] {
			wm geometry ".top24" $wins(trace)
		    }
		}
	    }

	    $tracetext delete 1.0 end
	    if [file exists "$tracefile"] {
		set tf [open "$tracefile" r]
		while {[gets $tf line] >= 0} {
		    set elems [split $line "#"]
		    $tracetext insert end "[clock format [lindex $elems 0]] - [lindex $elems 1]\n"
		}
		close $tf
	    } else {
		$tracetext insert end "No tracelog available"
	    }
	    $tracetext see end
	}
	"save" {
	    set tf [open "$tracefile" a]
	    puts $tf "[clock seconds]#[quote_double_space $text]"
	    close $tf
	    if [winfo exists .top24] {
		command_trace "view"
	    }
	}
    }
}

proc switchtab_wizard {mode} {
global widget
    foreach f {key host confirm} {
	if {[grid info $widget([set f]frame)] != ""} {
	    grid remove $widget([set f]frame)
	}
    }
    
    grid $widget([set mode]frame) -in .top53  -column 0 -row 1 -columnspan 1 -rowspan 1  -ipadx 2 -ipady 2 -padx 2 -pady 2 -sticky nesw
}

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

proc clear_profiles {} {
    global env widget noagentforward x11forward stricthost nopriv lfs rfs \
	    verbose quiet fork gateway compress algo compressval \
	    connwait termicon sshverconnect ipverconnect askuserspec noexec

    foreach b {noagentforward x11forward stricthost nopriv \
	    verbose quiet fork gateway compress connwait termicon askuserspec noexec} {
	set [set b] 0
    }
    
    set algo "default"
    set compressval 6

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

    if [info exists rfs] {
	unset rfs
    }

    $widget(userent) insert 0 "$env(USER)"
    $widget(portent) insert 0 "22"
    
    set sshverconnect "2"
    set ipverconnect "4"

    if {[winfo exists .top43]} {
	Window destroy .top43
	open_forwardings l
    }

    if {[winfo exists .top51]} {
	Window destroy .top51
	open_forwardings r
    }
}

proc provrunfile {term bg connstring runstring} {
    global env platform libdir

    if {$bg=="bg"} {
	set bgtag "&"
    } else {
	set bgtag ""
    }

    if {$term == "term"} {
	if {$platform == "macosx"} {
	    set termfile [read [open "$libdir/macosxtermdef" r]]

	    set termfiletitle [regsub {<Title>.*</Title>} $termfile "<Title>SecPanel</Title>"]
	    set termfileproc [regsub {<ExecString>.*</ExecString>} $termfiletitle "<ExecString>$connstring</ExecString>"]
	    puts [open "$env(HOME)/.secpanel/.runfiles/macrunproc-[clock clicks].term" w] $termfileproc

	} else {
	    set cf "$env(HOME)/.secpanel/.runfiles/runproc.[clock clicks]"
	    set connfile [open $cf w]
	    
	    puts $connfile $connstring
	    close $connfile
	    exec chmod +x $cf
	    
	    set cfr "$cf-run"
	    set crfile [open "$cfr" w]
	    
	    puts $crfile [regsub {<CONNFILE>} $runstring $cf]
	    close $crfile
	    exec chmod +x $cfr
	    
	    exec $cfr $bgtag
	}
    } else {
	set cfr "$env(HOME)/.secpanel/.runfiles/runproc.[clock clicks]-run"
	set crfile [open "$cfr" w]
	
	puts $crfile "$runstring $connstring"
	close $crfile
	exec chmod +x $cfr
	
	exec $cfr $bgtag
    }

    if {$bg == "nobg"} {
	file delete -force $cf
	file delete -force $cfr
    }
}

proc multiconnect {mode} {
    global widget env configs libdir

    if {! [$widget(specsites) index end] > 0} {
	showmessage "No connections available, please use \"New\"" ""
	return
    }
    
    if {[selection own] != $widget(specsites)} {
	showmessage "Please select connection" .top17
	return
    }
    
    set connsel [$widget(specsites) curselection]

    set connstring ""

    foreach connselentry $connsel {

	set actconn [retprof [$widget(specsites) get $connselentry]]

	source "$env(HOME)/.secpanel/profiles/$actconn.profile"
	
	if {$user == "<ASKFORUSER>"} {
	    set user [askforuser]
	    if {$user == "#####"} {
		return
	    }
	}
	switch -exact $mode {
	    "multixterm" {
		set connstring "$connstring $user@$host"
	    }
	    "cssh" {
		set connstring "$connstring $user@$host:$port"
	    }
	}
    }

    switch -exact $mode {
	"multixterm" {
	    set runstring "multixterm -xc \"ssh %n\""
	}
	"cssh" {
	    set runstring "cssh"
	}
    }

    command_trace save "$runstring $connstring"
    provrunfile noterm bg $connstring $runstring
}

proc connect {{cm ""}} {
    global widget env configs libdir termtype

    set sshverconnect 1
    
    if {$cm == "ss"} {
	set connsel 1
    } else {
	
	if {! [$widget(specsites) index end] > 0} {
	    showmessage "No connections available, please use \"New\"" ""
	    return
	}
	
	if {[selection own] != $widget(specsites)} {
	    showmessage "Please select connection" .top17
	    return
	}

	set connsel [$widget(specsites) curselection]
	
    }
    

    foreach connselentry $connsel {

	if {$cm == "ss"} {
	    set actconn [retprof [$widget(sspecsites).sspecmenu entrycget active -label]]
	}

	set actconn [retprof [$widget(specsites) get $connselentry]]

	source "$env(HOME)/.secpanel/profiles/$actconn.profile"
	
	if {$user == "<ASKFORUSER>"} {
	    set user [askforuser]
	    if {$user == "#####"} {
		return
	    }
	}
	
	if {[array size lfs] > 0} {
	    foreach lf [array names lfs] {
		if {[regsub {<TARGET-HOST>} [lindex [split $lf :] 1] $host th]} {
		    append lf_tag " -L [lindex [split $lf :] 0]:$th:[lindex [split $lf :] 2] "
		} else {
		    append lf_tag " -L [lindex [split $lf :] 0]:[lindex [split $lf :] 1]:[lindex [split $lf :] 2] "
		}
	    }
	} else {
	    set lf_tag " "
	}
	
	set localhost [info hostname]
	if {[array size rfs] > 0} {
	    foreach rf [array names rfs] {
		if {[regsub {<LOCAL-HOST>} [lindex [split $rf :] 1] $localhost lh]} {
		    append rf_tag " -R [lindex [split $rf :] 0]:$lh:[lindex [split $rf :] 2] "
		} else {
		    append rf_tag " -R [lindex [split $rf :] 0]:[lindex [split $rf :] 1]:[lindex [split $rf :] 2] "
		}
	    }
	} else {
	    set rf_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 != "default" || $algo == ""} {
	    set algo_tag "-c $algo "
	} else {
	    set algo_tag " "
	}
    
	if {$identity != ""} {
	    set ident_tag "-i $identity "
	} else {
	    set ident_tag " "
	}
   
	if {[info exists cfgfile] && $cfgfile != ""} {
	    set cfgfile_tag "-F $cfgfile "
	} else {
	    set cfgfile_tag " "
	}    
    
	if {[info exists noagentforward] && $noagentforward} {
	    set noagentforward_tag "-a "
	} else {
	    set noagentforward_tag "-A "
	}    

	if {$command != "" && ([info exists noexec] && ! $noexec) && \
		([info exists subsys] && $subsys == "")} {
	    set command_tag "$command"
	} elseif {[info exists subsys] && $subsys != ""} {
	    set command_tag "-s $subsys"
	} else {
	    set command_tag ""
	}
    
	if $compress {
	    # openssh
	    if {$configs(sshver) == "OpenSSH"} {
		set compressval_tag "-o \'CompressionLevel [set compressval]\' "
	    } else {
		set compressval_tag "-o CompressionLevel=$compressval "
	    }
	} else {
	    set compressval_tag " "
	}
    
	array set bools {
	    "x11forward" "-x" \
		"stricthost" "-o StrictHostKeyChecking=yes" \
		"nopriv" "-P" \
		"verbose" "-v" \
		"quiet" "-q" \
		"fork" "-f" \
		"gateway" "-g" \
		"compress" "-C" \
		"noexec" "-N"
	}
    
	# foreach f [array names $bools]
	foreach f {x11forward stricthost nopriv verbose \
		       quiet fork gateway compress noexec} {
	    if {[info exists $f] && [set $f]} {
		set [set f]_tag "$bools($f) "
	    } else {
		set [set f]_tag " "
	    }
	}

	if [info exists sshverconnect] {
	    set sshvertag "-[set sshverconnect] "
	}

	if [info exists ipverconnect] {
	    set ipvertag "-[set ipverconnect] "
	} else {
	    set ipvertag " "
	}

	# openssh
	if {$configs(sshver) == "OpenSSH"} {
	    if {[info exists x11forward] && ! $x11forward} {
		set x11forward_tag "-X "
	    }	    
	    if {[info exists noexec] && $noexec} {
		set noexec_tag "-N "
	    }
	}

	# <xterm selection and params>
	set defterm 0
	
	if $defterm {
	    set usetermver "Xterm"
	} else {
	    set usetermver $configs(termver)
	}
	
	set icontag ""
	
	set configs(xtermbin) $termtype([set usetermver]_path)
	set titlepar $termtype([set usetermver]_titlepar)
	set quotepar $termtype([set usetermver]_quotepar)
	set execpar $termtype([set usetermver]_execpar)
	if {[info exists termicon] && $termicon} {
	    set icontag $termtype([set usetermver]_iconpar)
	}
	# </xterm selection and params>


	set waittag ""
	set woption ""
	if {[info exists connwait] && $connwait } {
	    set waittag "$libdir/secpanel.wait"
	    set woption "\'"
	}

	set connstring "$configs(sshbin) $user_tag \
	    $noagentforward_tag $x11forward_tag $noexec_tag $stricthost_tag $sshvertag \
            $ipvertag $port_tag $algo_tag \
	    $ident_tag $cfgfile_tag $nopriv_tag $verbose_tag $quiet_tag \
	    $fork_tag $gateway_tag $compress_tag $compressval_tag \
	    $lf_tag $rf_tag $host $command_tag"

	set runstring "exec $configs(xtermbin) $icontag $titlepar \"SSH Connection - $title\" \
	    $execpar $quotepar $waittag $woption <CONNFILE> $woption $quotepar"

	provrunfile term bg $connstring $runstring

	historyman write 1 "$title"
	command_trace save "$connstring"
    }
}


proc probeversion {} {
    global widget configs

    set binstring [$widget(sshent) get]
    if {$binstring == ""} {
	set binstring "ssh"
    }

    catch {exec $binstring -V} ver

    if [regexp -nocase "openssh" $ver] {
	set restext "I guess we have an OpenSSH-version\n\nFound $ver"
	set configs(sshver) "OpenSSH"
    } elseif [regexp -nocase "SSH Secure Shell" $ver] {
	set restext "I guess we have a\nSSH.com-version\n\nFound $ver"
	set configs(sshver) "SSH.com"
    } else {
	set restext "I am not sure about what kind of program is this!\n\nMaybe not a SSH-binary?\nOr doesn't exist at all..."
    }	

    showmessage "$restext" .top17
}

proc showconfirm {text parent} {
    global questres

    if {$parent == ""} {
	set p .top17
    } else {
	set p $parent
    }

    set old [focus]
    Window show .top18

    set xcoord [expr [winfo rootx $p] + ([winfo width $p] / 2) - ([winfo width .top18] / 2)]
    set ycoord [expr [winfo rooty $p] + ([winfo height $p] / 2) - ([winfo height .top18] / 2)]
    wm geometry .top18 +$xcoord+$ycoord

    .top18.mes19 config -text "$text"
    tkwait visibility .top18

    focus .top18
    grab .top18
    tkwait variable questres
    grab release .top18
    focus $old
    Window destroy .top18
    if {$questres} {
	return 1
    } else {
	return 0
    }
}

proc getuser {} {
    global widget userres
    set userres [$widget(askeduser) get]
}

proc askforuser {"mode c"} {
    global userres widget
    set old [focus]
    Window show .top21

    if {$mode == "md"} {
	wm title .top21 "SecPanel - Make dir" 
	.top21.fra22.mes23 config -text "Enter name of new directory:"
	.top21.but26 config -text "Make dir"
    }

    if {$mode == "protectdata"} {
	wm title .top21 "SecPanel - Give password for SecPanel data protection" 
	.top21.fra22.mes23 config -text "Enter name of new directory:"
	.top21.but26 config -text "Make dir"
    }

    tkwait visibility .top21
    focus $widget(askeduser)
    grab .top21
    tkwait variable userres
    grab release .top21
    focus $old
    Window destroy .top21
    return $userres
}

proc quote_space {in} {
    regsub -all " " $in "\\ " out
    return $out
}

proc quote_double_space {in} {
    regsub -all " +" $in " " out
    return $out
}

proc showmessage {text parent} {
    if {$parent == ""} {
	set p .top17
    } else {
	set p $parent
    }

    Window show .top22
    .top22.mes23 config -text $text

    set xcoord [expr [winfo rootx $p] + ([winfo width $p] / 2) - ([winfo width .top22] / 2)]
    set ycoord [expr [winfo rooty $p] + ([winfo height $p] / 2) - ([winfo height .top22] / 2)]
    wm geometry .top22 +$xcoord+$ycoord

    focus .top22
    grab .top22
    tkwait window .top22
}


proc check_sources {mode} {
    global configs
    switch -exact $mode {
	ssh {
	}
	sp {
	    exec $configs(browserbin) "http://secpanel.mymediahost.de/?sp_check" &
	}
    }
}

proc delconn {} {
    global widget env
    if {[selection own] == $widget(specsites)} {
	set actentry [$widget(specsites) get active]
	set delprof [retprof $actentry]
	if {[showconfirm "Delete $actentry?" ""] == 1} {
	    file delete "$env(HOME)/.secpanel/profiles/$delprof.profile"
	    specsiteupdate
	    clear_prmenu
	    selection clear
	} else {
	    return
	}

    } 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 {[showconfirm "Delete $act?" ""] == 1} {
	file delete "$env(HOME)/.secpanel/profiles/$act.profile"
	clear_prmenu
	clear_profiles
	specsiteupdate
    }
}

proc hostkey {mode} {
    global env widget configs hostkeytype
    set khfile "$env(HOME)/.ssh/known_hosts"

    catch {exec $configs(keygenbin) -h} ver
    if [regexp -nocase "F hostname Find hostname" $ver] {
	set hostkeytype "hashed"
    } else {
	set hostkeytype "clear"
    }

    switch -exact $mode {
	edit {
	    
	    Window show .top50
	    $widget(knownhosts) delete 0 end

	    if { ! [file exists $khfile]} {
		showmessage "No $khfile found" ""
		return
	    }

	    if {$hostkeytype=="hashed"} {
		
		# handle new hashed hostkey format
		set profiles [glob -nocomplain "$env(HOME)/.secpanel/profiles/*.profile"]
		
		foreach prof [lsort $profiles] {
		    source $prof
		    catch {exec $configs(keygenbin) -F $host} ver		
		 
		    if [regexp -nocase "found" $ver] {
			$widget(knownhosts) insert end $host
		    }
		}
		
		return
		# end of handling hashed hostkeys
		
	    } else {
		
		set hosts [open $khfile r]
		while {[gets $hosts line] >= 0} {
		    lappend hl [lindex [split $line] 0]
		}
		
		if {[file size $khfile] > 0} {
		    foreach h [lsort $hl] {
			$widget(knownhosts) insert end $h
		    }
		}
		    
		close $hosts
		return
	    }
	}
	view {
	    keygen info host
	}
	export {
	    if {[selection own] != $widget(knownhosts)} {
		showmessage "No hostkey selected!" ".top50"
		return
	    }
	    set actk [$widget(knownhosts) get active]
	    set hkf [tk_getSaveFile -initialdir "$env(HOME)"]
	    if {$hkf == ""} {
		return
	    } else {
		set hkfout [open "$hkf" w]
		
		set hosts [open $khfile r]
		while {[gets $hosts line] >= 0} {
		    set kparts [split $line]
		    if {[lindex $kparts 0] == $actk} {
			puts $hkfout $line
			break
		    }
		}
		close $hosts

		close $hkfout
		return
	    }		
	}
	delete {
	    if {[selection own] != $widget(knownhosts)} {
		showmessage "No hostkey selected!" ".top50"
		return
	    }
	    set actk [$widget(knownhosts) get active]
	    if {[showconfirm "Delete $actk?" ".top50"] == 1} {

		if {$hostkeytype=="hashed"} {
		    # handle deletion of hashed hostkeys
		    if [catch {exec $configs(keygenbin) -R $actk} err] {
			showmessage $err ""
		    }
		    # end handling deletion of hashed hostkeys
		} else {

		    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 $line
			    }
			}
			close $hosts
		    }
		}
		hostkey edit
		selection clear
	    } else {
		return
	    }
	}
    }
}


proc launch_scp {} {
    global scpcode libdir
    
    if {! $scpcode} {
	source $libdir/sp_scp.tcl
	set scpcode 1
    }
    
    scpman open
}


proc insprot {nr mode} {
    global widget
    $widget([set mode]fout) delete 0 end
    $widget([set mode]fout) insert 0 $nr
}

proc keygen {mode "in_keytype {}"} {
    global env widget configs pwtextmode libdir nopass passintext kf keytype termtype
    

    # <xterm selection and params>
    set defterm 1

    if $defterm {
	set usetermver "Xterm"
    } else {
	set usetermver $configs(termver)
    }
    
    set icontag ""
    
    set configs(xtermbin) $termtype([set usetermver]_path)
    set titlepar $termtype([set usetermver]_titlepar)
    set quotepar $termtype([set usetermver]_quotepar)
    set execpar $termtype([set usetermver]_execpar)
    if {[info exists termicon] && $termicon} {
	set icontag $termtype([set usetermver]_iconpar)
    }
    # </xterm selection and params>

   
    switch -exact $mode {
	gen {
	    # comment
	    if {[.top52.fra18.ent24 get] == ""} {
		set commtag " "
	    } else {
		set commtag "-C '[.top52.fra18.ent24 get]' "
	    }

	    # file
	    array set ktfiles {"SSH1 RSA1" "identity" "SSH2 RSA" "id_rsa" "SSH2 DSA" "id_dsa"}
	    set ktfile $ktfiles($keytype)

	    set identfile "[$widget(identpath) get]"
	    if {$identfile == ""} {
		set identfile "$env(HOME)/.ssh/$ktfile"
	    }
	    set filetag "-f $identfile "

	    if [file exists $identfile] {
		if [showconfirm "$identfile exists. Overwrite?" .top52] {
		    file delete $identfile
		} else {
		    return
		}
	    }
	    
	    # pass
	    if {$nopass} {
		set passtag "-N \"\""
	    } elseif {$passintext} {
		set passtag " "
	    } elseif {[.top52.fra18.ent29 get] == ""} {
		showmessage "Please enter the password for the new key!" .top52
		return
	    } else {
		if {[.top52.fra18.ent29 get] == [.top52.fra18.ent25 get]} {
		    set passtag "-N [.top52.fra18.ent29 get] "
		} else {
		    showmessage "Password and repeated password are not the same!" .top52
		    return
		}
	    }

	    # type
	    array set ktshorts {"SSH1 RSA1" "rsa1" "SSH2 RSA" "rsa" "SSH2 DSA" "dsa"}
	    set typetag "-t $ktshorts($keytype) "
	    
	    set connstring "$configs(keygenbin) $filetag $passtag $typetag $commtag"

	    if {$passintext} {
		set kgstringt "$configs(keygenbin) $filetag $typetag $commtag"
	    } else {
		set kgstringt "$configs(keygenbin) $filetag -N ***** $typetag $commtag"
	    }

	    set runstring "exec $configs(xtermbin) $titlepar \"SecPanel ssh-keygen\" \
		    $execpar $quotepar $libdir/secpanel.wait <CONNFILE> $quotepar"

	    provrunfile term nobg $connstring $runstring

	    update_keylist
	    keygen clear

	    command_trace save "$kgstringt"
	    historyman write 4 "$identfile"
	}
	"clear" {
	    foreach ke {.top52.fra18.ent24 .top52.fra18.ent29 .top52.fra18.ent29 .top52.fra18.ent25} {
		[set ke] delete 0 end
	    }
	    $widget(identpath) delete 0 end
	    set keytype "SSH2 DSA"
	    set nopass 0
	    set passintext 0
	    set pwtextmode 0
	}
	0 {
	    set keytype "SSH2 DSA"
	    Window show .top52
	    .top52.fra18.but27 configure -image [image create photo -file $libdir/images/folder.gif]
	    update_keylist
	}
	1 {
	    if {[selection own] != $widget(keylist)} {
		showmessage "No key selected!" .top52
		return
	    }

	    set kf "$env(HOME)/.ssh/[$widget(keylist) get active]"

	    if [set pwtextmode] {
		set connstring "$configs(keygenbin) -p -f $kf"
		
		set runstring "exec $configs(xtermbin) $titlepar \"SecPanel - \
			change password for $kf\" \
			$execpar $quotepar $libdir/secpanel.wait <CONNFILE> $quotepar"

		provrunfile term bg $connstring $runstring
	    } 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
	    }

	    set chpwdstr "$configs(keygenbin) -p -f $kf -P ***** -N *****"

	    if [catch {exec $configs(keygenbin) -p -f $kf -P $oldp -N $newp1} err] {
		showmessage $err ""
		return
	    }
	    Window destroy .top20
	    command_trace save "$chpwdstr"
	}
	info {
	    if {$in_keytype != "host"} {

		if {[$widget(keylist) index end] == 0} {
		    return
		}

		if {[selection own] != $widget(keylist)} {
		    showmessage "No key selected!" .top52
		    return
		}
		set actk [$widget(keylist) get active]
		set actkfile "$env(HOME)/.ssh/$actk"
		if {! [file exists "$actkfile"]} {
		    showmessage "Keyfile not found" .top52
		    return
		}
	    } else {
		set khfile "$env(HOME)/.ssh/known_hosts"
		
		if {[$widget(knownhosts) index end] == 0} {
		    return
		}
		
		set actk [$widget(knownhosts) get active]
		
		if [file exists $khfile] {
		    if {[file size $khfile] > 0} {
			set hosts [open $khfile r]
			while {[gets $hosts line] >= 0} {
			    set kparts [split $line]
			    if {[lindex $kparts 0] == $actk} {
				set fname "$env(HOME)/.secpanel/.runfiles/hkview.[clock clicks]"
				set af [open "$fname" w]
				puts $af $line
				close $af
				set actkfile "$fname"
			    }
			}
			close $hosts
		    } else {
			showmessage "Keyfile empty" .top50
			return
		    }
		} else {
		    showmessage "Keyfile not found" .top50
		    return
		}
	    }

	    set fptext ".top19.tex17"
	    set bbtext ".top19.tex18"

	    if [file exists "$actkfile"] {
		Window show .top19

		if {$in_keytype != "host"} {
		    set kt "user key"
		} else {
		    set kt "host key"
		}

		.top19.fra22.lab23 config -text "Keyfile: $actkfile"
		.top19.fra22.lab24 config -text "Keytype: $kt"

		$fptext config -state normal
		$bbtext config -state normal

		$fptext delete 1.0 end
		$bbtext delete 1.0 end

		$fptext insert end "[exec $configs(keygenbin) -l -f $actkfile]"
		$bbtext insert end "[exec $configs(keygenbin) -B -f $actkfile]"
		
		$fptext config -state disabled
		$bbtext config -state disabled
		return
	    } else {
		showmessage "Couldn't find the public key for this identity!" .top52
		return
	    }
	}
	del {
	    if {[selection own] != $widget(keylist)} {
		showmessage "No key selected!" .top52
		return
	    }
	    
	    if [showconfirm "Really delete [$widget(keylist) get active]?" .top52] {
		file delete -force "$env(HOME)/.ssh/[$widget(keylist) get active]"
		file delete -force "$env(HOME)/.ssh/[$widget(keylist) get active].pub"
		update_keylist
	    }
	}
	chpath {
	    choosefile "" "" "" keygen
	}
	dist {
	    Window show .top53
	    specsiteupdate
	    distwizard key f
	}
    }
}

proc update_keylist {} {
    global widget env
    if [winfo exists .top52] {
	$widget(keylist) delete 0 end
    }
    if [winfo exists .top53] {
	$widget(distkeylist) delete 0 end
    }

    set keyfiles [glob -nocomplain "$env(HOME)/.ssh/*.pub"]
    foreach kf [lsort $keyfiles] {
	if [winfo exists .top52] {
	    $widget(keylist) insert end [file rootname [file tail $kf]]
	}
	if [winfo exists .top53] {
	    $widget(distkeylist) insert end [file rootname [file tail $kf]]
	}
    }
}

proc load_profile {mode} {
    global env widget noagentforward x11forward stricthost nopriv \
	verbose quiet fork gateway compress algo \
	compressval lfs rfs connwait termicon sshverconnect \
	ipverconnect askuserspec noexec

    foreach var {noagentforward x11forward stricthost nopriv \
		     verbose quiet fork gateway compress algo \
		     compressval lfs rfs connwait termicon askuserspec noexec} {
	if [info exists [set var]] {
	    unset $var
	}
    }
    
    foreach rvar {sshverconnect ipverconnect} {
	if [info exists [set rvar]] {
	    unset $rvar
	}
    }	

    if {! [info exists sshverconnect]} {
	set sshverconnect "2"
    }

    if {! [info exists ipverconnect]} {
	set ipverconnect "4"
    }

    if {$mode == "ssh"} {
	set profile [$widget(profiles) get active]
    } elseif {$mode == "specsites"} {
	set profile [retprof [$widget(specsites) get active]]
    } elseif {$mode == "scphosts"} {
	set profile [retprof [$widget(scphosts) get active]]
    }

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

    foreach f {title host user port command subsys identity cfgfile profile} {
	$widget([set f]ent) delete 0 end
	if [info exists $f] {
	    $widget([set f]ent) insert 0 [set $f]
	}
    }

    if {! [array exists lfs] && $lfs != ""} {
	set lfsnew [set lfs]
	unset lfs
	foreach listelem $lfsnew {
	    array set lfs \
		    "[lindex [split $listelem :] 0]:<TARGET-HOST>:[lindex [split $listelem :] 1] \
		    {Local forward vom old Version of SecPanel}"
	}
    }

    if {[winfo exists .top43]} {
	open_forwardings l
    }

    if {[winfo exists .top51]} {
	open_forwardings r
    }
}

proc manage_agent {mode "m run"} {
    global env widget configs launcher defident agent wins
    switch -exact $mode {
	"launch" {
	    
	    if {[info exists env(SSH_AGENT_PID)] && [info exists env(SSH_AUTH_SOCK)]} {
		if {[showconfirm "There seems to be another SSH-Agent. Start anyway?" ""] == 0} {
		    return
		}
	    }

	    # Start ssh-agent and read envs
	    if {! [file exists "$configs(agentbin)"] && [catch {exec which "$configs(agentbin)"}]} {
		showmessage "Can't find SSH-Agent ($configs(agentbin))\nCheck configration!" ".top17"
		changetab terminal
		return error
	    }

	    set agentout [open "| $configs(agentbin) -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

	    $widget(idents) delete 0 end

	    wm title .top17 "SecPanel - Agent active"
	    set agent 1

	    command_trace save "$configs(agentbin) -c"
	    historyman write 6 "Launching agent"
	}
	"kill" {
	    if {$m == "end" && ! $launcher && $agent == "ext"} {
		return
	    } elseif {$m == "end" && $launcher && $agent != "ext"} {
		catch {exec $configs(agentbin) -k} killerr
		unset env(SSH_AGENT_PID)
		unset env(SSH_AUTH_SOCK)
		historyman write 6 "Stopping agent"
	    } elseif {$m == "end" && $launcher && $agent == "ext"} {
		return
	    } else {
		if [info exists env(SSH_AGENT_PID)] {
		    if {$agent == "ext"} {
			showmessage "Will not kill external agent!" .top17
			return
		    }
		    if {[showconfirm "Kill SSH-agent?" ""] == 1} {
			exec $configs(agentbin) -k
			unset env(SSH_AGENT_PID)
			unset env(SSH_AUTH_SOCK)
			$widget(statusagent) config -text "No Agent" -bg red
			wm title .top17 "SecPanel - No Agent"
			$widget(idents) delete 0 end
			set agent 0

			command_trace save "$configs(agentbin) -k"
			historyman write 6 "Stopping agent"
			if [winfo exists .top33] {
			    destroyfilter .top33
			}
		    } else {
			return
		    }
		} else {
		    showmessage "No agent running" .top17
		}
	    }
	}
	"info" {
	    if {[info exists env(SSH_AGENT_PID)] && [info exists env(SSH_AUTH_SOCK)]} {
		Window show .top33

		if {[info exists configs(wingeom)] && $configs(wingeom)} {
		    if [info exists wins(agentinfo)] {
			wm geometry ".top33" $wins(agentinfo)
		    }
		}

		.top33.fra34.lab38 config -text $env(SSH_AUTH_SOCK)
		.top33.fra34.lab39 config -text $env(SSH_AGENT_PID)

		catch {exec $configs(addbin) -l} err

		command_trace save "$configs(addbin) -l"

		set text .top33.cpd36.03
		$text delete 1.0 end
		$text insert end "Fingerprints of keys contained by the running agent:\n\n"
		$text insert end $err
	    } else {
		showmessage "No agent running or\nagent environment not clean" .top17
	    }
	}
	"chdef" {
	    set defident [tk_getOpenFile -initialdir "$env(HOME)/.ssh/"]
	    if {$defident != ""} {
		save_globals chdef
		historyman write 6 "Setting default identity to $defident"
	    }
	}
	"rmdef" {
	    set defident ""
	    save_globals chdef
	    historyman write 6 "Removing default identity"
	}
	"addident" {
	    if {! [info exists env(SSH_AGENT_PID)]} {
		showmessage "No agent running" .top17
		return
	    }

	    if {($m == "start")} {
		if { $launcher && [info exists defident] && $defident != ""} {
		    showstatus "Adding default identity"
		    update idletasks
		    set fname $defident
		} else {
		    set fname ""
		}
	    } else {
		showstatus "Adding identity"
		update idletasks
		set fname [tk_getOpenFile -initialdir "$env(HOME)/.ssh/"]
	    }
	    if {$fname != ""} {
		# openssh
		if {$configs(sshver) == "OpenSSH"} {
		    set env(SSH_ASKPASS) $configs(askpassbin)
		}

		catch {exec $configs(addbin) $fname < /dev/null} err
		command_trace save "$configs(addbin) $fname < /dev/null"

		if [string match "*No such file*" $err] {
		    showmessage "Can't find your askpass program-\nCheck configuration!" .top17
		    return
		}

		if [string match "Bad key file*" $err] {
		    showmessage "Bad key file" .top17
		    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
		}
		if [winfo exists .top33] {
		    manage_agent "info"
		}
		showstatus ""
		historyman write 6 "Adding identity $fname"
	    } else {
		showstatus ""
		return
	    }
	}
	"remident" {
	    if {! [info exists env(SSH_AGENT_PID)]} {
		showmessage "No agent running" .top17
		return
	    }

	    if {[selection own] != $widget(idents)} {
		showmessage "No Identity selected" ""
		return
	    } else {
		catch {exec $configs(addbin) -d [$widget(idents) get active]}
		$widget(idents) delete active
		selection clear
		command_trace save "$configs(addbin) -d [$widget(idents) get active]"
		historyman write 6 "Removing identity [$widget(idents) get active]"
		if [winfo exists .top33] {
		    manage_agent "info"
		}
	    }
	}
    }
}

proc newconn {state} {
    changetab ssh
    clear_profiles
}

proc propconn {mode} {
    global widget
    if {[selection own] != $widget([set mode])} {
	showmessage "Please select connection" .top17
	return
    }
    if {[$widget([set mode]) index end] > 0} {
	changetab ssh
	load_profile $mode
    } else {
	showmessage "No conncections available, please use \"New\"" ""
	return
    }
}

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

proc save_profile {} {
    global env widget noagentforward x11forward stricthost nopriv verbose \
	    quiet fork gateway compress algo compressval lfs rfs \
	    connwait termicon sshverconnect ipverconnect askuserspec noexec

    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]
    if {[info exists askuserspec] && $askuserspec} {
	set user "<ASKFORUSER>"
    }
    set port [$widget(portent) get]
    set command [$widget(commandent) get]
    set subsys [$widget(subsysent) get]

    if {$title == "" || $host == ""} {
	showmessage "You must enter at least host and title" ""
	return
    }
    
    if {$subsys != "" && ($command != "" || $noexec)} {
	showmessage "The subsys-entry will be used later (has higher priority)" .top17
    }

    set identity [$widget(identityent) get]
    set cfgfile [$widget(cfgfileent) get]

    set prfile [open "$env(HOME)/.secpanel/profiles/$prname.profile" w]
    
    puts $prfile "#\n# SecPanel-Profile\n# Do not edit, use SecPanel instead\n#"
    
    foreach ent {title host user port command subsys identity cfgfile} {
	puts $prfile "set [set ent] \"[set $ent]\""
    }
    foreach bool {noagentforward x11forward stricthost nopriv verbose \
	    quiet fork gateway compress connwait termicon askuserspec noexec} {
	if [info exists [set bool]] {
	    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]\""
    }

    puts $prfile "set sshverconnect \"[set sshverconnect]\""

    puts $prfile "set ipverconnect \"[set ipverconnect]\""

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

    if [info exists rfs] {
	puts $prfile "array set rfs {[array get rfs]}"
    } else {
	puts $prfile "array set rfs {}"
    }

    close $prfile

    specsiteupdate    
    clear_prmenu
    clear_profiles
}

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


proc specsiteupdate {{mode ""}} {
    global widget env
    $widget(specsites) delete 0 end
    $widget(scphosts) delete 0 end

    if [winfo exists $widget(distconnlist)] {
	$widget(distconnlist) delete 0 end
    }

    set profiles [glob -nocomplain "$env(HOME)/.secpanel/profiles/*.profile"]

    if {$mode == "ss"} {
	if {! [winfo exists $widget(sspecsites).sspecmenu]} {
	    menu $widget(sspecsites).sspecmenu -tearoff 0 -border 1
	    $widget(sspecsites) config -menu $widget(sspecsites).sspecmenu
	} else {
	    $widget(sspecsites).sspecmenu delete 0 end
	}
    }

    foreach prof [lsort $profiles] {
	source $prof
	$widget(specsites) insert end $title
	$widget(scphosts) insert end $title
	if [winfo exists $widget(distconnlist)] {
	    $widget(distconnlist) insert end $title
	}

	if {$mode == "ss"} {
	     $widget(sspecsites).sspecmenu add command -label "$title" -command "connect ss"
	}
	
	unset lfs
    }
}

proc about {} {
    global libdir spversion
    Window show .top25
    .top25.fra26.lab21 config -text "SecPanel $spversion"
}

proc showstatus {text} {
    global widget
    $widget(status) config -text $text
    update idletasks
}

proc do_firstinit {lv} {
    global libdir spversion env
    source $libdir/convert_history.tcl
    source $libdir/convert_profile.tcl
}

proc do_exit {} {
    global env wins libdir configs

    foreach f [glob -nocomplain "$env(HOME)/.secpanel/.runfiles/*"] {
	file delete -force $f
    }

    if {[info exists env(SSH_AGENT_PID)] && [info exists env(SSH_AUTH_SOCK)]} {
	manage_agent kill "end"
    }

    foreach {winn winnr} {base .top17 trace .top24 scp .top34 sat .top27 agentinfo .top33 hist .top26} {
	if [winfo exists $winnr] {
	    set wins($winn) [wm geometry $winnr]
	}
    }

    save_globals "geom"

    # spdata
    if [set configs(protectdata)] {
	exec $libdir/dppw.tcl "en"
    }

    destroyfilter .top17

    exit
}

proc destroyfilter {win} {
    global wins
    foreach {winn winnr} {base .top17 trace .top24 scp .top34 sat .top27 agentinfo .top33 hist .top26} {
	if {$win == $winnr} {
	    set wins($winn) [wm geometry $win]
	}
    }
    Window destroy $win
}

proc main {argc argv} {
    global widget env configs libdir spversion launcher agent termtype

    wm protocol .top17 WM_DELETE_WINDOW do_exit

#    bind .top17 <Destroy> {
#        do_exit
#    }

    foreach f {ssh keygen agent add askpass scp browser} {
	$widget([set f]ent) insert 0 "$configs([set f]bin)"
    }
    foreach b {connects scp profiles keys configs sscreen} {
	$widget([set b]but) config -image \
		[image create photo -file $libdir/images/[set b]_gr.gif]
    }

    source $libdir/termdefs

    foreach k [array names termtype] {
	if [string match "*_path" $k] {
	    set termname [string replace $k [string first "_" $k] end]
	    set termpath $termtype($k)
	    if {! [catch {exec which "$termpath"}]} {
		.top17.fra44.fra19.fra32.fra38.men40.01 add radiobutton \
		    -value "$termname" -variable "configs(termver)" -label "$termname"
	    } else {
		.top17.fra44.fra19.fra32.fra38.men40.01 add radiobutton \
		    -value "$termname" -variable "configs(termver)" -label "$termname (not found)" \
		    -state "disabled"
	    }
	}
    }

    set lv 0

    if [file exists "$env(HOME)/.secpanel/.init"] {
	set vf [open "$env(HOME)/.secpanel/.init" r]
	set lv [read $vf]

	if {[string equal $spversion $lv] != 1} {
	    do_firstinit $lv
	    exec echo -n $spversion > $env(HOME)/.secpanel/.init
	}
	close $vf
    } else {
	exec echo -n $spversion > $env(HOME)/.secpanel/.init
    }

    menu .mc1 -tearoff 0 -borderwidth 1


    if {! [catch {exec which "cssh"}]} {
	.mc1 add command -label "ClusterSSH" -command "multiconnect cssh"
    } else {
	.mc1 add command -label "ClusterSSH (not found)" -command "multiconnect cssh" -state "disabled"
    }

    if {! [catch {exec which "multixterm"}]} {
	.mc1 add command -label "Multi Xterm" -command "multiconnect multixterm"
    } else {
	.mc1 add command -label "Multi Xterm (not found)" -command "multiconnect multixterm" -state "disabled"
    }

    bind .top17.fra46.fra26.fra29.fra36.but38 <Button> {
	tk_popup .mc1 [winfo pointerx .top17] [winfo pointery .top17]
    }

    clear_prmenu
    clear_profiles
    specsiteupdate

    if {[info exists env(SSH_AGENT_PID)] && [info exists env(SSH_AUTH_SOCK)]} {
	$widget(statusagent) config -text "Agent active (external)" -bg green -fg black
	wm title .top17 "SecPanel - Agent active (external)"
	historyman write 6 "Accepted external agent"

	set initagentout [open "| ssh-add -L" r]
	while {[gets $initagentout line] >= 0} {
	    if [string match "The agent has no identities*" $line] {
		continue
	    }
	    $widget(idents) insert end [lindex [split $line] 2]
	}

	set agent "ext"
    } else {
	$widget(statusagent) config -text "No Agent" -bg red
	wm title .top17 "SecPanel - No agent"
    }


    if {$launcher} {
	if {[manage_agent launch] != "error"} {
	    manage_agent addident "start"
	}
    }

    if {[info exists configs(startsat)] && $configs(startsat)} {
	changetab small
    }

}

source $libdir/gui.tcl

if {[info exists configs(wingeom)] && $configs(wingeom)} {
    if [info exists wins(base)] {
	wm geometry ".top17" $wins(base)
    }
}

foreach b {.top17.fra44.fra19.fra20.but23 .top17.fra44.fra19.fra26.03 \
	       .top17.fra44.fra19.fra27.03 .top17.fra44.fra19.fra28.03 \
	       .top17.fra44.fra19.fra29.03 \
	       .top17.fra44.fra19.fra30.03 .top17.fra21.fra24.but22 \
	       .top17.fra21.fra24.but23 .top17.fra44.fra19.fra18.03 \
	       } {
    $b configure -image [image create photo -file $libdir/images/folder.gif]
}

main $argc $argv
