##################################################################
# SecPanel
#
# Secure copy (SCP) related code
##################################################################

proc scptransfer {mode} {
    global env widget configs scpurl libdir

    set scptransfer "$env(HOME)/.secpanel/.runfiles/scptransfer.[clock clicks]"

    set dlr $widget(scpdirsr)
    set flr $widget(scpfilesr)
    set dll $widget(scpdirsl)
    set fll $widget(scpfilesl)

    set lactdir [.top34.fra35.ent45 get]
    set ractdir [.top34.fra37.ent44 get]

    switch -exact $mode {
	cptoremote {
	    if {[selection own] == $dll} {
		set rectag " -r "
		set lr $dll
	    } elseif {[selection own] == $fll} {
		set rectag ""
		set lr $fll
	    } else {
		showmessage "No files or directories selected on the local site" .top34
		return
	    }
	}
	cptolocal {
	    if {[selection own] == $dlr} {
		set rectag " -r "
		set lr $dlr
	    } elseif {[selection own] == $flr} {
		set rectag ""
		set lr $flr
	    } else {
		showmessage "No files or directories selected on the remote site" .top34
		return
	    }
	}
    }
    
    foreach cs [$lr curselection] {
	lappend resslist [$lr get $cs]
    }
    
    array set bools {
	"scpstats" "-q" \
		"scppres" "-p" \
		"scpverb" "-v" \
		"scpcomp" "-C"
    }

    foreach f [array names bools] {
	if [set configs($f)] {
	    set [set f]_tag "$bools($f) "
	} else {
	    set [set f]_tag " "
	}
    }

    if [info exists configs(scpport)] {
	if {$configs(scpport) != "" && $configs(scpport) != 22} {
	    set porttag " -P $configs(scpport) "
	} else {
	    set porttag ""
	}
    }

    if {$configs(sshver) == "OpenSSH"} {
	set progtag " -S $configs(sshbin) "
    } else {
	set progtag ""
    }

    set transferfile [open "$scptransfer" w]

    set scpstring1 "$configs(scpbin) $progtag $porttag $scpstats_tag $scppres_tag $scpverb_tag $scpcomp_tag $rectag "
    puts -nonewline $transferfile $scpstring1

    regsub -all " " $ractdir "\\ " rpad1
    regsub -all "\\(" $rpad1 "\\(" rpad2
    regsub -all "\\)" $rpad2 "\\)" rpad

    regsub -all " " $lactdir "\\ " lpad1
    regsub -all "\\(" $lpad1 "\\(" lpad2
    regsub -all "\\)" $lpad2 "\\)" lpad

    foreach r $resslist {
	if {$mode == "cptolocal"} {
	    regsub -all " " $r "\\ " rp1
	    regsub -all "\\(" $rp1 "\\(" rp2
	    regsub -all "\\)" $rp2 "\\)" rp
	    set scpstring2 "\"$scpurl:$rpad/$rp\" "
	    puts -nonewline $transferfile $scpstring2
	} else {
	    set scpstring2 "\"$lactdir/$r\" "
	    puts -nonewline $transferfile $scpstring2
	}
    }
    
    if {$mode == "cptolocal"} {
	set scpstring3 " \"$lactdir\""
	puts $transferfile $scpstring3
    } else {
	set scpstring3 " \"$scpurl:$rpad\""
	puts $transferfile $scpstring3
    }

    close $transferfile
    exec chmod +x "$scptransfer"
    
    if {$configs(termver) == "GNOME-Term"} {
	set quotepar "\""
    } else {
	set quotepar ""
    }

    set cf "$scptransfer-run"
    set connfile [open $cf w]

    set connstring "exec $configs(xtermbin) -e $quotepar $libdir/secpanel.wait \"$scptransfer\" $quotepar &"
    puts $connfile $connstring
    close $connfile
    exec chmod +x $cf
    exec $cf &

    command_trace save "$scpstring1$scpstring2$scpstring3"

    if {$mode == "cptolocal"} {
	historyman write 3 "$scpurl -> Local"
    } else {
	historyman write 3 "Local -> $scpurl"
    }
}

proc scpAuth {sock} {
    global pass

    gets $sock passandport

    set serverpass [lindex [split $passandport] 1]

    if {$serverpass != $pass} {
	close $sock
	showmessage "Wrong authentication from remote ListServer\nHad to reject connection" .top17
	return
    } else {
	close $sock
	scpman opengui
    }
}

proc Accept {sock addr port} {
    global pass

    fconfigure $sock -buffering line
    fileevent $sock readable "scpAuth $sock"
}

proc scptools {tool side} {
    global widget scplister configs scpurl

    set actdirl "[.top34.fra35.ent45 get]"
    set actdirr "[.top34.fra37.ent44 get]"

    set dlr $widget(scpdirsr)
    set flr $widget(scpfilesr)
    set dll $widget(scpdirsl)
    set fll $widget(scpfilesl)

    set ltext "local"
    set rtext "remote"

    switch -exact $tool {
	mkdir {

	    set newdir [askforuser md]
	    if {$newdir == "#####"} {
		return
	    }

	    switch -exact $side {
		l {
		    file mkdir "[set actdir[set side]]/$newdir"
		}
		r {
		    puts $scplister "++MakeDir [set actdir[set side]]/$newdir"
		}
	    }
	    scpswitchdir ent [set side]
	}
	delete {
	    if {[selection own] == [set dl[set side]]} {
		set lr [set dl[set side]]
	    } elseif {[selection own] == [set fl[set side]]} {
		set lr [set fl[set side]]
	    } else {
		showmessage "No files or directories selected on the [set [set side]text] site" .top34
		return
	    }
	    
	    foreach cs [$lr curselection] {
		lappend resslist "[set actdir[set side]]/[$lr get $cs]"
	    }
	    
	    if [showconfirm "Really delete $resslist?" ""] {
		switch -exact $side {
		    l {
			foreach f $resslist {
			    if {[catch {file delete $f} err] > 0} {
				showmessage "$err" .top34
			    }
			}
		    }
		    r {
			foreach f $resslist {
			    puts $scplister "++DelFile $f"
			}
		    }
		}
		scpswitchdir ent [set side]
	    }
	}
	list {
	    set text .top47.cpd48.03
	    Window show .top47
	    $text delete 1.0 end

	    if $configs(scpshowhidden) {
		set ls "la"
	    } else {
		set ls "l"
	    }

	    switch -exact $side {
		l {
		    if $configs(scpshowhidden) {
			set ls "la"
		    } else {
			set ls "l"
		    }
		    $text insert end "Contents of $actdirl\n\n"
		    update idletasks
		    set fl [open "| ls -$ls [quote_space $actdirl]" r]
		    while {[gets $fl line] >= 0} {
			$text insert end "$line\n"
		    }
		    close $fl
		}
		r {
		    $text insert end "Contents of $scpurl:$actdirr\n\n"
		    update idletasks
		    puts $scplister "++Listing$ls $actdirr"
		    while 1 {
			gets $scplister line
			if {$line == "+++++"} {
			    break
			}
			$text insert end "$line\n"
		    }
		}
	    }
	}
    }
}

proc scpman {mode} {
    global widget configs libdir env scplister scpurl controlserver pass spversion wins

    switch -exact $mode {
	"open" {
	    
	    if {[ $widget(scphosts) index end] <= 0} {
		showmessage "Please configure a new connection. There are no hosts to connect to!" .top17
		return
	    }
	    
	    if {[selection own] != $widget(scphosts)} {
		showmessage "Please select connection" .top17
		return
	    }

	    set actconn [retprof [$widget(scphosts) get active]]
	    source "$env(HOME)/.secpanel/profiles/$actconn.profile"

	    if {$user == "<ASKFORUSER>"} {
		set user [askforuser]
		if {$user == "#####"} {
		    return
		}
	    }

	    set scpurl "$user@$host"

	    # Launching Control-Server in SecPanel
	    if [info exists controlserver] {
		close $controlserver
	    }
	    set controlserver [socket -server "Accept" -myaddr 127.0.0.1 $configs(controllocalport)]
	    fconfigure $controlserver -buffering line

	    showstatus "Waiting for ListServer-Callback"

	    # Generating a password
	    set pass [expr {int(rand() * 1000 * [pid])}][expr {int(rand() * 1000 * [pid])}]

	    # Launching listserver on remote site
	    set lf [open "$libdir/listserver.[set configs(lsinterpret)]" r]
	    set currlf [open "$env(HOME)/.secpanel/.listserver.[set configs(lsinterpret)]" w]
	    while {[gets $lf line] >= 0} {
		if [regsub {<PASS-XXXXX>} $line $pass out] {
		    puts $currlf $out
		    continue
		}
		if [regsub {<listserverport-XXXXX>} $line $configs(listserverport) out] {
		    puts $currlf $out
		    continue
		}
		if [regsub {<controlremoteport-XXXXX>} $line $configs(controlremoteport) out] {
		    puts $currlf $out
		    continue
		}
		puts $currlf $line
	    }
	    close $currlf
	    close $lf

	    if [set configs(lsverbose)] {
		set lsverbosetag "-v"
	    } else {
		set lsverbosetag " "
	    }

	    if [info exists configs(scpport)] {
		if {$configs(scpport) != "" && $configs(scpport) != 22} {
		    set porttag " -p $configs(scpport) "
		} else {
		    set porttag ""
		}
	    }

	    switch -regexp $configs(termver) {
		"GNOME-Term" {
		    set titlepar "-t"
		    set quotepar "\""
		    if {[info exists termicon] && $termicon} {
			set icontag "-iconic"
		    }
		}
		"KDE-Term" {
		}
		"Xterm|Rxvt|Aterm" {
		    set titlepar "-title"
		    set quotepar ""	    
		    if {[info exists termicon] && $termicon} {
			set icontag "-iconic"
		    }
		}
		"Eterm" {
		    set titlepar "-T"
		    set quotepar ""	    
		    if {[info exists termicon] && $termicon} {
			set icontag "--iconic"
		    }
		}
	    }
	    
	    set waittag ""
	    set woption ""
	    if {[info exists configs(lswait)] && [set configs(lswait)] } {
		set waittag "$libdir/secpanel.wait"
		set woption "\'"
	    }

	    set scpf "$env(HOME)/.secpanel/.runfiles/scpconnect.[clock clicks]"
	    set scpfrun "$scpf-run"

	    set connectfile [open "$scpf" w]
	    set connectrunfile [open "$scpfrun" w]

	    puts $connectrunfile "echo -e \"SecPanel $spversion ListServer\n\nIn this shell we get a connection for establishing\na graphical file listing.\n---------------------------------------------------------\n\n\""
	    set connstring "exec $configs(xtermbin) $titlepar \"SecPanel ListServer\" \
		    -e $quotepar $waittag $woption $scpfrun $woption $quotepar"

  	    set connrunstring "$configs(sshbin) -C $lsverbosetag $porttag \
  		    -L $configs(scpguiport):127.0.0.1:$configs(listserverport) \
                    -R $configs(controlremoteport):127.0.0.1:$configs(controllocalport) \
  		    -l $user $host cat < $env(HOME)/.secpanel/.listserver.[set configs(lsinterpret)] \">\" .listserver\\; chmod +x .listserver\\; ./.listserver"


	    puts $connectfile $connstring
	    
	    puts $connectrunfile $connrunstring

	    close $connectfile
	    close $connectrunfile

	    exec chmod +x $scpf
	    exec chmod +x $scpfrun

	    exec $scpf &

	    command_trace save "$connrunstring"
	    
	    historyman write 2 "$scpurl"
	}
	"opengui" {
	    showstatus "Received CallBack from ListServer"
	    close $controlserver
	    unset controlserver

	    Window show .top34

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

	    .top34.fra46.lab47 config -text "$env(USER)@[info hostname]"
	    .top34.fra17.lab18 config -text "$scpurl"

	    .top34.fra48.but49 config -image [image create photo -file $libdir/images/arrow_right.gif]
	    .top34.fra48.but50 config -image [image create photo -file $libdir/images/arrow_left.gif]

	    if {[catch {set scplister [socket 127.0.0.1 $configs(scpguiport)]} err] > 0} {
		puts "opengui Error: $err"
	    }

	    fconfigure $scplister -buffering line
	    showstatus "Connected to ListServer"
	    puts $scplister "auth $pass"
	    
	    scplist $env(HOME) l
	    scplist "++InitListing" r
	}
	"close" {
	    puts $scplister "++CloseYourSelf"
	    close $scplister
	    destroyfilter .top34
	}
    }
}

proc scpswitchdir {y mode} {
    global widget env
    switch -exact $mode {
	l {
	    set actdir "[.top34.fra35.ent45 get]"
	    if {$y == "ent"} {
		if {$actdir == "~"} {
		    scplist "$env(HOME)" $mode
		} else {
		    scplist "$actdir" $mode
		}
		return
	    }
	}
	r {
	    set actdir "[.top34.fra37.ent44 get]"
	    if {$y == "ent"} {
		if {$actdir == "~"} {
		    scplist "++InitListing" r
		} else {
		    scplist "$actdir" $mode
		}
		return
	    }
	}
    }
    set dl $widget(scpdirs[set mode])
    set fl $widget(scpfiles[set mode])

    if {$actdir != "/"} {
	scplist "$actdir/[$dl get [$dl nearest $y]]" $mode
    } else {
	scplist "/[$dl get [$dl nearest $y]]" $mode
    }
}

proc scplist {actdir mode} {
    global widget scplister configs

    set dl $widget(scpdirs[set mode])
    set fl $widget(scpfiles[set mode])

    $dl delete 0 end
    $fl delete 0 end
    
    set pe [file split "$actdir"]
    set pl [llength $pe]
    
    if {[lindex $pe [expr $pl - 1]] == ".."} {
	set actdir "[eval file join [lrange $pe 0 [expr $pl - 3]]]"
    }
    
    if {$actdir != "/"} {
	$dl insert end ..
    }

    switch -exact $mode {
	"l" {
	    .top34.fra35.ent45 delete 0 end
	    .top34.fra35.ent45 insert 0 "$actdir"

	    if $configs(scpshowhidden) {
		set gpat "glob -nocomplain \"$actdir/.*\" \"$actdir/*\""
	    } else {
		set gpat "glob -nocomplain \"$actdir/*\""
	    }

	    foreach f [lsort [eval $gpat]] {

		if {[file tail "$f"] == ".." || [file tail "$f"] == "."} {
		    continue
		}
		if [file isdirectory "$f"] {
		    $dl insert end [file tail "$f"]
		} else {
		    $fl insert end [file tail "$f"]
		}
	    }
	}
	"r" {
	    puts $scplister "$actdir\t$configs(scpshowhidden)"
	    
	    # Catching errors from ListServer...
	    set actdir "[string trimleft [gets $scplister] "+"]"

	    .top34.fra37.ent44 delete 0 end
	    .top34.fra37.ent44 insert 0 "$actdir"

	    while 1 {
		gets $scplister line
		if {$line == "+++++"} {
		    break
		}
		if [regsub {^\+\+ } $line "" ls] {
		    $dl insert end [file tail $ls]
		} else {
		    $fl insert end [file tail $ls]
		}
	    }
	}
    }
}
