package require Tk 8.0
proc MAIN {argc argv} {
    global xf xf_image env tk_version tcl_platform tkPriv

    # DEBUG TODO
    if {[string compare windows $tcl_platform(platform)] == 0} {
	console show
    }

    puts stdout "Starting X-Files..."
    wm withdraw .
    SetWaitPointer
    set xf(A_VERSION) "2.00b1"
    set xf(mail) "xfiles@java.inf.tu-dresden.de"
    set xf_image(errorimage) [image create bitmap -data "#define error2_width 36
    #define error2_height 36
    static unsigned char error2_bits[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x08, 0xff, 0xff, 0x1f, 0x00, 0x08, 0x03, 0x00, 0x10, 0x00, 0x08, 0x05, 0x00, 0x50, 0x00, 0x08, 0x09, 0x00, 0xb0, 0x00, 0x08, 0xf1, 0xff, 0x50, 0x00, 0x08, 0x51, 0x8d, 0xb0, 0x00, 0x08, 0xb1, 0x8a, 0x50, 0x00, 0x08, 0xd1, 0x8d, 0xb0, 0x00, 0x08, 0xb1, 0x88, 0x50, 0x00, 0x08, 0x51, 0x88, 0xb0, 0x00, 0x08, 0xb1, 0x88, 0x50, 0x00, 0x08, 0x51, 0x88, 0xb0, 0x00, 0x08, 0xb1, 0x88, 0x50, 0x00, 0x08, 0x51, 0x88, 0xb0, 0x00, 0x08, 0xb1, 0x88, 0x50, 0x00, 0x08, 0xff, 0x8f, 0xb0, 0x00, 0x08, 0x00, 0x90, 0x50, 0x00, 0x08, 0x00, 0xa0, 0xb0, 0x00, 0x08, 0x00, 0xc0, 0x50, 0x00, 0xf8, 0xff, 0xff, 0xb0, 0x00, 0x10, 0x00, 0x00, 0x50, 0x00, 0x20, 0x00, 0x00, 0xb0, 0x00, 0xc0, 0xff, 0xff, 0x5f, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };"]

    set xf_image(topimage) [image create bitmap -data "#define top_width 16
    #define top_height 16
    #define top_x_hot 8
    #define top_y_hot 5
    static unsigned char top_bits[] = {
	0xfe, 0xff, 0xfe, 0xff, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };"]
    set xf_image(bottomimage) [image create bitmap -data "#define bottom_width 16
    #define bottom_height 16
    #define bottom_x_hot 8
    #define bottom_y_hot 10
    static unsigned char bottom_bits[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0xfe, 0xff, 0xfe, 0xff
    };"]
    set xf_image(swap) [image create bitmap -data "#define swap2_width 26
    #define swap2_height 11
    static unsigned char swap2_bits[] = {
	0xff, 0xcf, 0xff, 0x03, 0x21, 0x48, 0x10, 0x02, 0x31, 0x00, 0x30, 0x02, 0xf9, 0xff, 0x71, 0x02, 0x3d, 0x00, 0xf0, 0x02, 0xff, 0xff, 0xff, 0x03, 0x3d, 0x00, 0xf0, 0x02, 0x39, 0xfe, 0x7f, 0x02, 0x31, 0x00, 0x30, 0x02, 0x21, 0x48, 0x10, 0x02, 0xff, 0xcf, 0xff, 0x03
    };"]
    set xf_image(c_left) [image create bitmap -data "#define left3_width 13
    #define left3_height 13
    static unsigned char left3_bits[] = {
	0xff, 0x0f, 0x01, 0x08, 0x41, 0x08, 0x61, 0x08, 0x71, 0x00, 0xf9, 0x1f, 0xfd, 0x1f, 0xf9, 0x1f, 0x71, 0x00, 0x61, 0x08, 0x41, 0x08, 0x01, 0x08, 0xff, 0x0f
    };"]
    set xf_image(c_right) [image create bitmap -data "#define right3_width 13
    #define right3_height 13
    static unsigned char right3_bits[] = {
	0xfe, 0x1f, 0x02, 0x10, 0x42, 0x10, 0xc2, 0x10, 0xc0, 0x11, 0xff, 0x13, 0xff, 0x17, 0xff, 0x13, 0xc0, 0x11, 0xc2, 0x10, 0x42, 0x10, 0x02, 0x10, 0xfe, 0x1f
    };"]

	
    if {$argc > 3} {
	puts stderr "Syntax: X-Files \[-iconify\] \[left_startupdir \[right_startupdir\]\]"
	exit 0
    }
    CreateLog "left"
    CreateLog "right"
    if {[info exists env(XF_HOME)]} {
	set xf(xf_home) [string trimright $env(XF_HOME) /]/
    } {
	set xf(xf_home) [TildeSubst $xf(xf_home)]
    }
    set xf(user_home) [TildeSubst [file join ~ .x-files]]
    #set xf(user_home) [TildeSubst [file join F:/ .x-files]]
    if {![file exists $xf(user_home)]} {
	file mkdir [list $xf(user_home)]
	#if [catch {eval exec mkdir -p -m 0755 -- [list $xf(user_home)]}] {
	    #MakeDirProc $xf(user_home)
        #}
    }
    ReadResources
    SetExternalCommands
    
    frame .xfiles
    set tmp [option get .xfiles messagelog_file {}]
    if {[string compare {} $tmp] == 0} {
	set xf(log_file) $xf(user_home)xfLog.1
    } {
	set xf(log_file) [file join [TildeSubst [file dirname $tmp]] [file tail $tmp]]
    }
    
    MenuBar
    # Load settings, 
    # this has to be _after_ creating the menubar
    LoadSettings
    # if async mode on, disable turbo entry
    set xf(turbo_bu) $xf(turbomode)
    if {$xf(async_fo)} {
	set xf(turbomode) 1
	.xfmenu.butt.m entryconfigure Turbo* -state disabled
    }	

    set xf(trashdir) [TildeSubst [option get .xfiles trash_dir {}]]xf_foolproof/
    #puts $xf(trashdir)
    if {![file exists $xf(trashdir)]} {
	file mkdir [list $xf(trashdir)]
	#if [catch {eval exec mkdir -p -m 0700 -- [list $xf(trashdir)]}] {
	    #MakeDirProc $xf(trashdir)
	#}
    }
    set xf(actionbuttons_file) [LoadConfigFile "xfiles.buttons"]
    set xf(extensions_file) [LoadConfigFile "xfiles.extensions"]
    set xf(tag_file) [LoadConfigFile "xfiles.tags"]
    set xf(headers_file) [LoadConfigFile "xfiles.headers"]
    set xf(user_pophelp_file) [LoadConfigFile "xfiles.user_pophelp" 0]
    set xf(ftpbook_file) [LoadConfigFile "xfiles.ftpbook"]
    foreach s [list "left" "right"] {
	NullSelect $s
	set xf(fsmode_$s) 0
	set xf(smode_$s) 0
	.log$s.t config -font [option get .xfiles log_font {}]
	SetPaths $s [option get .xfiles startup_dir_$s {}]
	set xf(hiddens_$s) [option get .xfiles hidden_files_$s {}]
	set xf(mask$s) *
	set xf(sortby_$s) $xf(sortby)
	set xf(sortorder_$s) $xf(sortorder)
	set xf(no_aud_$s) 0
    }
    ParseArgs
    foreach s [list "left" "right"] {
	if {![file isdirectory $xf(pathi$s)]} {
	    MessageBox "Invalid $s startup path\n$xf(pathi$s) !!" $s
	    SetPaths $s $env(HOME)
	}
    }
    set xf(main_pophelp_file) [file join $xf(xf_home) xfiles.main_pophelp]
    set xf(helpmode) 0
    set xf(editmode) 0
    set xf(editbutton) .xfright.bf(0).f(0).b(0)
    set xf(clearselect) 0
    set xf(buttonset1) [option get .xfiles button_set_1 {}]
    set xf(buttonset2) [option get .xfiles button_set_2 {}]
    set xf(buttonset3) [option get .xfiles button_set_3 {}]
    set xf(buttonset4) [option get .xfiles button_set_4 {}]
    set xf(button_cols) [option get .xfiles button_cols {}]
    set xf(highlightthicknes) [option get .xfiles button_spacing {}]
    set xf(reg) "<UNREGISTERED>"
    set xf(reversi) [option get .xfiles pack_order_reverse {}]
    set xf(mb) 1
    set xf(outwin_num) 0
    set xf(do_backup) [option get .xfiles fileselector_make_backup {}]
    set xf(autofocus) [option get .xfiles focus_follows_mouse {}]

    # get user email address
    set xf(user_email) [option get .xfiles user_email {}]
    if {[string compare $xf(user_email) {}] == 0 || \
	    [string compare {Please@Configure.me} $xf(user_email)] == 0} {
	if {[info exists env(USER)]} {
	    set xf(user_email) "$env(USER)@[info hostname]"
	} elseif {[info exists env(USERNAME)]} {
	    set xf(user_email) "$env(USERNAME)@[info hostname]"
	} elseif {[info exists env(LOGNAME)]} {
	    set xf(user_email) "$env(LOGNAME)@[info hostname]"
	} {
	    set xf(user_email) "Please@Configure.me"
	}
    }
    set xf(leftautoud) [file mtime $xf(pathileft)]
    set xf(rightautoud) [file mtime $xf(pathiright)]
    set xf(noinfo) 0
    set xf(te_on) 0
    set xf(be_on) 0
    set xf(ee_on) 0
    set xf(re_on) 0
    set xf(fae_on) 0
    set xf(b2r) 0
    set xf(b1r) 0
    set xf(b1e) 0
    set xf(sb1) 0
    set xf(screen) 0
    set xf(screen.active) 0
    set tkPriv(xf_line) 1
    if {[set xf(peekheader) [option get .xfiles peek_file_header {}]] == ""} {
	set xf(peekheader) 1
    }
    set xf(do_list_0) {}
    set xf(do_list_4) {}
    # TODO new resources, remember also the colors!!
    set xf(confirmVFSexit) [option get .xfiles confirm_vfs_exit {}]
    set xf(history_len) [option get .xfiles history_menu_length {}]

    # FTP vars
    set xf(ftp.update) 0
    set xf(ftp.shortlist) 0
    set xf(ftp.chunk) [option get .xfiles ftp_chunk {}]
    set xf(ftp.doendmessage) [option get .xfiles ftp_show_endmessage {}]
    set xf(ftp.doendcommand) [option get .xfiles ftp_do_endcommand {}]
    set xf(ftp.endcommand) [option get .xfiles ftp_endcommand {}]

    after idle LoadUndo
    if {$xf(button_cols) < 1} {set xf(button_cols) 1}
    if {$xf(button_cols) > 6} {set xf(button_cols) 6}
    set xf(history_0) {}

    frame .ff -bg #c9c9c9
    set xf(fuf) .ff
    #FileWindow .ff
    FileFrame .ff -exportselection false -relief ridge \
	    -wrap none -cursor top_left_arrow -setgrid 1 -width 40
    # save default text attributes
    set xf(text.attr) "-font \{[$xf(fuf).leftlist cget -font]\} -fg \{[$xf(fuf).leftlist cget -fg]\} -bg \{[$xf(fuf).leftlist cget -bg]\}"

    ColumnHeaders left
    ColumnHeaders right
    MakeTagMatch

    frame .xfleft -relief sunken -bd 2
    frame .xfright -relief sunken -bd 2
    ButtonFrame 0 {L} {.xfleft}
    ButtonFrame 1 {R} {.xfright}
    ButtonFrame 2 {L} {.xfleft}
    ButtonFrame 3 {R} {.xfright}
    ButtonFrame 4 {L} {.xfleft}
    ButtonFrame 5 {R} {.xfright}
    ButtonFrame 6 {L} {.xfleft}
    ButtonFrame 7 {R} {.xfright}
    ButtonFrame 8 {L} {.xfleft}
    ButtonFrame 9 {R} {.xfright}
    ButtonFrame 10 {L} {.xfleft}
    ButtonFrame 11 {R} {.xfright}
    ButtonFrame 12 {L} {.xfleft}
    ButtonFrame 13 {R} {.xfright}
    ButtonFrame 14 {L} {.xfleft}
    ButtonFrame 15 {R} {.xfright}

    if {$xf(reversi) == 0} {
	set b "bottom"
	set t "top"
    } {
	set b "top"
	set t "bottom"
    }
    pack .xfiles -side $t -fill x
    pack .ff -side $b -expand true -fill both
    pack .xfleft -side left -expand true -fill both -in .xfiles
    pack .xfright -side right -expand true -fill both -in .xfiles

    for {set i 0} {$i < 8} {incr i} {
	if {$xf(linz[expr {$i+1}]) == 1} {
	    pack .xfleft.bf([expr {2 * $i}]) -side bottom -expand true -fill x
	    pack .xfright.bf([expr {2 * $i +1}]) -side bottom -expand true -fill x
	}
    }

    #$xf(pathEnt_left) xview moveto 1
    #$xf(pathEnt_left) icursor end
    #$xf(pathEnt_right) xview moveto 1
    #$xf(pathEnt_right) icursor end
    Bindings

    if {[catch {set site " on [info hostname]"}]} {
	if {[catch {set site " on $env(HOSTNAME)"}]} {
	    set site ""
	}
    }
    wm title . "X-Files $xf(A_VERSION)$site"
    #wm geometry . [option get .xfiles geometry {}]
    if {!$xf(iconify)} {
	wm deiconify .
	if {$tk_version < 8.0} {
	    tkwait visibility $xf(fuf).rightlist
	}
    } {
	wm iconify .
    }
    wm protocol . WM_DELETE_WINDOW {Confirm_exit}
    set xf(redrawleft) 0
    set xf(redrawright) 0
    after idle [list UpdateListbox "left"]
    after idle [list UpdateListbox "right"]

    if {$xf(mailmsgbox) == 1} {
	.xfmenu.butt.m.mail entryconfigure Read* -state disabled
    }
    if {![info exists env(MAIL)]} {
	set xf(mailtime) 0
	set xf(mailatime) 0
	set xf(mailchk) 0
	.xfmenu.butt.m entryconfigure Mail* -state disabled
	LogBoth "Could not find mailbox, disabling MailCheck-feature!\n \[No variable env(MAIL)\]" 1
    } elseif {![file exists $env(MAIL)] || \
	    [catch {set xf(mailtime) [file mtime $env(MAIL)]}]} {
	set xf(mailtime) 0
	set xf(mailatime) 0
	MailChk
    } {
	set xf(mailatime) [file atime $env(MAIL)]
	if {$xf(mailchk) == 1} {
	    MailChk
	} {
	    .xfmenu.butt.m.mail entryconfigure Messa* -state disabled
	    .xfmenu.butt.m.mail entryconfigure Read* -state disabled
	}
    }
    # MKi 13.1.98
    if {[file exists /proc/meminfo] \
	    && [string compare Linux $tcl_platform(os)] == 0} {
	.xfmenu.butt.m.sub1 entryconfigure Mem* -state normal
    } {
	set xf(memenable) 0
	.xfmenu.butt.m.sub1 entryconfigure Mem* -state disabled
    }
    titletime
    titlemem
    after 1000 [list CheckErrorSize]
    after 1000 [list CheckTrashDevice]
    unset xf(reversi) xf(iconify)
    if {$xf(autoupdate) == 1} {AutoUD}
    set xf(config_menu_bg) [.xfmenu.config cget -bg]
    set xf(config_menu_abg) [.xfmenu.config cget -activebackground]
    SetArrowPointer

    after idle Packages
    #if {$tk_version >= 8.0} {
	wm geometry . [option get .xfiles geometry {}]
    #}
    update idletasks
}

proc DEBUG {str} {
    global xf
    if {$xf(debug)} {
	puts "DEB: $str"
    }
}

proc LoadSettings {} {
    global xf
    
    # set defaults TODO
    set xf(mailchk) 1
    set xf(mailmsgbox) 1
    set xf(r_mail_on_ack) 0
    set xf(memenable) 1
    set xf(timeenable) 1
    set xf(turbomode) 0
    set xf(async_fo) 1
    set xf(safedelete) 1
    set xf(log) 1
    set xf(log2file) 0
    set xf(autoupdate) 1
    set xf(sortby) 0
    set xf(sortorder) "increasing"
    set xf(links) 0
    set xf(MMB_opens_other) 0
    set xf(debug) 0
    
    # the button lines
    set xf(linz1) 1
    set xf(linz2) 1
    set xf(linz3) 1
    set xf(linz4) 1
    set xf(linz5) 1
    set xf(linz6) 0
    set xf(linz7) 0
    set xf(linz8) 0
    
    # column configuration
    set xf(cf.name) {3 20 1}
    set xf(cf.size) {2 9 0}
    set xf(cf.mtim) {1 15 1}
    # MKi Virtuals in Windows require longer field, lets use the same
    #if [string match {unix} $tcl_platform(platform)] {
	set xf(cf.prot) {0 10 0}
    #} {
    #    set xf(cf.prot) {0 4 0}
    #}	    
    set xf(cf.owne) {0 9 1}
    set xf(cf.grou) {0 9 1}
    set xf(cf_name_case) 0
    
    # load user saved
    if {[file exists "$xf(user_home)xfiles.settings"]} {
	source "$xf(user_home)xfiles.settings"
    }

    # Create the actual format clause
    MakeColumnFormat left
    MakeColumnFormat right
}
proc SaveSettings {} {
    global xf
    set fh [open [file join $xf(user_home) xfiles.settings] w]
    puts $fh "# X-Files settings, use menuitem 'File/Save settings' to create this"
    puts $fh "set xf(turbomode) $xf(turbomode)"
    puts $fh "set xf(async_fo) $xf(async_fo)"
    puts $fh "set xf(autoupdate) $xf(autoupdate)"
    puts $fh "set xf(links) $xf(links)"
    puts $fh "set xf(MMB_opens_other) $xf(MMB_opens_other)"
    puts $fh "set xf(sortby) $xf(sortby)"
    puts $fh "set xf(sortorder) $xf(sortorder)"
    puts $fh "set xf(memenable) $xf(memenable)"
    puts $fh "set xf(timeenable) $xf(timeenable)"
    puts $fh "set xf(log) $xf(log)"
    puts $fh "set xf(log2file) $xf(log2file)"
    puts $fh "set xf(safedelete) $xf(safedelete)"
    puts $fh "set xf(mailchk) $xf(mailchk)"
    puts $fh "set xf(mailmsgbox) $xf(mailmsgbox)"
    puts $fh "set xf(r_mail_on_ack) $xf(r_mail_on_ack)"
    puts $fh "set xf(debug) $xf(debug)"
    puts $fh "set xf(linz1) $xf(linz1)"
    puts $fh "set xf(linz2) $xf(linz2)"
    puts $fh "set xf(linz3) $xf(linz3)"
    puts $fh "set xf(linz4) $xf(linz4)"
    puts $fh "set xf(linz5) $xf(linz5)"
    puts $fh "set xf(linz6) $xf(linz6)"
    puts $fh "set xf(linz7) $xf(linz7)"
    puts $fh "set xf(linz8) $xf(linz8)"
    foreach nn [list name size prot mtim owne grou] {
	puts $fh "set xf(cf.$nn) \{$xf(cf.$nn)\}"
    }
    puts $fh "set xf(cf_name_case) $xf(cf_name_case)"

    close $fh
    MessageBox "Settings saved!"
}
# clears current HyperList
proc ClearHyperList {} {
    global xf

    if {[AskWin "Clear HyperList: Are You Sure ?" -50 -50 {} {} {} Yes No] == 0} {
	return
    }
    if {$xf(fsmode_left) == 4 || $xf(fsmode_right) == 4} {
	set xf(do_list_4) {}
    } {
	set xf(do_list_0) {}
    }
    if {$xf(smode_left) == 3} {
	HyperList 1 left
    } elseif {$xf(smode_right) == 3} {
	HyperList 1 right
    }
}

# appends current selection to HyperList
# param s is for future, maybe a hotkey could also be used and
# side extracted there
# param show is 1, when we want to show the selection, 0 when we want to append
proc HyperList {show {s {}}} {
    global xf

    if {$show == 0} {
	set str "from which the selection will be appended."
    } {
	set str "where you want the HyperList listed."
    }
    if {[string compare $s {}] == 0} {
	# no side was given, ask
	switch [AskWin "HyperList: Define the side $str" -50 -50 "Right" {} {} "Left"] {
	    1 {
		# left
		set s left
	    }
	    2 {
		# right
		set s right
	    }
	    0 {
		# cancel
		return
	    }
	}
    }
    if {$show == 0} {
	# append selection
	foreach item [GetSelNames $s] {
	    if {[regexp {/$} $item]} {
		set new [file join $xf(pathi$s) $item]/
	    } {
		set new [file join $xf(pathi$s) $item]
	    }
	    if {[lsearch -exact $xf(do_list_$xf(fsmode_$s)) $new] == -1} {
		# not already on list
		lappend xf(do_list_$xf(fsmode_$s)) $new
	    } {
		Log $s "HyperList: item already on list '$new'" 0
	    }
	}
	DEBUG $xf(do_list_$xf(fsmode_$s))
    } {
	if {[string compare $s left] == 0} {
	    set o right
	} {
	    set o left
	}
	# show selection in list
	DEBUG "show HyperList"
	set xf(no_aud_$s) 1
	set xf(smode_$s) 3
	NullSelect $s
	FileList $s $xf(pathi$s)
	DefaultInfo $s
    }
}
# complete visual settings for HyperList mode
# TODO voiks tän tehdä toisin, nyt tulee redundanttia asetusta joka
# listauskerralla...
proc HyperListSettings {s} {
    global xf

    if {[string compare $s left] == 0} {
	set o right
    } {
	set o left
    }
    if {$xf(smode_$s) == 3} {
	# HyperList mode
	$xf(fuf).${s}list config -bg [option get .xfiles hyperlist_mode_bg {}]
	$xf(pathEnt_$s) config -relief flat -state disabled
	.ff.$s.dirroot config -state disabled
	if {$xf(fsmode_$s) == 4} {
	    # this is FTP, disable copy
	    .ff.${o}list.popup_menu entryconfig "Copy" -state disabled
	}
	.ff.${o}list.popup_menu entryconfig "Move" -state disabled
	.ff.${o}list.popup_menu entryconfig "Copy To" -state disabled
	.ff.${o}list.popup_menu entryconfig "Move To" -state disabled
    } {
	# not HyperList
	$xf(pathEnt_$s) config -relief sunken -state normal
	.ff.$s.dirroot config -state normal
	.ff.${o}list.popup_menu entryconfig "Copy" -state normal
	.ff.${o}list.popup_menu entryconfig "Move" -state normal
	.ff.${o}list.popup_menu entryconfig "Copy To" -state normal
	.ff.${o}list.popup_menu entryconfig "Move To" -state normal
    }
}

# When deleting, asks whether to delete a single file from HyperList, 
# filesystem or both
# Returns one if only from HyperList or cancel was pressed.
proc DelSingleClipFile {s file} {
    global xf

    if {$xf(smode_$s) == 3} {
	set clip [AskWin "Delete '$file' from the HyperList only or also from the filesystem?" -50 -50 "Both" {} {} "HyperList"]
	switch $clip {
	    1 -
	    2 {
		DEBUG $file
		set idx [lsearch -exact $xf(do_list_$xf(fsmode_$s)) $file]
		set xf(do_list_$xf(fsmode_$s)) [lreplace $xf(do_list_$xf(fsmode_$s)) $idx $idx]
		if {$clip == 1} {
		    # HyperList only
		    return 1
		}
	    }
	    0 {
		# cancel
		return 1
	    }
	}
    }
    return 0
}

proc LoadUndo {} {
    global xf
    # load undo
    if {[file exists "$xf(user_home)xfiles.undopath"]} {
	set fh [open "$xf(user_home)xfiles.undopath" r]
	set xf(undopath) [gets $fh]
	close $fh
	.xfmenu.butt.m.del entryconfigure Undo* -state normal
    }
    # load history
    if {[file exists "$xf(user_home)xfiles.history"]} {
	set fh [open "$xf(user_home)xfiles.history" r]
	set xf(history_0) [gets $fh]
	close $fh
    }
}
proc SaveUndo {} {
    global xf
    if {[catch {set fh [open [file join $xf(user_home) xfiles.undopath] w]} err]} {
	MessageBox "Unable to save undo information:\n\n$err"
    } {
	puts $fh $xf(undopath)
	close $fh
    }
}
proc Packages {} {
    package require BE
    package require EE
    package require RE
    package require VFS
    package require FTP
    package require FAE
    package require XF_Dialogs
    package require BGEXEC
}
proc ParseArgs {} {
    global xf argc argv
    set xf(iconify) 0
    set cc 0
    for {set i 0} {$i < $argc} {incr i} {
	set a [lindex $argv $i]
	switch -- $a {
	    -iconify {set xf(iconify) 1}
	    default {
		if {$cc == 0} {
		    SetPaths "left" $a
		} elseif {$cc == 1} {
		    SetPaths "right" $a
		}
		incr cc
	    }
	}
    }
}
proc ReadResources {} {
    global xf

    set res1 [catch {option readfile [file join $xf(xf_home) xfilesrc] startupFile} err1]
    set res2 [catch {option readfile [file join $xf(user_home) xfilesrc] userDefault}]
    if {$res2 == 0} {
	set xf(rcfile) [file join $xf(user_home) xfilesrc]
    } {
	set xf(rcfile) [file join $xf(xf_home) xfilesrc]
    }

    if {$res1 && $res2} {
	puts stderr "Could not read either $xf(xf_home)xfilesrc or $xf(user_home)xfilesrc. Exiting...\n"
	exit
    } elseif {$res1 == 1} {
	puts stdout "X-Files startup warning: $err1\n"
    }
}
proc SetExternalCommands {} {
    global xf tcl_platform
    
    set version "-3-"
    set type _$tcl_platform(os)
    
    # TODO
    set xf(LISTRAR) {rar v -v -c- -cfg-}
    set xf(FROMRAR) {rar x -r -y -o+ -cfg-}
    set xf(TORAR) {rar u -r -y -o+ -cfg- -ol}
    #set xf(MOVETORAR) {rar m -r -y -o+ -cfg- -ol}
    set xf(DELRAR) {rar d -r -y -cfg-}
    set xf(RAROUTP) {rar e -y -o+ -cfg-}
    set xf(LISTRPMFILES) {rpm -qlp}
    set xf(LISTRPMATTRS) {rpm --dump -qlp}
    
    if {[file exists [file join $xf(user_home) xfiles.commands$type$version]]} {
	source [file join $xf(user_home) xfiles.commands$type$version]
    } {
	set pwd [pwd]
	cd $xf(user_home)
	
	# TODO: check if CMDSHELL in win can be retrieved from the env-variable
	switch -glob -- $tcl_platform(os) {

	    *NT* {set xf(CMDSHELL) { cmd.exe /c}}
	    *95* {set xf(CMDSHELL) { command.com /c}}
	    default {
		set xf(CMDSHELL) {}
		set xf(COPY) {cp -r --}
		set xf(MOVE) {mv -f --}
		set xf(DEL) {rm -rf --}
		set xf(MKDIR) {mkdir -p --}
	    }
	}
	set xf(LISTZIP) {unzip -Z}
	set xf(TOZIP) {zip -rqy}
	set xf(DELZIP) {zip -dq}
	set xf(FROMZIP) {unzip -oqq}
	set xf(ZIPOUTP) {unzip -pqq}
	set xf(LISTTAR) {tar tvf}
	set xf(TOTAR) {tar -rf}
	set xf(FROMTAR) {tar -xf}
	set xf(TAROUTP) {tar Oxf}
	set xf(LISTLHA) {lha lq}
	set xf(TOLHA) {lha aq}
	set xf(FROMLHA) {lha eqf}
	set xf(LHAOUTP) {lha pq}
	set xf(DELLHA) {lha dq}
	if {[catch {exec tar --help} foo]} {
	    catch {eval exec tar} foo
	}
	if {[regexp -nocase -- {--delete} $foo]} {
	    set xf(DELTAR) {tar --delete -f}
	    set xf(notardel) 0
	} {
	    set xf(DELTAR) {tar -f}
	    set xf(notardel) 1
	}
	if {[catch {exec df --help} foo]} {
	    set xf(DISKFREE) df
	} {
	    if {[regexp -nocase -- {--no-sync} $foo]} {
		set xf(DISKFREE) {df --no-sync}
	    } {
		set xf(DISKFREE) df
	    }
	}
	set xf(df_1k) 0
	if {[catch {eval exec df -k}] == 0} {
	    append xf(DISKFREE) " -k"
	    set xf(df_1k) 1
	}
	if {[catch {eval exec df -T}] == 0} {
	    append xf(DISKFREE) " -T"
	    set xf(df_1k) 1
	}
	if {[catch {eval exec du -sk}]} {
	    set xf(DIRSIZE) {du -s}
	    set xf(du_1k) 0
	} {
	    set xf(DIRSIZE) {du -sk}
	    set xf(du_1k) 1
	}
	set fh [open $xf(user_home)xfiles.commands$type$version w]
	puts $fh "# X-Files commands file, version $version\n# Created on [clock format [clock seconds] -format %c]\n"
	foreach i [list COPY MOVE DEL MKDIR CMDSHELL LISTZIP TOZIP DELZIP \
		FROMZIP ZIPOUTP LISTTAR TOTAR FROMTAR TAROUTP DELTAR \
		notardel DISKFREE df_1k DIRSIZE du_1k LISTLHA TOLHA DELLHA FROMLHA LHAOUTP] {
	    puts $fh "set xf($i) \{$xf($i)\}"
	}
	close $fh
	
	cd $pwd
    }
}
proc ColumnSort {s sortby bind} {
    global xf

    # if name, check if user wants case sensitive or insensitive
    #puts "sort: [. config -bg]"
    # TODO windows default color is SystemButtonFace ?!?!?
    set bg [. cget -bg]
    #puts $bg
    if {[string match {\#*} $bg]} {
	set bg [string range $bg 1 end]
	for {set i 1} {$i < 8} {incr i} {
	    $xf(fuf).${s}header.f.$i config -bg #$bg
	}
	set bg [expr 0x$bg - 0x202020]
	#puts $bg
	$xf(fuf).${s}header.f.$bind config -bg #[format "%X" $bg]
    }
    if {$sortby == 0} {
	incr sortby $xf(cf_name_case)
    }
    if {$xf(sortby_$s) == $sortby} {
	# same, change direction
	# TODO mites Name ja nameIcase
	if {[string compare increasing $xf(sortorder_$s)] == 0} {
	    set xf(sortorder_$s) decreasing
	} {
	    set xf(sortorder_$s) increasing
	}
    } {
	# no, new
	set xf(sortby_$s) $sortby
	set xf(sortorder_$s) increasing
    }
    set xf(redraw$s) 1
    UpdateListbox $s
}
proc ColumnHeaders {s} {
    global xf tags

    regexp {^.*\"([^\"]*)\"(.*)\]$} $xf(cf_$s) gfg form attr
    set ind 1
    set c $xf(fuf).${s}header
    set f $c.f
    grid configure $f.1 $f.2 $f.3 $f.4 $f.5 $f.6 $f.7
    set ind [lsearch -exact $tags(DEFAULT.attr) -font]
    if {$ind > -1} {
	# if DEFAULT tag has font defined, use that
	incr ind
	set font [lindex $tags(DEFAULT.attr) $ind]
    } {
	# if not, use default text widget font
	set font [lindex $xf(text.attr) 1]
    }
    foreach len $form item $attr {
	regexp {^%[-+]*([0-9]+)s$} $len gfg l
	incr l 1
	switch [string range $item 1 end] {
	    name {
		#$f.$ind config -width 3 -text Ext -command [list ColumnSort $s 1]
		#$f.[incr ind] config -width [expr $l - 3] -text " Name" -command [list ColumnSort $s 0] -anchor c
		$f.$ind config -width 16 -text Name -command [list ColumnSort $s 0 $ind] -anchor c -font $font
		incr ind
		$f.$ind config -width [expr {$l - 16}] -text Ext -command [list ColumnSort $s 1 $ind] -anchor c -font $font
		#grid columnconfigure $f [expr $ind-1] -weight 1
	    }
	    size {
		$f.$ind config -width $l -text Size -command [list ColumnSort $s 4 $ind] -anchor c -font $font
	    }
	    prot {
		$f.$ind config -width $l -text Protection -command [list ColumnSort $s 5 $ind] -anchor c -font $font
	    }
	    mtim {
		$f.$ind config -width $l -text "Mod. Time" -command [list ColumnSort $s 2 $ind] -anchor c -font $font
	    }
	    owne {
		$f.$ind config -width $l -text Owner -command [list ColumnSort $s 6 $ind] -anchor c -font $font
	    }
	    grou {
		$f.$ind config -width $l -text Group -command [list ColumnSort $s 7 $ind] -anchor c -font $font
	    }
	}
	incr ind
    }
    $f.[expr {$ind -1}] config -anchor w
    for {set i $ind} {$i < 8} {incr i} {
	grid remove $f.$i
    }
}
proc MakeColumnFormat {s} {
    global xf

    # create the column format clause
    set tmp "\[format \""
    set end ""
    for {set i 1} {$i < 7} {incr i} {
	# find items in the order they should be
	foreach nn [list name size prot mtim owne grou] {
	    if {[lindex $xf(cf.$nn) 0] == $i} {
		# column should be visible in this position
		if {[lindex $xf(cf.$nn) 2] == 1} {
		    set t "%-[lindex $xf(cf.$nn) 1]s"
		} {
		    set t "%[lindex $xf(cf.$nn) 1]s"
		}
		append tmp "$t  "
		append end " \$$nn"
		break
	    }
	}
    }
    if {[string length $tmp] > 9} {
	set tmp [string range $tmp 0 [expr {[string length $tmp]-3}]]
    }
    append tmp "\n\"$end\]"
    set xf(cf_$s) $tmp
}
proc LogBoth {text class} {
    after idle [list Log left $text $class]
    after idle [list Log right $text $class]
}
proc CheckTrashDevice {} {
    global xf tcl_platform

    if {[string compare unix $tcl_platform(platform)] == 0} {
	# do check only for Unix
	set fs [string match {*-T*} $xf(DISKFREE)]
	ExecGetDfSize $xf(DISKFREE) $xf(trashdir) fs "left"
	if {[string compare "msdos" $fs] == 0} {
	    MessageBox "Your trashdirectory is in a MSDOS-partition. Names could be truncated, disabling safedelete..."
	    set xf(safedelete) 0
	    .xfmenu.butt.m.del entryconfigure Safe* -state disabled
	}
    }
}
proc CheckErrorSize {} {
    global xf TMP env tcl_platform

    LogBoth "X-Files started on [clock format [clock seconds] -format %c]" 2
    if {[catch {set s "[file size $xf(user_home)ErrorLog] bytes"}]} {
	set s "N/A"
    }
    LogBoth "Init: size of ErrorLog: $s" 0
    set x [winfo pointerx .]
    set y [winfo pointery .]

    set errl [file join $xf(user_home) ErrorLog]
    if {[file exists $errl] \
	    && [file size $errl] > [expr 100*1024]} {
	if {[AskWin "The size of the X-Files 'ErrorLog' -file is over 100 kb.\nRemove it NOW?" -50 -50 {} $x $y Yes No]} {
	    file delete -force $errl
	    #exec rm $xf(user_home)ErrorLog
	}
    }
    if {[catch {set s "[file size $xf(log_file)] bytes"}]} {
	set s "N/A"
    }
    LogBoth "Init: size of log-file: $s" 0
    if {[file exists $xf(log_file)] \
	    && [file size $xf(log_file)] > [expr 100*1024]} {
	if {[AskWin "The size of the message log-file is over 100 kb.\nRemove it NOW?" -50 -50 {} $x $y Yes No]} {
	    file delete -force -- $xf(log_file)
	    #exec rm $xf(log_file)
	}
    }
    # since this is executed after idle, put here the creation of
    # temp dirs etc.
    if {[info exists env(TEMP)]} {
	set TMP(dir) [file join $env(TEMP) X-Files[pid]]/
    } elseif {[info exists env(TMP)]} {
	set TMP(dir) [file join $env(TMP) X-Files[pid]]/
    } {
	set TMP(dir) [file join [lindex [file split [pwd]] 0] tmp X-Files[pid]]/
    }
    # check for other tmp dirs
    foreach dir [glob -nocomplain -- [file join [file dirname $TMP(dir)] X-Files*/]] {
	if {[file owned $dir] == 1} {
	    # belongs to this user
	    LogBoth "Init: Possibly old temp directory '$dir' detected. If you do not have multiple X-Files sessions open, you can safely delete it." 1
	}
    }
    # create new
    file mkdir $TMP(dir)
    # change permissions so that no one else can access temp dir
    if {[string compare unix $tcl_platform(platform)] == 0} {
	# TODO non portable code
	file attributes $TMP(dir) -permissions 040700
    }
    # reset the temp id counter
    set TMP(idx) 0
}

proc CreateLog {s} {
    global log

    set log($s.win) [frame .log$s]
    set log($s.nrow) 1

    text .log$s.t -wrap word -relief sunken -bd 2 \
	    -padx 0 -pady 0 -bg "#404040" \
	    -yscrollcommand [list .log$s.sb set] \
	    -width 10 -height 6 -wrap char -highlightthickness 0
    scrollbar .log$s.sb -command [list .log$s.t yview] -width 8 \
	    -bg "#404040" -highlightthickness 0
    pack .log$s.sb -side $s -fill y
    pack .log$s.t -fill both -expand 1
}
proc Log {s text class} {
    global log xf

    if {$xf(log) == 1} {
	switch $class {
	    0 {set fg "yellow"}
	    1 {set fg "#ff9999"}
	    2 {set fg "#00ffff"}
	    3 {set fg "green"}
	    default {set fg "#333333"}
	}
	$log($s.win).t configure -state normal
	$log($s.win).t tag add tg.$log($s.nrow) $log($s.nrow).0 $log($s.nrow).end
	$log($s.win).t tag configure tg.$log($s.nrow) -foreground $fg
	if {[regsub -all \n $text {\ } tmp] > 0} {
	    regsub -all {\\} $tmp {} text
	}
	$log($s.win).t insert end "* $text\n" tg.$log($s.nrow)
	$log($s.win).t see end
	$log($s.win).t configure -state disabled
	incr log($s.nrow)
    }
    if {$xf(log2file) == 1} {
	after idle [list Log2File $s $text]
    }
}
proc Log2File {s text} {
    global xf
    set lh [open $xf(log_file) {WRONLY APPEND CREAT}]
    puts $lh "[clock format [clock seconds] -format %c]: [format "%-6s %s" [string toupper $s] $text]"
    close $lh
}
proc ShowLog {s} {
    global log

    if {[winfo ismapped $log($s.win)]} {
	place forget $log($s.win)
    } {
	place $log($s.win) -in .ff.${s}list -x 0 -rely 1.0 \
		-anchor sw -relwidth 1.0
	raise $log($s.win)
	update idletasks
    }
}
proc ClearLogs {} {
    global log

    foreach s {left right} {
	$log($s.win).t configure -state normal
	$log($s.win).t delete 0.0 end
	set t$s $log($s.win)
	$log($s.win).t configure -state disabled
    }
    unset log
    set log(left.nrow) 1
    set log(right.nrow) 1
    set log(left.win) $tleft
    set log(right.win) $tright
}
proc LogVis {} {
    global xf log

    if {$xf(log) == 1} {
	grid $xf(fuf).leftinfo.log 
	grid $xf(fuf).rightinfo.log
    } {
	place forget $log(left.win)
	place forget $log(right.win)
	grid remove $xf(fuf).leftinfo.log $xf(fuf).rightinfo.log
    }
}
proc FormatNumber {number} {
    set l [string length $number]
    set i 0
    set n 0
    while {$i<$l} {
	incr n
	set o $i
	incr i 3
	set foo($n) [string range $number [expr {$l-$i}] [expr {$l-$o-1}]]
    }
    for {set a $n} {$a > 0} {incr a -1} {
	append res "$foo($a) "
    }
    return $res
}

proc ProtEditor {s} {
    global prot res xf

    if {[string compare {} $xf(selekted$s)] == 0} {
	NoSelect $s
	return
    }
    set xf(clearselect) 1
    catch {destroy .prot_edit}
    set pe [toplevel .prot_edit]
    wm withdraw $pe
    wm title $pe "X-Files ProtEditor"
    wm geometry $pe +300+300
    wm minsize $pe 184 147
    wm protocol $pe WM_DELETE_WINDOW {set res abort}

    frame $pe.top -bd 3 -relief ridge -bg "#bcbcbc"
    label $pe.top.l -bg "#c0c0c0"
    pack $pe.top.l -side left -fill x
    pack $pe.top -side top -fill x
    update idletasks

    frame $pe.m
    frame $pe.m.1
    frame $pe.m.2
    frame $pe.m.3
    frame $pe.m.4

    label $pe.m.1.u -text "user:"
    label $pe.m.1.g -text "group:"
    label $pe.m.1.a -text "all:"
    pack $pe.m.1.a $pe.m.1.g $pe.m.1.u -side bottom -pady 1
    pack $pe.m.1 -side left -fill y

    label $pe.m.2.l -text "read" -width 6
    checkbutton $pe.m.2.u -variable prot(ur) -onvalue 4 -pady 0
    checkbutton $pe.m.2.g -variable prot(gr) -onvalue 4 -pady 0
    checkbutton $pe.m.2.a -variable prot(ar) -onvalue 4 -pady 0
    pack $pe.m.2.a $pe.m.2.g $pe.m.2.u $pe.m.2.l -side bottom
    pack $pe.m.2 -side left -fill y

    label $pe.m.3.l -text "write" -width 6
    checkbutton $pe.m.3.u -variable prot(uw) -onvalue 2 -pady 0
    checkbutton $pe.m.3.g -variable prot(gw) -onvalue 2 -pady 0
    checkbutton $pe.m.3.a -variable prot(aw) -onvalue 2 -pady 0
    pack $pe.m.3.a $pe.m.3.g $pe.m.3.u $pe.m.3.l -side bottom
    pack $pe.m.3 -side left -fill y

    label $pe.m.4.l -text "execute" -width 6
    checkbutton $pe.m.4.u -variable prot(ue) -pady 0
    checkbutton $pe.m.4.g -variable prot(ge) -pady 0
    checkbutton $pe.m.4.a -variable prot(ae) -pady 0
    pack $pe.m.4.a $pe.m.4.g $pe.m.4.u $pe.m.4.l -side bottom
    pack $pe.m.4 -side left -fill y

    pack $pe.m -side top -fill both

    frame $pe.b -bd 3 -relief ridge
    button $pe.b.ok -text "OK" -width 6 \
	    -command {\
	    set user [expr {$prot(ur)+$prot(uw)+$prot(ue)}];\
	    set group [expr {$prot(gr)+$prot(gw)+$prot(ge)}];\
	    set all [expr {$prot(ar)+$prot(aw)+$prot(ae)}];\
	    set res $user$group$all}

    button $pe.b.cancel -text "Cancel" -width 6 \
	    -command {set res {}}
    button $pe.b.abort -text "Abort!" -width 6 \
	    -command {set res abort}
    pack $pe.b.ok -side left -padx 10
    pack $pe.b.abort $pe.b.cancel -side right
    pack $pe.b -side top -fill x

    focus $pe.b.ok
    bind $pe <Control-c> {set res ""}
    bind $pe <Escape> {set res ""}

    wm deiconify $pe
    grab $pe

    set changed 0
    foreach f [GetSelNames $s] {
	SetChecks prot $xf(pathi$s) $f
	$pe.top.l config -text "File: $f"
	tkwait variable res
	if {![string compare abort $res]} {
	    set xf(clearselect) 0
	    set xf(noinfo) 1
	    after 50 [list set xf(noinfo) 0]
	    after 150 [list InfoChange $s "Command aborted!"]
	    after 4000 [list DefaultInfo $s]
	    break
	}
	if {[string compare {} $res]} {
	    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!
	    if {[catch {eval exec chmod $res [list [file join $xf(pathi$s) $f]]} err]} {
		MessageBox $err $s
		continue
	    }
	    set changed 1
	}
    }
    catch {destroy $pe}
    unset prot
    if {$changed} {
	UpdateListbox $s
    }
}

proc SetChecks {arr path file} {
    upvar $arr prot

    catch {file stat $path$file stat}
    set mode [expr {[format "%o" $stat(mode)] % 1000}]
    for {set i 0} {$i < 3} {incr i} {
	set d [string index $mode $i]
	switch $i {
	    0 {set c u}
	    1 {set c g}
	    2 {set c a}
	}
	set prot(${c}r) [expr {$d & 100}]
	set prot(${c}w) [expr {$d & 10}]
	set prot(${c}e) [expr {$d & 1}]
    }
}
proc LoadConfigFile {file {nhf 1}} {
    global xf

    if {[file exists [file join $xf(user_home) $file]]} {
	if {$nhf == 1} {
	    if {[catch {uplevel #0 source [list [file join $xf(user_home) $file]]} err]} {
		puts stderr "Error while reading [file join $xf(user_home) $file]: $err"
	    } {
		return [file join $xf(user_home) $file]
	    }
	} {
	    return [file join $xf(user_home) $file]
	}
    }
    if {[file exists [file join $xf(xf_home) $file]]} {
	if {$nhf == 1} {
	    if {[catch {uplevel #0 source [list [file join $xf(xf_home) $file]]} err]} {
		puts stderr "Error while reading '[file join $xf(xf_home) $file]': $err"
	    } {
		return [file join $xf(xf_home) $file]
	    }
	} {
	    return [file join $xf(xf_home) $file]
	}
    }
    puts stderr "Could not read $file either in ~/.x-files/ or in $xf(xf_home), exiting..."
    exit
}

proc MakeSaveDir {} {
    global xf

    if {![file exists $xf(user_home)]} {
	file mkdir $xf(user_home)
	#if [catch {eval exec $xf(MKDIR) [list $xf(user_home)]}] {
	    #MakeDirProc $xf(user_home)
	#}
    }
}

proc TildeSubst {path {s {}}} {
    global env tcl_platform

    #puts "TildeSubst"
    if {[string compare windows $tcl_platform(platform)] == 0} {
	# Windows TODO
	return [string trimright [file join $path] /]/
    } {
	# Unix
	if {[catch {set dir [pwd]/}]} {
	    #puts "catch baa"
	    set dir [string trimright $env(HOME) /]/
	}
	set path [string trimright $path /]/
	set rc $path
	if {[string match "\." $path] || [string match "\./" $path]} {
	    #puts if1
	    set rc [string trimright $dir /]/
	} elseif {[regexp {^~[^/]*/} $path beg]} {
	    #puts if2
	    if {[catch {glob -- $beg} err]} {
		MessageBox "Invalid pathname: $path\nError: $err" $s
		set rc [string trimright $env(HOME) /]/
	    } {
		regsub {^~[^/]*/} $path [string trimright $err /]/ rc
	    }
	} elseif {[regexp {\.\./} $path beg]} {
	    #puts if3
	    if {[catch {cd $beg} err]} {
		MessageBox "Invalid pathname: $path\nError: $err" $s
		set rc [string trimright $env(HOME) /]/
	    } {
		set new [pwd]
		regsub {\.\./} $path $new/ rc
	    }
	} elseif {![string match {/*} $path]} {
	    #puts if4
	    regsub {^\./} $path {} path
	    set rc [string trimright [pwd] /]/[string trimright $path /]/
	}
	#catch {cd $dir}
	return $rc
    }
}

proc GetParentDir {dir} {
    return [string trimright [file dirname $dir] /]/
}

proc Bindings {} {
    global xf log

    bind XF <Enter> {
	SetCursor %W
	if {$xf(autofocus) != 0} {
	    focus %W
	}
    }
    bind . <Tab> {}
    bind XF <Control-c> {Confirm_exit}
    bind XF <Control-z> {wm iconify .}
    # TODO MKi 981011 onks tää OK?
    bind XF <Escape> {
	if {[string match {*left*} %W]} {
	    set s left
	} {
	    set s right
	}
	if {$xf(smode_$s) == 2} {
	    # CopyTo or MoveTo selection
	    if {[AskWin "Cancel $xf(copyto_target) ?" -50 -50 {} {} {} Yes No] == 1} {
		# yes
		set xf(copyto_target) {}
		break
	    }
	}
    }
    bind XF <Control-space> {
	if {[string match {*left*} %W]} {
	    set s left
	} {
	    set s right
	}
	set ent $xf(pathEnt_$s)
	if {[$ent select present] && [string match [focus] $ent]} {
	    continue
	}
	focus $ent
	$ent select range 0 end
	break
    }
    bind XF <Button-1> {
	if {$xf(helpmode) == 1 } {
	    HelpInfo %x %y %W
	    tkButtonUp %W
	    break
	}
    }

    # append selection to HyperList
    bind XF <Control-a> {
	if {[string match {*left*} %W]} {
	    set s left
	} {
	    set s right
	}
	if {$xf(fsmode_$s) != 0 && $xf(fsmode_$s) != 4} {
	    MessageBox "HyperList: Only normal and FTP modes have this feature!" $s
	    break
	}

	HyperList 0 $s
	break
    }
    # show HyperList
    bind XF <Control-s> {
	if {[string match {*left*} %W]} {
	    set s left
	} {
	    set s right
	}
	if {$xf(fsmode_$s) != 0 && $xf(fsmode_$s) != 4} {
	    MessageBox "HyperList: Only normal and FTP modes have this feature!" $s
	    break
	}
	HyperList 1 $s
	break
    }
    bind XF <Control-d> {
	ClearHyperList
    }
    bind XF <Control-h> {
	.xfmenu.help.m invoke 1
	if {$xf(helpmode)} {set m "ON"} {set m "OFF"}
	LogBoth "Help mode $m." 2
	SetCursor %W
	break
    }

    bind XF "+" {if {$xf(helpmode) == 1} "GetHelp $xf(xf_home)xfiles.manual"}

    bind XF <Control-D> {Xf_variable_dumb}

    bind XF <Key> {
	if {[string match {F*} %K]} {
	    set xf(butsetindic) ""
	}
	switch %K {
	    F1 {ButtonLines 1 1}
	    F2 {ButtonLines 2 1}
	    F3 {ButtonLines 3 1}
	    F4 {ButtonLines 4 1}
	    F5 {ButtonLines 5 1}
	    F6 {ButtonLines 6 1}
	    F7 {ButtonLines 7 1}
	    F8 {ButtonLines 8 1}
	    F9 {
		set xf(butsetindic) "Set 1 (F9)"
		ButtonLineSets $xf(buttonset1)
	    }
	    F10 {
		set xf(butsetindic) "Set 2 (F10)"
		ButtonLineSets $xf(buttonset2)
		break
	    }
	    F11 {
		set xf(butsetindic) "Set 3 (F11)"
		ButtonLineSets $xf(buttonset3)
	    }
	    F12 {
		set xf(butsetindic) "Set 4 (F12)"
		ButtonLineSets $xf(buttonset4)
	    }
	    default {}
	}
    }
    bind XF_Path <Double-Button-1> {
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	set i [%W index insert]
	set end [string first / [string range $xf(pathi$s) $i end]]
	if {[string match $xf(pathi$s) [string range $xf(pathi$s) 0 [expr $i + $end]]] == 0} {
	    # allow other modes, too
	    #if {$xf(fsmode_$s) == 0} {
		#History $s
	    #}
	    SetPaths $s [string range $xf(pathi$s) 0 [expr $i + $end]]
	    NullSelect $s
	    
	    FileList $s $xf(pathi$s)
	    DefaultInfo $s
	    break
	}
    }
    bind XF_Path <Control-space> {
	if {[string match {*left*} %W]} {
	    set o "right"
	} {
	    set o "left"
	}
	focus $xf(pathEnt_$o)
	$xf(pathEnt_$o) select range 0 end
	%W xview moveto 1
	%W icursor end
	break
    }
    bind XF_Path <Key> {
	if {[string match {*left*} %W]} {
	    set s "left"
	    set o "right"
	} {
	    set s "right"
	    set o "left"
	}
	# HyperList mode
	if {$xf(smode_$s) == 3} {
	    break
	}
	if {[%W select present]} {
	    switch %K {
		Delete -
		BackSpace {
		    InvalidateLb $s
		    %W delete sel.first sel.last
		    #if {[string compare {} $xf(pathi$s)] == 0} {
			#%W insert 0 "/"
		    #}
		    %W xview moveto 1
		    %W icursor end
		    break
		}
		Alt_L {}
		default {
		    # MKi: allow default selection replacement
		    #%W select clear
		}
	    }
	}
	switch %K {
	    Tab {
		DirComplete $s
		break
	    }
	    Up -
	    Down {
		if {$xf(smode_$s) == 1 && [$xf(fuf).${s}list index end] > 2.0} {
		    set lb $xf(fuf).${s}list
		    regexp {^[^\.]*} [$lb tag ranges sel] sel
		    regexp {^[^\.]*} [$lb index end] end
		    set end [expr $end-2]
		    if {[string compare {} $sel] == 0} {
			$lb tag add sel 1.0 2.0
		    } {
			if {[string match Up %K]} {set i -1} {set i 1}
			# if (first and UP) or (last and DOWN), do nothing
			if {($sel == 1 && $i == -1) || \
				($sel == $end && $i == 1)} {
			    break
			}
			$lb tag remove sel $sel.0 [expr $sel+1].0
			$lb tag add sel [expr $sel+$i].0 [expr $sel+$i+1].0
			$lb see [expr $sel+$i].0
		    }
		    # make selection topmost tag
		    $lb tag raise sel
		}
	    }
	    Alt_L {}
	    default {
		InvalidateLb $s
	    }
	}
    }
    bind XF_Path <Return> {
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	    # in FTP mode and busy
	    #puts "FTP Busy"
	    MessageBox "FTP connection is busy!" $s
	    break
	}
	%W select clear
	set l $xf(fuf).${s}list
	set sel [FL_Selection $s]
	if {$xf(smode_$s) == 1 && \
		[string compare {} $sel] != 0} {
	    set file [$l get [expr $sel+1].0 [$l index "[expr $sel+1].0 lineend"]]
	    $l tag remove sel [expr $sel+1].0 [expr $sel+2].0
	    regsub {[^/]*$} $xf(pathi$s) {} xf(pathi$s)
	    FileOK $s $file "L"
	} {
	    BindReturn $s
	}
    }
    bind XF_Path <Button-3> {
	if {[string match {*left*} %W]} {
	    set s "left"
	    set o "right"
	} {
	    set s "right"
	    set o "left"
	}
	switch $xf(smode_$s) {
	    0 {
		SetWaitPointer
		ListFlash $s
		switch $xf(fsmode_$s) {
		    0 {
			if {[string compare $xf(pathi$s) $xf(pathi$o)] == 0} {
			    UpdBoth
			} {
			    UpdateListbox $s
			    DefaultInfo $o
			}
		    }
		    1 {VirtualZip $xf(virtualfile) $s 1}
		    2 {VirtualTar $xf(virtualfile) $s $xf(tar.decomp) 1}
		    3 {VirtualLha $xf(virtualfile) $s 1}
		    4 {
			set xf(ftp.update) 1
			FileList $s $xf(pathi$s)
			DefaultInfo $s
		    }
		    5 {VirtualRpm $xf(virtualfile) $s 1}
		    6 {VirtualRar $xf(virtualfile) $s 1}
		}
		SetArrowPointer
	    }
	    3 {
		# HyperList mode
		break
	    }
	    default {
		BindReturn $s
	    }
	}
    }
    bind XF_Path <Button-1> {
	set xf(b1e) 1
	after 300 [list HistoryMenu %W]
    }
    bind XF_Path <B1-Leave> {
	if {$xf(b1e)} {
	    break
	}
    }
    bind XF_Path <ButtonRelease-1> {
	set xf(b1e) 0
    }
    bind XF_Path <B1-Motion> {
	set xf(b1e) 0
    }
    bind XF_Path <Enter> {
	if {$xf(helpmode)} {
	    %W config -cursor question_arrow
	} {
	    %W config -cursor xterm
	}
	%W xview moveto 1
	%W icursor end
    }

    bind Button <Return> {%W invoke}
    bind all <F10> {}

    bind XF_Listbox <BackSpace> {
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	dirUp $s
	#PreviousDirectory $s
    }
    bind XF_Listbox <Delete> {
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	if {[string compare {} $xf(selekted$s)] != 0 \
		&& [AskWin "\[Delete selected files\]: Are You Sure ?" -50 -50 {} {} {} Yes No] == 1} {
	    FileOps "rm" $s
	}
    }
    bind XF_Listbox <Key-Up> {%W yview scroll -1 units}
    bind XF_Listbox <Key-Down> {%W yview scroll 1 units}
    bind XF_Listbox <Key-Left> {%W xview scroll -1 units}
    bind XF_Listbox <Key-Right> {%W xview scroll 1 units}
    bind XF_Listbox <Key-Prior> {%W yview scroll -1 pages}
    bind XF_Listbox <Key-Next> {%W yview scroll 1 pages}
    bind XF_Listbox <B1-Leave> {
	if {!$xf(helpmode)} {
	    set tkPriv(x) %x
	    set tkPriv(y) %y
	    tkTextAutoScan %W
	}
    }
    bind XF_Listbox <B1-Enter> {
	tkCancelRepeat
    }

    bind XF_Listbox <Shift-Button-1> {
	#puts SB1
	if {$xf(sb1) == 0} {
	    # start section to be marked
	    set xf(sb1) 1
	    event generate %W <<XF_B1>> -x %x -y %y
	} {
	    # end section to be marked
	    set xf(sb1) 0
	    LB_tkTextSelectTo %W %x %y
	}
	break
    }
    event add <<XF_B1>> <1>
    bind XF_Listbox <<XF_B1>> {
	#puts XF_B1
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	if {$xf(smode_$s) == 2} {
	    # CopyTo or MoveTo selection
	    if {[string compare $s $xf(copyto_side)] == 0 \
		    && $xf(fsmode_$s) > 0} {
		# user tries VFS to VFS copy
		MessageBox "Sorry, VFS to VFS file operations are not supported, yet!" $s
		break
	    }
	    regexp {^[^\.]*} [ClickIndex %W %x %y] ind
	    #puts "B1: CopyTo: [expr $ind-1] [llength [set vd$s]]"
	    if {$ind > [llength [set vd$s]]} {
		MessageBox "$xf(copyto_target): Select a directory!" $s
		break
	    }
	    set xf(copyto_side) $s
	    set xf(copyto_target) $xf(pathi$s)[GetFileName $s [expr $ind-1]]
	    #DEBUG $xf(copyto_target)
	    break
	}
	if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	    # in FTP mode and busy
	    #puts "FTP Busy"
	    #Log $s "FTP busy..." 3
	    MessageBox "FTP connection is busy!" $s
	    break
	}
	    
	focus %W
	set xf(b1r) 1
	set stop_calc 0
	if {$xf(helpmode)} {
	    HelpInfo %x %y %W
	    break
	} {
	    #tkCancelRepeat
	    set point [ClickIndex %W %x %y]
	    regexp {^[^\.]*} $point tkPriv(xf_line)

	    # are we adding or removing a selection
	    if {[string match {*sel*} [%W tag names $point]]} {
		set tkPriv(xf_mode) remove
	    } {
		set tkPriv(xf_mode) add
	    }		
	    # necessary parts from tkTextButton1
	    set tkPriv(mouseMoved) 0
	    set tkPriv(pressX) %x
	    set tkPriv(xf_selection) [%W tag ranges sel]
	    %W mark set anchor $point
	    #if {[%W cget -state] == "normal"} {focus %W}
	    LB_tkTextSelectTo %W %x %y
	    
	    #%W activate @%x,%y
	}
    }
    bind XF_Listbox <ButtonRelease-1> {
	#puts BR1
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}

	# this is now moved to DB1 since 
	# double-clicking left the file "selected"

	#if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	    # in FTP mode and busy
	    #puts "FTP Busy"
	    #Log $s "FTP busy..." 3
	    #MessageBox "FTP connection is busy!" $s
	    #break
	#}
	tkCancelRepeat
	regexp {^[^\.]*} [%W index anchor] a
	regexp {^[^\.]*} [ClickIndex %W %x %y] n
	if {$a <= $n} {
	    set alku $a
	    set loppu $n
	} {
	    set alku $n
	    set loppu $a
	}
	#puts "$alku -> $loppu"
	#puts "$xf(selekted$s) :: [FL_Selection $s]"
	# without this, when changing to a directory that has less 
	# items that was the clickesd index,
	# an error would occur
	if {$stop_calc == 0} {
	    #DEBUG "bababaa $tkPriv(xf_mode)"
	    for {set i [expr $alku-1]} {$i < $loppu} {incr i} {
		if {$i == 0 && [string match {*\.\.*} [%W get 1.0 [%W index "1.0 lineend"]]]} {
		    %W tag remove sel 1.0 2.0
		    SetArrowPointer
		    continue
		}
		set ind [lsearch -exact $xf(selekted$s) $i]
		if {[string compare {remove} $tkPriv(xf_mode)] == 0} {
		    if {$ind > -1} {
			AddSelSize $s $i "-"
		    }
		} {
		    if {$ind == -1} {
			AddSelSize $s $i "+"
		    }
		}
	    }
	}
	set xf(selekted$s) [FL_Selection $s]
	# in VFS a doubleclick left the infoarea unupdated...
	# it seems that doubleclick generates only one Button-1 event now
	if {$xf(b1r) || $xf(fsmode_$s)} {
	    DefaultInfo $s
	}
	set xf(b1r) 1
	#DEBUG "selsum1: $xf(selsum$s)"
    }
    bind XF_Listbox <B1-Motion> {
	#puts B1M
	catch {
	    if {!$xf(helpmode)} {
		set tkPriv(mouseMoved) 1
		set tkPriv(x) %x
		set tkPriv(y) %y
		LB_tkTextSelectTo %W %x %y
	    }
	}
    }
    bind XF_Listbox <Double-Button-1> {
	#puts "DB1 :: $xf(sb1)"
	if {$xf(sb1)} {
	    break
	}
	set xf(b1r) 0
	set xf(sb1) 0
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	SetWaitPointer
	if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	    # in FTP mode and busy
	    #puts "FTP Busy"
	    Log $s "FTP busy..." 3
	    #MessageBox "FTP connection is busy!" $s
	    break
	}
	# make selection mode remove, otherwise selsum is not correct 
	# MKi 981028
	set tkPriv(xf_mode) remove
	set ind [FileClick %W %x %y]
	FileOK $s [GetFileName $s $ind] "L" [GetFileLink $s $ind]
	SetArrowPointer
    }

    event add <<XF_B2>> <2> <Control-Button-1>
    bind XF_Listbox <<XF_B2>> {
	#puts B2
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	    # in FTP mode and busy
	    #puts "FTP Busy"
	    MessageBox "FTP connection is busy!" $s
	    break
	}
	set stop_calc 1
	set xf(b2r) 1
	set tkPriv(x) %x
	set tkPriv(y) %y
	
	tkCancelRepeat
	%W scan mark %x %y
	set tkPriv(mouseMoved) 0
	#$W activate @$x,$y
	after 300 [list set xf(b2r) 0]
    }

    event add <<XF_B2-Motion>> <B2-Motion> <Control-B1-Motion>
    bind XF_Listbox <<XF_B2-Motion>> {
	set xf(b2r) 0
	if {(%x != $tkPriv(x)) || (%y != $tkPriv(y))} {
	    set tkPriv(mouseMoved) 1
	}
	if {$tkPriv(mouseMoved)} {
	    %W scan dragto 10000 %y
	    #%W scan dragto %x %y
	}
    }
    bind XF_Listbox <Double-Button-2> {}
    event add <<XF_ButtonRelease-2>> <ButtonRelease-2> <Control-ButtonRelease-1>
    bind XF_Listbox <<XF_ButtonRelease-2>> {
	if {$xf(b2r)} {
	    #puts B2R
	    if {[string match {*left*} %W]} {
		set s "left"
		set o "right"
	    } {
		set s "right"
		set o "left"
	    }
	    SetWaitPointer
	    regexp {^[^\.]*} [ClickIndex %W %x %y] point
	    set i [expr $point - 1]
	    #puts $i
	    set ind [lsearch $xf(selekted$s) $i]
	    #puts $ind
	    if {$ind > -1} {
		AddSelSize $s $i "-"
		set xf(selekted$s) [lreplace $xf(selekted$s) $ind $ind]
		CorrectColor $o xf {} {}
		ShowSelSize $s
	    }
	    %W tag add sel $point.0 [expr $point+1].0
	    # make selection topmost tag
	    %W tag raise sel
	    update idletasks
	    after 500 [list %W tag remove sel $point.0 [expr $point+1].0]
	    set ind [FileClick %W %x %y]
	    FileOK $s [GetFileName $s $ind] "M" [GetFileLink $s $ind]
	    SetArrowPointer
	}
    }

    bind XF_Listbox <Button-3> {
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	    # in FTP mode and busy
	    #puts "FTP Busy"
	    MessageBox "FTP connection is busy!" $s
	    break
	}
	tk_popup $xf(fuf).${s}list.popup_menu %X %Y
    }

    bind XF_Listbox <KeyPress> {
	if {[string match {*left*} %W]} {
	    set s "left"
	} {
	    set s "right"
	}
	ListKey %W %A $xf(pathi$s) $xf(fsmode_$s)
    }

    # swap button
    bind $xf(fuf).swap <Button-2> {tkButtonDown %W}
    bind $xf(fuf).swap <Button-3> {tkButtonDown %W}
    bind $xf(fuf).swap <ButtonRelease-2> {tkButtonUp %W}
    bind $xf(fuf).swap <ButtonRelease-3> {tkButtonUp %W}
    bindtags $xf(fuf).swap [list XF $xf(fuf).swap Button . all]
    
    foreach j {left right} {
	foreach k {dirup dirroot all no copy evfs} {
	    bind .ff.$j.$k <Button-2> {tkButtonDown %W}
	    bind .ff.$j.$k <Button-3> {tkButtonDown %W}
	    bind .ff.$j.$k <ButtonRelease-2> {tkButtonUp %W}
	    bind .ff.$j.$k <ButtonRelease-3> {tkButtonUp %W}
	    bindtags .ff.$j.$k [list XF .ff.$j.$k Button . all]
	}
	# hidden checkbuttons
	bind .ff.$j.hide <Button-2> {tkCheckRadioInvoke %W}
	bind .ff.$j.hide <Button-3> {tkCheckRadioInvoke %W}
	bindtags .ff.$j.hide [list XF .ff.$j.hide Checkbutton . all]

	# listboxes
	bindtags $xf(fuf).${j}list {XF XF_Listbox . all}
	bindtags $xf(pathEnt_$j) {XF XF_Path Entry . all}
	bindtags $xf(infoEnt_$j) {XF . all}
	bind .ff.$j.mask <Return> [list MaskReturn $j]
	bind .ff.$j.mask <Enter> {
	    if {$xf(helpmode)} {
		%W config -cursor question_arrow
	    } {
		%W config -cursor xterm
	    }
	    %W xview moveto 1
	    %W icursor end
	}
	bindtags .ff.$j.mask [list XF .ff.$j.mask Entry . all]
    }
}

# This procdure is executed when user hits Return in the mask entry
proc MaskReturn {s} {
    global xf

    Log $s "File mask changed to '$xf(mask$s)'" 2
    NullSelect $s
    FileList $s $xf(pathi$s)
}

# Returns the index of the clicked line in the format 'line.char'. 
# This is needed to avoid the dummy line in the end.
proc ClickIndex {W x y} {
    set end [expr {[$W index end] - 1.0}]
    set try [$W index @$x,$y]
    #puts "$try :: $end"
    if {$try == $end} {
	return [expr {$try - 1.0}]
    }
    return $try
}

# overrides the internal procedure, providing the behaviour we want
proc LB_tkTextSelectTo {w x y} {
    global tkPriv tcl_platform

    set cur [ClickIndex $w $x $y]
    #puts "$cur"
    regexp {^[^\.]*} $cur line
    if {$line == $tkPriv(xf_line) && $tkPriv(mouseMoved)} {
	#puts ret
	return
    }
    #puts "$line"
    #puts noret
    if {[catch {$w index anchor}]} {
	$w mark set anchor $cur
    }
    regexp {^[^\.]*} [$w index anchor] anchor
    set i $tkPriv(xf_line)
    # define order, since text widget does not 
    # understand indices like '5 1' as listbox does
    if {$i <= $line} {
	set a $i
	set l [expr {$line + 1}]
    } {
	set a $line
	set l [expr {$i + 1}]
    }
    if {$anchor <= $line} {
	set na $anchor
	set nl [expr {$line + 1}]
    } {
	set na $line
	set nl [expr {$anchor + 1}]
    }
    # behaviour copied from tkListboxMotion
    if {[string match add $tkPriv(xf_mode)]} {
	$w tag remove sel $a.0 $l.0
	$w tag add sel $na.0 $nl.0
    } {
	$w tag remove sel $a.0 $l.0
	$w tag remove sel $na.0 $nl.0
    }
    while {($i < $line) && ($i < $anchor)} {
	foreach {b e} $tkPriv(xf_selection) {
	    if {($b <= $i) && ($i < $e)} {
		$w tag add sel $i.0 [expr {$i + 1}].0
	    }
	}
	incr i
    }
    while {($i > $line) && ($i > $anchor)} {
	foreach {b e} $tkPriv(xf_selection) {
	    if {($b <= $i) && ($i < $e)} {
		$w tag add sel $i.0 [expr {$i + 1}].0
	    }
	}
	incr i -1
    }
    set tkPriv(xf_line) $line
    # make selection topmost tag
    $w tag raise sel
}

# change to the previous directory in current list
proc PreviousDirectory {s} {
    global xf

    set dir [lindex $xf(history_$xf(fsmode_$s)) 0]
    if {[string compare $dir {}] != 0} {
	ChangeDir $s $dir
    }	
}

proc HistoryMenu {W} {
    global xf

    if {$xf(b1e)} {
	if {[string match {*left*} $W]} {
	    set s "left"
	} {
	    set s "right"
	}
	if {[llength $xf(history_$xf(fsmode_$s))] > 0} {
	    #set focus [focus]
	    set dir [XF_PopMenu .__pop $xf(history_$xf(fsmode_$s)) 5 10 [winfo rootx $W] [expr {[winfo rooty $W] + [winfo height $W]}] 1]
	    if {[string compare {} $dir] != 0} {
		# something was selected
		ChangeDir $s $dir
	    }
	    #focus $focus
	}
    }
}
proc SetCursor {W} {
    global xf
    set cur [$W cget -cursor]
    if {$xf(helpmode)} {
	if {[string match "top_left_arrow" $cur] || \
		[string compare {} $cur] == 0} {
	    $W config -cursor question_arrow
	}
    } {
	if {[string match "question_arrow" $cur]} {
	    $W config -cursor top_left_arrow
	}
    }
}
proc InvalidateLb {s} {
    global xf

    #if {[$xf(fuf).${s}list index end] > 2.0 && $xf(fsmode_$s) == 0} {}
    if {[$xf(fuf).${s}list index end] > 2.0} {
	set xf(no_aud_$s) 1
	NullSelect $s
	$xf(fuf).${s}list config -state normal
	$xf(fuf).${s}list delete 0.0 end
	$xf(fuf).${s}list config -bg [option get .xfiles writepath_mode_bg {}] -state disabled
	set xf(smode_$s) 1
	update idletasks
    }
}

proc ListKey {W a path fsmode} {
    global vdleft vdright vfleft vfright

    if {[string compare {} $a]} {
	if {[string match *left* $W]} {
	    set dirpit [llength $vdleft]
	    set files $vfleft
	} {
	    set dirpit [llength $vdright]
	    set files $vfright
	}
	set others {}
	foreach row $files {
	    lappend others [lindex $row 0]
	}
	#for {set cc 0}  {$cc < [llength $files]} {incr cc} {
	 #   lappend others [lindex [lindex $files $cc] 0]
	#}
	set flag 1
	set pad 0
	set i 0
	while {$flag} {
	    set loc [lsearch $others $a*]
	    if {$loc > -1} {
		set flag 0
		$W yview [expr {$loc+$dirpit+$pad}]
	    } {
		scan $a %c i
		if {$i > 126} {
		    set flag 0
		    $W yview moveto 1
		} {
		    set pad -1
		    set a [format %c [incr i]]
		    set loc [lsearch $others $a*]
		}
	    }
	}
    }
}
proc SetWaitPointer {{W .}} {
    $W config -cursor watch
    update idletasks
}
proc SetArrowPointer {{W .}} {
    $W config -cursor top_left_arrow
    update idletasks
}
proc ListFlash {s} {
    global xf

    set color [$xf(fuf).${s}list cget -bg]
    $xf(fuf).${s}list config -bg "#f0f0f0"
    update idletasks
    $xf(fuf).${s}list config -bg $color
    update idletasks
}

proc InfoChange {s string} {
    global xf

    if {!$xf(noinfo)} {
	set xf(infoA$s) ""
	$xf(infoEnt_$s) config -justify left
	$xf(infoEnt_$s) config -bg "#10106a"
	set xf(infoA$s) $string
	if {![string match {Selected*} $string] && ![string match {Calcul*} $string]} {
	    after idle [list Log $s $string 2]
	}
	update idletasks
    }
}

proc DirComplete {s} {
    global xf

    #puts "DirComplete()"
    if {[string compare {} $xf(pathi$s)] == 0} {
	set xf(pathi$s) [lindex [file split $xf(backup_$s)] 0]
	$xf(pathEnt_$s) icursor end
	ListFlash $s
	bell
	ShowChoices $s
	return
    }
    if {($xf(fsmode_$s) > 0 && [string match */ $xf(pathi$s)]) || \
	    ($xf(fsmode_$s) == 0 && [file isdirectory $xf(pathi$s)])} {
	if {[string match */ $xf(pathi$s)] || \
		[llength [GetDirsInDir $s $xf(pathi$s)]] > 1} {
	    ListFlash $s
	    bell
	    ShowChoices $s
	} {
	    set xf(pathi$s) [string trimright $xf(pathi$s) /]/
	}
	$xf(pathEnt_$s) xview moveto 1
	$xf(pathEnt_$s) icursor end
	return
    }
    set tail [file tail $xf(pathi$s)]
    set dir {}
    if {[string match /* $xf(pathi$s)] && ![string match /*/* $xf(pathi$s)]} {
	set dir [lindex [file split $xf(pathi$s)] 0]
    } elseif {[string match /*/* $xf(pathi$s)]} {
	set dir [file dirname $xf(pathi$s)]/
    } elseif {[string match {/*} $xf(pathi$s)]} {
	set dir [lindex [file split $xf(pathi$s)] 0]
	set tail $xf(pathi$s)
    }
    if {[string compare {//} $dir] == 0} {
	set dir /
    }
    #puts "DEB: $dir :: $tail"
    #set dirs [GetDirsInDir $s $xf(pathi$s)]
    set dirs [GetDirsInDir $s $dir $tail]

    if {[llength [split $dirs]] == 1} {
	#if [file isdirectory $dir$dirs] {
	    set xf(pathi$s) $dir$dirs
	    $xf(pathEnt_$s) xview moveto 1
	    $xf(pathEnt_$s) icursor end
	#}
    } {
	if {[llength [split $dirs]] > 1} {
	    set l [expr {[string length $tail] -1}]
	    set miss 0
	    set dir1 [lindex $dirs 0]
	    while {!$miss} {
		incr l
		if {$l == [string length $dir1]} {
		    break
		}
		set new [string range $dir1 0 $l]
		foreach d $dirs {
		    if {![string match $new* $d]} {
			set miss 1
			incr l -1
			break
		    }
		}
	    }
	    #puts "DEB: ll $dir1"
	    set xf(pathi$s) $dir[string range $dir1 0 $l]
	    $xf(pathEnt_$s) xview moveto 1
	    $xf(pathEnt_$s) icursor end
	}
	ListFlash $s
	bell
	#puts "DEB: new dir $xf(pathi$s)"
	ShowChoices $s
    }
}
proc GetDirsInDir {s dir {stub {}}} {
    global xf vfs ftpcac ftp

    #puts "DEBUG: <$dir :: $stub>"
    SetWaitPointer
    set dirs {}
    if {$xf(fsmode_$s) == 0} {
	# normal
	if {$xf(hiddens_$s) == 1} {
	    set files [lsort [glob -nocomplain -- $dir$stub{.*,*}]]
	} {
	    set files [lsort [glob -nocomplain -- $dir$stub*]]
	}
	foreach f $files {
	    if {[string match {*\.\.} $f] || [string match {*\.} $f]} {
		continue
	    }
	    if {[file isdirectory $f]} {
		lappend dirs [file tail $f]/
	    }
	}
    } {
	# VFS
	if {$xf(fsmode_$s) == 4} {
	    # FTP
	    #if {[info exists ftpcac($dir$stub/)]} {
		#set dir $dir$stub/
		#set stub {}
	    #}
	    if {[info exists ftpcac($dir)] == 0} {
		# not cached, change dir
		# check timeout
		if {[FO_CheckFTPTimeOut $s $xf(ftp.sock)]} {
		    return
		}
		if {[FTP_CMD $xf(ftp.sock) "CWD $dir"] == -1} {
		    # error
		    return
		}
		if {[FTP_LIST $xf(ftp.sock) 1 $xf(ftp.active)] == -1} {
		    # error, list is empty
		    MessageBox "Unable to get file listing...\n\n$ftp($xf(ftp.sock).status)" $s
		    return
		}
		set filelist [split $ftp($xf(ftp.sock).readed) \n]
		set filelist [lreplace $filelist 0 0]
		#puts "DEB: $filelist"
		foreach f $filelist {
		    if {[string match $stub*/ $f]} {
			lappend dirs $f
		    }
		}
	    } {
		# FTP cached
		foreach d $ftpcac(${dir}dirs) {
		    if {[string match $stub* $d]} {
			lappend dirs [lindex $d 0][lindex $d 1]
		    }
		}
	    }
	} {
	    # VFS, other than FTP
	    # we have directories in the memory
	    if {[info exists vfs($dir$stub/)]} {
		set dir $dir$stub/
		set stub {}
	    }
	    if {[info exists vfs($dir)]} {
		foreach d $vfs(${dir}dirs) {
		    if {[string match $stub* $d]} {
			lappend dirs [lindex $d 0][lindex $d 1]
		    }
		}
	    }
	}
    }

    SetArrowPointer
    #puts "DEB: dirs <$dirs>"
    return $dirs
}
proc ShowChoices {s} {
    global xf
    if {$xf(fsmode_$s) == 0 || [string match */ $xf(pathi$s)]} {
	set dirs [GetDirsInDir $s $xf(pathi$s)]
    } {
	set dirs [GetDirsInDir $s [file dirname $xf(pathi$s)] [file tail $xf(pathi$s)]]
    }
    #puts "Show(): $dirs"
    InvalidateLb $s
    $xf(fuf).${s}list config -state normal
    foreach dir $dirs {
	$xf(fuf).${s}list insert end ${dir}\n
    }
    $xf(fuf).${s}list config -state disabled
}
proc SelectionSize {s} {
    global xf
    global stop_calc

    set stop_calc 0
    if {[string match {*left*} $s]} {
	set s "left"
	set o "right"
    } {
	set s "right"
	set o "left"
    }
    set xf(selekted$s) [FL_Selection $s]
    set xf(selsum$s) 0.0
    if {[string compare {} $xf(selekted$s)] == 0} {
	DefaultInfo $s
	return
    }
    foreach f $xf(selekted$s) {
	if {$stop_calc} {
	    NullSelect $s
	    DefaultInfo $s
	    return
	}
	set size [GetFileSize $s $f].0
	set xf(selsum$s) [expr {$xf(selsum$s) + $size}]
	update idletasks
    }
    CorrectColor $o xf {} {}
    ShowSelSize $s
    SetArrowPointer
}

proc AddSelSize {s ind mark} {
    global xf
    set xf(selsum$s) [expr $xf(selsum$s) $mark [GetFileSize $s $ind].0]
}

proc ShowSelSize {s} {
    global xf
    #puts "DEB: sel = $xf(selsum$s)"
    regexp {^([^\.]*)\..*$} [expr {$xf(selsum$s)/1024}] gfg size
    InfoChange $s "Selected [llength $xf(selekted$s)]\
	    objects: [FormatNumber $size]kb"
}
proc BindReturn {s} {
    global xf
    SetWaitPointer
    if {[string match {ftp://*} [string tolower $xf(pathi$s)]]} {
	# user has given an ftp address
	#regexp {^ftp://(.*)$} [string tolower $xf(pathi$s)] gfg address
	#VirtualFTP $s $address
	VirtualFTP $s $xf(pathi$s)
    } {
	set f [TildeSubst $xf(pathi$s) $s]
	FileOK $s $f {}
	set xf(no_aud_$s) 0
	focus $xf(fuf).${s}list
	after idle [list Log $s "CWD: $f" 2]
    }
    SetArrowPointer
}
proc HiddenMode {s} {
    global xf
    SetWaitPointer
    NullSelect $s
    FileList $s $xf(pathi$s)
    DefaultInfo $s
    if {$xf(hiddens_$s)} {
	set str "Show hidden files!"
    } {
	set str "Hide hidden files!"
    }
    after idle [list Log $s $str 2]
    SetArrowPointer
}

proc History {s} {
    global xf

    set menu history_$xf(fsmode_$s)
    if {[info exists xf(backup_$s)] && [info exists xf($menu)]} {
	# check if dir is already in list
	set ind [lsearch $xf($menu) $xf(backup_$s)]
	if {$ind > -1} {
	    # yes
	    # first remove item
	    set xf($menu) [lreplace $xf($menu) $ind $ind]
	}
	# insert dir to the beginning
	set xf($menu) [linsert $xf($menu) 0 $xf(backup_$s)]
	# limit the size to user defined amount of items
	set xf($menu) [lrange $xf($menu) 0 [expr {$xf(history_len) - 1}]]
    }
}

proc UpdateListbox {s {pos {}} {delay {}} {swap 0}} {
    global xf vdleft vdright vfleft vfright

    if {[string match $s left]} {
	#set dirpit [llength $vdleft]
	set o "right"
    } {
	#set dirpit [llength $vdright]
	set o "left"
    }

    if {$xf(smode_$s) != 3} {
	# not HYPERLIST mode
	if {$xf(fsmode_$s) == 0} {
	    $xf(fuf).${s}list config -bg [option get $xf(fuf).${s}list background {}]
	} {
	    $xf(fuf).${s}list config -bg [option get .xfiles vfs_mode_bg {}]
	}
    }
    if {!$swap} {set selfiles [GetSelNames $s]}
    if {[string compare {} $pos] == 0} {
	set pos [expr {[lindex [$xf(fuf).${s}list yview] 0]+0.0001}]
    }
    FileList $s $xf(pathi$s)
    set def 0
    if {[string compare {} $xf(selekted$s)] == 0} {
	set def 1
    } {
	if {!$swap} {
	    set xf(selekted$s) {}
	    set xf(selsum$s) 0.0
	    set dd [set vd$s]
	    set m [string match {\.\.} [lindex [lindex $dd 0] 0]]
	    set dirs [lrange $dd $m end]
	    set dirpit [llength $dd]
	    foreach f $selfiles {
		if {[string match {*/} $f]} {
		    set i $m
		    foreach row $dirs {
			#if [catch {set name [set ${dirs}($i.name)][set ${dirs}($i.ext)]}] {continue}
			set name [lindex $row 0][lindex $row 1]
			if {[string compare $f $name] == 0} {
			    lappend xf(selekted$s) $i
			    set xf(selsum$s) [expr {$xf(selsum$s) + [GetFileSize $s $i]}]
			}
			incr i
		    }
		} {
		    set i $dirpit
		    foreach row [set vf$s] {
			#if [catch {set name [set ${files}($i.name)][set ${files}($i.ext)]}] {continue}
			set name [lindex $row 0][lindex $row 1]
			if {[string compare $f $name] == 0} {
			    lappend xf(selekted$s) $i
			    set xf(selsum$s) [expr {$xf(selsum$s) + [GetFileSize $s $i]}]
			}
			incr i
		    }
		    #for {set i 0} {$i < [llength $files]} {incr i} {
			#set file [lindex $files $i]
			#set name [lindex $file 0][lindex $file 1]
			#if {[string compare $f $name] == 0} {
			 #   set ind [expr $i+$dirpit]
			 #   lappend xf(selekted$s) $ind
			 #   incr xf(selsum$s) [GetFileSize $s $ind]
			#}
		    #}
		}
	    }
	}
	foreach i $xf(selekted$s) {
	    $xf(fuf).${s}list tag add sel [expr {$i+1}].0 [expr {$i+2}].0
	}
	# make selection topmost tag
	$xf(fuf).${s}list tag raise sel

	CorrectColor $o xf {} {}
	if {[string compare {} $xf(selekted$s)] != 0} {
	    if {[string compare {} $delay]} {
		after $delay [list ShowSelSize $s]
	    } {
		ShowSelSize $s
	    }
	} {
	    set def 1
	}
    }
    if {$def} {
	if {[string compare {} $delay]} {
	    after $delay [list DefaultInfo $s]
	} {
	    DefaultInfo $s
	}
    }
    $xf(fuf).${s}list yview moveto $pos
    catch {set xf(${s}autoud) [file mtime $xf(pathi$s)]}
}
proc SelectAll {s} {
    global xf

    SetWaitPointer
    InfoChange $s "Calculating..."
    # Do not include the dummy line in the end...
    set end [expr {[$xf(fuf).${s}list index end] - 1.0}]
    $xf(fuf).${s}list tag add sel 2.0 $end
    # if root dir, select also line 1
    if {$xf(fsmode_$s) == 0 && \
	    [string match $xf(pathi$s) [lindex [file split $xf(pathi$s)] 0]]} {
	$xf(fuf).${s}list tag add sel 1.0 2.0
    }
    # make selection topmost tag
    $xf(fuf).${s}list tag raise sel
    after idle [list Log $s "Selected all items" 2]
    after idle [list SelectionSize $s]
}
proc ClearSelection {s} {
    UnselectAll $s
    DefaultInfo $s
}
proc UnselectAll {s} {
    global xf

    $xf(fuf).${s}list tag remove sel 0.0 end
    $xf(fuf).${s}list config -selectbackground [option get .xfiles selectBg_$s {}]
    update idletasks
    NullSelect $s
    after idle [list Log $s "Cleared all selections" 2]
}

proc NullSelect {s} {
    global xf
    set xf(selekted$s) {}
    set xf(selsum$s) 0.0
}
proc NoSelect {s} {
    global xf
    SetArrowPointer
    set xf(mb) 1
    InfoChange $s "No files selected!"
    bell
    after 4000 [list DefaultInfo $s]
}
proc CopyVars {afrom ato sfrom sto} {
    upvar $ato result $afrom array
    foreach i [list pathi backup_ parent_ selsum hiddens_ fsmode_ devicefree fstype mask mdos_ cf_ sortby_ sortorder_ df infoA redraw selekted smode_ no_aud_] {
	set result(${i}$sto) $array(${i}$sfrom)
    }
}
proc Copyleft {} {
    global xf vdleft vfleft vdright vfright

    History "left"
    set pos [expr {[lindex [$xf(fuf).rightlist yview] 0]+0.0001}]

    CopyVars xf xf "right" "left"
    set xf(selektedleft) $xf(selektedright)
    set vdleft $vdright
    set vfleft $vfright
    CorrectColor "left" xf {} {}
    set xf(redrawleft) 1
    UpdateListbox "left" $pos {} 1
    LogBoth "Right listing copied to the left." 2
}
proc Swap_sides {} {
    global xf vdleft vfleft vdright vfright

    if {$xf(fsmode_left) > 0} {
	grid remove $xf(fuf).left.evfs 
	grid $xf(fuf).right.evfs 
    } elseif {$xf(fsmode_right) > 0} {
	grid remove $xf(fuf).right.evfs 
	grid $xf(fuf).left.evfs 
    }

    set temp(?) ?
    CopyVars xf temp "right" ""
    CopyVars xf xf "left" "right"
    CopyVars temp xf "" "left"
    unset temp

    set selekt $xf(selektedright)
    set xf(selektedright) $xf(selektedleft)
    set xf(selektedleft) $selekt
    set temp $vdright
    set vdright $vdleft
    set vdleft $temp
    set temp $vfright
    set vfright $vfleft
    set vfleft $temp

    if {[info exists xf(bgact.side)]} {
	if {[string match left $xf(bgact.side)]} {
	    set xf(bgact.side) right
	} {
	    set xf(bgact.side) left
	}
    }
    set posr [expr {[lindex [$xf(fuf).rightlist yview] 0]+0.0001}]
    set posl [expr {[lindex [$xf(fuf).leftlist yview] 0]+0.0001}]

    set xf(redrawleft) 1
    set xf(redrawright) 1
    UpdateListbox "left" $posr {} 1
    UpdateListbox "right" $posl {} 1
    LogBoth "Listings swapped." 2
}
proc CopyRight {} {
    global xf vdleft vfleft vdright vfright

    History "right"
    set pos [expr {[lindex [$xf(fuf).leftlist yview] 0]+0.0001}]

    CopyVars xf xf "left" "right"
    set xf(selektedright) $xf(selektedleft)
    set vdright $vdleft
    set vfright $vfleft
    CorrectColor "right" xf {} {}
    set xf(redrawright) 1
    UpdateListbox "right" $pos {} 1
    LogBoth "Left listing copied to the right." 2
}
proc ExitVFS {s} {
    global xf
    #if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	# in FTP mode and busy
	#puts "FTP Busy"
	#return
    #}
    if {$xf(confirmVFSexit) == 1} {
	set rc [AskWin "Exit virtual mode?" -50 -50 {} {} {} Yes No]
    } {
	set rc 1
    }
    if {$rc == 1} {
	AfterVirtual $s
	#puts "$xf(fsmode_$s) :: $xf(pathi$s)"
	FileList $s $xf(pathi$s)
	DefaultInfo $s
    }
}
proc dirUp {s} {
    global xf stop_calc ftp

    if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	# in FTP mode and busy
	#puts "FTP Busy"
	MessageBox "FTP connection is busy!" $s
	return
    }
    set stop_calc 1
    #History $s
    if {$xf(smode_$s) == 3} {
	# exit HyperList mode
	SetPaths $s $xf(backup_$s)
	set xf(no_aud_$s) 0
	set xf(smode_$s) 0
    } {	
	# normal
	if {$xf(fsmode_$s) == 0} {
	    if {[string match $xf(pathi$s) $xf(parent_$s)]} {
		return
	    }
	} {
	    if {[string match $xf(pathi$s) /]} {
		ExitVFS $s
		return
	    }
	}
	SetPaths $s $xf(parent_$s)
    }

    NullSelect $s
    FileList $s $xf(pathi$s)
    # MKi 15.1.98  do defaultinfo always
    #if {[string match $xf(pathi$s) [lindex [file split $xf(pathi$s)] 0]] || [string compare {} $xf(selekted$s)]} {
	DefaultInfo $s
    #}
}
proc dirRoot {s} {
    global xf stop_calc ftp

    if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	# in FTP mode and busy
	#puts "FTP Busy"
	MessageBox "FTP connection is busy!" $s
	return
    }
    set stop_calc 1
    if {[string match $xf(backup_$s) $xf(parent_$s)] \
	    && $xf(smode_$s) == 0} {
	return
    }
    #if [string match $xf(fsmode_$s) 0] {
	#History $s
    #}
    SetPaths $s [lindex [file split $xf(pathi$s)] 0]
    $xf(fuf).${s}list config \
	    -selectbackground [option get .xfiles selectBg_$s {}]
    NullSelect $s
    FileList $s $xf(pathi$s)
    DefaultInfo $s
}
proc FF_ScrollSet_left args {
    global xf
    eval $xf(fuf).leftheader $args
    eval $xf(fuf).leftlist $args
}
proc FF_ScrollSet_right args {
    global xf
    eval $xf(fuf).rightheader $args
    eval $xf(fuf).rightlist $args
}
proc FileFrame {parent args} {
    global xf xf_image

    foreach s [list left right] {
	# LBs
	eval {text $parent.${s}list -yscrollcommand \
		[list $parent.${s}sy set] -xscrollcommand \
		[list $parent.${s}sx set]} $args
	scrollbar $parent.${s}sy -orient vertical -command \
		[list $parent.${s}list yview] -relief ridge \
		-highlightthickness 0
	scrollbar $parent.${s}sx -orient horizontal -command \
		[list FF_ScrollSet_$s xview] -relief ridge \
		-highlightthickness 0
	# column headers
	set c [text $parent.${s}header -xscrollcommand [list $parent.${s}sx set] -width 1 -height 1 -highlightthickness 0 -cursor top_left_arrow -bd 0]
	set f [frame $c.f]
	button $f.1 -highlightthickness 0 -bd 1 -padx 0 -pady 0
	button $f.2 -highlightthickness 0 -bd 1 -padx 0 -pady 0
	button $f.3 -highlightthickness 0 -bd 1 -padx 0 -pady 0
	button $f.4 -highlightthickness 0 -bd 1 -padx 0 -pady 0
	button $f.5 -highlightthickness 0 -bd 1 -padx 0 -pady 0
	button $f.6 -highlightthickness 0 -bd 1 -padx 0 -pady 0
	button $f.7 -highlightthickness 0 -bd 1 -padx 0 -pady 0

	grid $f.1 $f.2 $f.3 $f.4 $f.5 $f.6 $f.7 -sticky ew -ipadx 0 -ipady 0
	$c window create 0.0 -window $f -align center -stretch 1 -padx 0 -pady 0
	$c config -state disabled
	
	# directory row
	set t [frame $parent.$s]
	button $t.evfs -text E -padx 1 -pady 0 -command [list ExitVFS $s]
	button $t.dirup -text .. -padx 1 -pady 0 -command [list dirUp $s]
	button $t.dirroot -text / -padx 3 -pady 0 \
		-command [list dirRoot $s]
	
	set xf(pathEnt_$s) [entry $t.e \
		-textvariable xf(pathi$s) -relief sunken]
	entry $t.mask -textvariable xf(mask$s) -width 4
	
	checkbutton $t.hide -text H -padx 2 -pady 1 \
		-variable xf(hiddens_$s)\
		-indicatoron false -command [list HiddenMode $s] \
		-selectcolor palevioletred1
	
	button $t.all -text A -padx 1 -pady 0 \
		-command [list SelectAll $s]
	button $t.no -text N -padx 1 -pady 0 \
		-command [list ClearSelection $s]

	if {[string compare left $s] == 0} {
	    button $t.copy -padx 0 -pady 0 -image $xf_image(c_left) \
		    -command Copyleft -cursor left_side -highlightthickness 1
	    grid $t.evfs $t.dirroot $t.dirup $t.e $t.mask $t.hide $t.all $t.no $t.copy -sticky news
	    grid columnconfigure $t 3 -weight 1
	} {
	    button $t.copy -padx 0 -pady 0 -image $xf_image(c_right) \
		    -command CopyRight -cursor right_side -highlightthickness 1
	    grid $t.copy $t.no $t.all $t.hide $t.e $t.mask $t.dirup $t.dirroot $t.evfs -sticky news
	    grid columnconfigure $t 4 -weight 1
	}
	grid remove $t.evfs

	# info row
	set t [frame $parent.${s}info]
	set xf(fsE_$s) [entry $t.fs -relief sunken -bd 2 \
		-textvariable xf(fstype$s) \
		-state disabled -justify center -bg "#404040" -fg "#ffff60" \
		-highlightthickness 0 -exportselection 0 \
		-cursor top_left_arrow -width 8]
	
	set xf(infoEnt_$s) [entry $t.info -relief sunken -bd 2\
		-textvariable xf(infoA$s) -state disabled -justify left\
		-bg "#404040" -fg "#ffff60" -highlightthickness 0 \
		-exportselection 0 -cursor top_left_arrow]
	#-font [option get $xf(fuf).leftlist font {}]]
	
	entry $t.df -relief sunken -bd 2 -textvariable xf(df$s) \
		-state disabled -justify center -bg "#404040" -fg "#ffff60" \
		-highlightthickness 0 -exportselection 0 \
		-cursor top_left_arrow -width 12
	
	button $t.log -text Log... -padx 1 -pady 0 \
		-command [list ShowLog $s] -bd 0 \
		-bg "#404040" -fg "#ffff60" -activebackground "#404040"\
		-activeforeground "#ffff60" -font *times*6* \
		-highlightthickness 0
	bindtags $t.fs [list XF . all]
	bindtags $t.df [list XF . all]
	bindtags $t.info [list XF . all]
	bindtags $t.log [list XF $parent.logr Button . all]
	
	if {[string match $s left]} {
	    grid $t.log $t.fs $t.info $t.df -sticky news
	    grid columnconfigure $t 2 -weight 1
	} {
	    grid $t.df $t.info $t.fs $t.log -sticky news
	    grid columnconfigure $t 1 -weight 1
	}
	if {$xf(log) == 0} {
	    grid remove $t.log
	}


	# popup menu
	set popup [menu $parent.${s}list.popup_menu -tearoff 0 \
		-relief ridge -bd 4 -bg grey80]
	#$popup add command -label "Previous Dir" -command [list PreviousDirectory $s]
	#$popup add separator
	$popup add command -label "Copy" -command [list PopupOps $s "cp"]
	$popup add command -label "Copy To" -command [list CopyTo $s]
	$popup add command -label "Move" -command [list PopupOps $s "mv"]
	$popup add command -label "Move To" -command [list MoveTo $s]
	$popup add separator
	$popup add cascade -label "Delete" -menu $popup.sub
	set popup.sub [menu $popup.sub -tearoff 0]
	$popup.sub add command -label "Yes!" -command [list PopupOps $s "rm"]\
		-activebackground "#ff0000" -background "#ffa0a0"
	set flag 1
	set a 1
	while {[string compare {} "[option get .xfiles popup_user_item_$a {}]"]} {
	    set xf(popup_user$a) "[option get .xfiles popup_user_item_$a {}]"
	    if {$flag} {
		set popup.user [menu $popup.user -tearoff 0]
		$popup add separator
		$popup add cascade -label "User" -menu $popup.user \
			-font "[option get $xf(fuf).${s}list.popup_menu.user font {}]"
		set flag 0
	    }
	    $popup.user add command -label [lindex $xf(popup_user$a) 0] \
		    -command [list PopupOps $s "$a" [lindex $xf(popup_user$a) 1]]
	    unset xf(popup_user$a)
	    incr a
	}
    }

    button $parent.swap -padx 0 -pady 0 -image $xf_image(swap) \
	    -command {Swap_sides} -cursor exchange -highlightthickness 1

    if {$xf(reversi) == 0} {
	grid $parent.left - $parent.right - -sticky news
    } {
	grid $parent.leftinfo - $parent.rightinfo - -sticky news
    }
    grid $parent.leftheader $parent.swap - $parent.rightheader -sticky news

    grid $parent.leftlist $parent.leftsy $parent.rightsy $parent.rightlist -sticky news
    grid $parent.leftsx x x $parent.rightsx -sticky news
    if {$xf(reversi) == 0} {
	grid $parent.leftinfo - $parent.rightinfo - -sticky news
    } {
	grid $parent.left - $parent.right - -sticky news
    }
    
    grid rowconfigure $parent 2 -weight 1
    grid columnconfigure $parent {0 3} -weight 1
}
proc PopupOps {s op {command {}}} {
    global xf

    switch $op {
	cp -
	mv -
	rm {
	    if {[string compare {} $xf(selekted$s)] == 0} {
		NoSelect $s
		return
	    } {
		FileOps $op $s
	    }
	}
	default {
	    Executer [lrange $command 0 end] [GetSelNames $s] $s "\[Pop-menu\]"
	}
    }
    if {$xf(clearselect) == 1} {
	UnselectAll $s
	update idletasks
	set xf(clearselect) 0
    }
}

# trial: listitem is {name ext size mode mtime owner group link}
proc FileList {s dir} {
    global xf vfs ftp ftpcac vdleft vdright vfleft vfright

    # if the other side is in short FTP mode, column format is not correct
    #MakeColumnFormat
#    set tt [time {
    set dirup 0
    #puts "FileList: $dir"
    if {$xf(redraw$s) == 0 || $xf(ftp.update) == 1} {
	catch {unset vd$s vf$s}
	if {$xf(smode_$s) < 2} {
	    # if CopyTo, do not reset value
	    set xf(smode_$s) 0
	}
	set vd$s {}
	set vf$s {}

	switch $xf(fsmode_$s) {
	    0 {
		if {$xf(smode_$s) != 3} {
		    # normal
		    $xf(fuf).${s}list config -bg [option get $xf(fuf).${s}list background {}]
		    if {![file executable $dir] || ![file readable $dir]} {
			SetArrowPointer
			set dirup 1
			set xf(no_aud_$s) 1
			InvalidPath $s "You have no permissions there!"
			unset xf(no_aud)
			#DefaultInfo $s
			#MessageBox "You have no permissions here!" $s
			return
			#break
		    }

		    if {[string compare $dir [lindex [file split $xf(pathi$s)] 0]] != 0} {
			set dirup 1
		    }
		    
		    if {!$xf(hiddens_$s)} {
			set files [glob -nocomplain -- ${dir}$xf(mask$s)]
		    } {
			set files [glob -nocomplain -- $dir{.$xf(mask$s),$xf(mask$s)}]
		    }
		    set clip 0
		} {
		    # HyperList
		    # check masks
		    set files {}
		    foreach f $xf(do_list_0) {
			if {[FL_VFS_Display $s [file tail $f]]} {
			    lappend files $f
			}
		    }
		    set clip 1
		    set dirup 1
		}
		

		foreach f $files {
		    # check if changes on filesystem since glob
		    if {![file exists $f]} {continue}
		    if {[string match directory [set t [file type $f]]]} {
			# skip . and ..
			if {[string match {*\.} $f] == 0 && \
				[string match {*\.\.} $f] == 0} {
			    lappend vd$s [FL_AddItem $f $xf(cf_$s) $clip 1]
			    #incr id
			}
		    } {
			switch $t {
			    link {
				if {[catch {set point [file readlink $f]}]} {
				    set linkdir 0
				    set lcatch 1
				} {
				    set lcatch 0
				    if {[file isdirectory [file join $dir $point]]} {
					set linkdir 1
				    } {
					set linkdir 0
				    }
				}
				if {$linkdir} {
				    if {$xf(links)} {
					set link " -> $point"
				    } {
					set link @
				    }
				    lappend vd$s [lreplace [FL_AddItem $f $xf(cf_$s) $clip 1] end end $link]
				} {
				    set link @
				    if {$lcatch} {
					set size [string length $f]
				    } {
					set size [string length $point]
					if {$xf(links)} {
					    set link " -> $point"
					}
				    }
				    set row [FL_AddItem $f $xf(cf_$s) $clip ]
				    set row [lreplace $row 2 2 $size]
				    set row [lreplace $row end end $link]
				    lappend vf$s $row
				}
			    }
			    characterSpecial -
			    blockSpecial {
				lappend vf$s [lreplace [FL_AddItem $f $xf(cf_$s) $clip] 2 2 "-Dev-"]
			    }
			    default {
				lappend vf$s [FL_AddItem $f $xf(cf_$s) $clip]
			    }
			}
		    }
		}
		# update AutoUD information
		catch {set xf(${s}autoud) [file mtime $dir]}
	    }
	    1 -
	    2 -
	    5 -
	    6 -
	    3 {
		$xf(fuf).${s}list config -bg [option get .xfiles vfs_mode_bg {}]
		# TODO
		#if {[regexp {^...:/(.*)$} $dir gfg new] == 1} {
		 #   set dir $new
		#}
		FL_VFS $s $dir vfs vd$s vf$s
		set dirup 1
	    }
	    4 {
		# FTP
		if {$xf(smode_$s) == 3} {
		    # HyperList mode
		    set xf(cf_$xf(bgact.side)) "\[format \"%-[lindex $xf(cf.name) 1]s\n\" \$name\]"

		    # check masks
		    foreach l $xf(do_list_4) {
			if {[string match */ $l]} {
			    # dir
			    if {[FL_VFS_Display $s [file tail $l]]} {
				lappend vd$s [list [file rootname $l] [file extension $l] 0 {} {} {} {} {}]
			    }
			} {
			    # file
			    if {[FL_VFS_Display $s [file tail $l]]} {
				lappend vf$s [list [file rootname $l] [file extension $l] 0 {} {} {} {} {}]
			    }
			}
		    }
		} {
		    # normal FTP
		    $xf(fuf).${s}list config -bg [option get .xfiles vfs_mode_bg {}] -state normal
		    
		    if {$xf(ftp.shortlist)} {
			set xf(cf_$xf(bgact.side)) "\[format \"%-[lindex $xf(cf.name) 1]s\n\" \$name\]"
		    } {
			MakeColumnFormat $xf(bgact.side)
		    }
		    
		    #puts "FTP $dir"
		    #puts "ftpcac: [lsort [array names ftpcac]]"
		    if {[info exists ftpcac($dir)] == 0 || $xf(ftp.update) == 1} {
			# either not cached or forced update

			$xf(fuf).${s}list delete 0.0 end
			$xf(fuf).${s}list insert 0.0 "Retrieving file listing..."
			$xf(fuf).${s}list config -state disabled

			if {$xf(ftp.update)} {
			    Log $s "FTP forced update: $dir" 3
			} {
			    Log $s "FTP directory not cached: $dir" 3
			}
			# check timeout
			if {[FO_CheckFTPTimeOut $s $xf(ftp.sock)]} {
			    return
			}
			set xf(ftp.update) 0
			if {[FTP_CMD $xf(ftp.sock) "CWD $dir"] == -1} {
			    # path not ok
			    InvalidPath $s $ftp($xf(ftp.sock).status)
			    return
			}
			SetPaths $s $dir

			set xf(ftp.enable_count) 1
			after 100 [list FL_FTP_listcount $s]

			# get long/short list
			if {[FTP_LIST $xf(ftp.sock) $xf(ftp.shortlist) $xf(ftp.active)] == -1} {
			    # error, list is empty
			    MessageBox "Unable to get file listing...\n\n$ftp($xf(ftp.sock).status)" $s
			    set xf(ftp.enable_count) 0
			    return
			}
			set xf(ftp.enable_count) 0
			
			set xf(df$s) "Parsing..."
			update idletasks

			# we have a listing
			#DEBUG ">$ftp($xf(ftp.sock).readed)<"
			set filelist [split $ftp($xf(ftp.sock).readed) \n]
			#DEBUG "FTP:\n$filelist"
			
			#set id 2
			# init cache vars
			set ftpcac($dir) {}
			set ftpcac(${dir}dirs) {}
			if {$xf(ftp.shortlist)} {
			    # short listing
			    set filelist [lreplace $filelist 0 0]
			    foreach l $filelist {
				if {[string match */ $l]} {
				    # dir
				    # cache
				    lappend ftpcac(${dir}dirs) [list $l {} 0 {} {} {} {} {}]
				    if {[FL_VFS_Display $s $l]} {
					lappend vd$s [list $l {} 0 {} {} {} {} {}]
				    }
				} {
				    # file
				    set f [string trimright $l \*]
				    set link {}
				    if {[string match *@ $f]} {
					set f [string trimright $f @]
					set link @
				    }
				    # cache
				    lappend ftpcac($dir) [list $f {} 0 {} {} {} {} $link]
				    if {[FL_VFS_Display $s $l]} {
					lappend vf$s [list $f {} 0 {} {} {} {} $link]
				    }
				}
			    }
			} {
			    # long listing
			    #set filelist [lreplace $filelist 0 0]
			    foreach l $filelist {
				# if listing includes . and .. items, remove them
				# also empty and "total" statements
				if {[llength $l] <= 2 || \
					[string match *\. $l] || \
					[string match *\.\. $l]} {
				    # skip . and ..
				    DEBUG "FTP dropped: $l"
				    continue
				}
				# workaround for AIX incompatibility
				set y [lindex $l 5]
				set nid [expr {[string first $y $l] + 13}]
				
				switch -- [string index $l 0] {
				    b -
				    c {
					# block or character device
					# recalculate the name index
					# TODO does not work with AIX, is there a need?
					set y [lindex $l 6]
					set nid [expr {[string first $y $l] + 13}]
					set row [lreplace [FL_AddFTPItem $l $nid $xf(cf_$s) 0 1] 2 2 "-Dev-"]
					lappend ftpcac($dir) $row
					if {[FL_VFS_Display $s [string range $l $nid end]]} {
					    lappend vf$s $row
					}
				    }
				    d {
					# dir
					set row [FL_AddFTPItem $l $nid $xf(cf_$s) 1]
					lappend ftpcac(${dir}dirs) $row
					if {[FL_VFS_Display $s [string range $l $nid end]]} {
					    lappend vd$s $row
					}
				    }
				    l {
					# link
					#set row [FL_AddFTPItem $l $nid $xf(cf_$s)]
					set temp [string range $l $nid end]
					set ag [string first " -> " $temp]
					regsub {^~} [string range $temp 0 [expr {$ag-1}]] \.\/\~ tail
					regsub {^\.\/\~} [file rootname $tail] \~ name
					
					if {[string match {*/} $temp]} {
					    # points to dir
					    #FL_AddFTPItem vd$s $id $l $nid $xf(cf_$s) 1
					    set ext [file extension $tail]/
					    if {$xf(links)} {
						set link [string range $temp $ag end]
					    } {
						set link @
					    }
					    set row [lreplace [FL_AddFTPItem $l $nid $xf(cf_$s) 1] 0 1 $name $ext]
					    set row [lreplace $row end end $link]
					    #lappend vd$s $row
					    set dirri 1
					} {
					    # points to file
					    set ext [file extension $tail]
					    if {$xf(links)} {
						set link [string range $temp $ag end]
					    } {
						set link @
					    }
					    set row [lreplace [FL_AddFTPItem $l $nid $xf(cf_$s)] 0 1 $name $ext]
					    set row [lreplace $row end end $link]
					    #lappend vf$s $row
					    set dirri 0
					}
					if {$dirri} {
					    lappend ftpcac(${dir}dirs) $row
					} {
					    lappend ftpcac($dir) $row
					}
					# the name arg here must be like this, since 
					# if the filename starts with a dot -> var name 
					# is empty and extension holds the string
					if {[FL_VFS_Display $s $name[file extension $tail]]} {			    
					    if {$dirri} {
						lappend vd$s $row
					    } {
						lappend vf$s $row
					    }
					}
				    }
				    default {
					# file
					set row [FL_AddFTPItem $l $nid $xf(cf_$s)]
					lappend ftpcac($dir) $row
					if {[FL_VFS_Display $s [string range $l $nid end]]} {
					    lappend vf$s $row
					    #FL_AddFTPItem vf$s $if $l $nid $xf(cf_$s)
					    #incr if
					}
				    }
				}
			    }
			    # cache long FTP list
			    #FL_CacheFTP $dir vd$s vf$s
			}
			set ftp($xf(ftp.sock).readed) {}
			unset filelist
		    } {
			# cached FTP dir
			SetPaths $s $dir
			Log $s "FTP directory cached: $dir" 3
			FL_VFS $s $dir ftpcac vd$s vf$s
		    }
		    #puts "ftpcac: [lsort [array names ftpcac]]"
		}
		set dirup 1
	    }
	}
	#$xf(pathEnt_$s) delete 0 end
	#$xf(pathEnt_$s) insert 0 $dir
	$xf(pathEnt_$s) xview moveto 1
	$xf(pathEnt_$s) icursor end

    } { ;# if $redraw...
	if {$xf(fsmode_$s) == 0 && [string compare $dir [lindex [file split $xf(pathi$s)] 0]] == 0} {
	    set dirup 0
	} {
	    set dirup 1
	    set vd$s [lrange [set vd$s] 1 end]
	}
    }
    set xf(redraw$s) 0
    HyperListSettings $s

    switch $xf(sortby_$s) {
	0 {
	    set vd$s [lsort -$xf(sortorder_$s) -index 0 [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -index 0 [set vf$s]]
	}
	1 {
	    # sort by extension
	    set vd$s [lsort -$xf(sortorder_$s) -index 1 [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -index 1 [set vf$s]]
	}
	2 {
	    # not for LHA or FTP, check is needed here if mtime sort
	    # was on when entering LHA- or FTP-mode
	    if {$xf(fsmode_$s) != 3 && $xf(fsmode_$s) != 4} {
		# sort by mtime
		set vd$s [lsort -$xf(sortorder_$s) -command FL_CompareMTime [set vd$s]]
		set vf$s [lsort -$xf(sortorder_$s) -command FL_CompareMTime [set vf$s]]
	    } {
		# FTP and LHA do not have valid times, but we can do string compare 
		# TODO of course we cannot... STUPIDO
		set vd$s [lsort -$xf(sortorder_$s) -index 4 [set vd$s]]
		set vf$s [lsort -$xf(sortorder_$s) -index 4 [set vf$s]]
	    }
	}
	3 {
	    # sort by name case insensitive
	    set vd$s [lsort -$xf(sortorder_$s) -dictionary -index 0 [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -dictionary -index 0 [set vf$s]]
	}
	4 {
	    # sort by size
	    set vd$s [lsort -$xf(sortorder_$s) -command FL_CompareSize [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -integer -index 2 [set vf$s]]
	}
	5 {
	    # sort by protections
	    set vd$s [lsort -$xf(sortorder_$s) -index 3 [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -index 3 [set vf$s]]
	}
	6 {
	    # sort by owner
	    set vd$s [lsort -$xf(sortorder_$s) -index 5 [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -index 5 [set vf$s]]
	}
	7 {
	    # sort by group
	    set vd$s [lsort -$xf(sortorder_$s) -index 6 [set vd$s]]
	    set vf$s [lsort -$xf(sortorder_$s) -index 6 [set vf$s]]
	}
	default {}
    }
    if {$dirup} {
	set vd$s [linsert [set vd$s] 0 {.. / {} {} {} {} {} {}}]
    }

    $xf(fuf).${s}list config -state normal
    $xf(fuf).${s}list delete 0.0 end
    
    if {[string match "left" $s]} {
	foreach row $vdleft {
	    FL_LbInsert $s end [FormatFileName [lindex $row 0] [lindex $row 1][lindex $row end]] [lindex $row 2] [lindex $row 3] [lindex $row 4] [lindex $row 5] [lindex $row 6] 1
	}
	foreach row $vfleft {
	    FL_LbInsert $s end [FormatFileName [lindex $row 0] [lindex $row 1][lindex $row end]] [lindex $row 2] [lindex $row 3] [lindex $row 4] [lindex $row 5] [lindex $row 6]
	}
    } {
	foreach row $vdright {
	    FL_LbInsert $s end [FormatFileName [lindex $row 0] [lindex $row 1][lindex $row end]] [lindex $row 2] [lindex $row 3] [lindex $row 4] [lindex $row 5] [lindex $row 6] 1
	}
	foreach row $vfright {
	    FL_LbInsert $s end [FormatFileName [lindex $row 0] [lindex $row 1][lindex $row end]] [lindex $row 2] [lindex $row 3] [lindex $row 4] [lindex $row 5] [lindex $row 6]
	}
    }
    $xf(fuf).${s}list mark set anchor 1.0
    $xf(fuf).${s}list config -state disabled

    if {$xf(fsmode_$s) == 4} {
	# if FTP, clear misc info
	set xf(df$s) {}
	update idletasks
    }
#} 2]
#puts "TIME $dir: $tt"
}

proc FL_FTP_listcount {s} {
    global xf ftp

    if {$xf(ftp.enable_count)} {
	if {[info exists ftp($xf(ftp.sock).datasock)] \
		&& [info exists ftp($ftp($xf(ftp.sock).datasock).rows)]} {
	    set xf(df$s) "$ftp($ftp($xf(ftp.sock).datasock).rows) lines..."
	    update idletasks
	}
	after 100 [list FL_FTP_listcount $s]
    }
}

proc FL_AddItem {f column_format clip {dir 0}} {
    if {$clip} {
	# HyperList mode
	set tail $f
    } {
	regsub {^~} [file tail $f] \.\/\~ tail
    }
    regsub {^\.\/\~} [file rootname $tail] \~ name
    lappend item $name
    if {$dir == 1} {
	lappend item [file extension $tail]/
	set size "<Dir>"
    } {
	lappend item [file extension $tail]
	set size [file size $f]
    }
    lappend item $size

    if {[regexp {prot} $column_format]} {
	lappend item [BitsProc $f]
    } {
	lappend item ""
    }
    if {[catch {set time [clock format [file mtime $f] -format "%d %b %y %H:%M"]}]} {
	# TODO: empty or N/A
	lappend item N/A
    } {
	lappend item $time
    }
    # these two only for unix...
    if {[regexp {owne} $column_format]} {
	if {[catch {lappend item [file attributes $f -owner]}]} {
	    lappend item N/A
	}
    } {
	lappend item N/A
    }
    if {[regexp {grou} $column_format]} {
	if {[catch {lappend item [file attributes $f -group]}]} {
	    lappend item N/A
	}
    } {
	lappend item N/A
    }
    # link
    lappend item {}
    return $item
}
proc FL_VFS {s dir arr var1 var2} {
    upvar $arr vfs $var1 ad $var2 af
    global xf

    foreach row $vfs(${dir}dirs) {
	if {[FL_VFS_Display $s [lindex $row 0][lindex $row 1]]} {
	    lappend ad $row
	}
    }
    foreach row $vfs($dir) {
	if {[FL_VFS_Display $s [lindex $row 0][lindex $row 1]]} {
	    lappend af $row
	}
    }
}
# Check if given FTP item should be displayed.
proc FL_VFS_Display {s item} {
    global xf

    # check hidden mask
    if {$xf(hiddens_$s) == 0 && [string match {\.*} $item]} {
	return 0
    }
    # check file mask
    if {[string match $xf(mask$s) $item] == 0} {
	return 0
    }
    return 1
}
proc FL_CacheFTP {dir var1 var2} {
    upvar $var1 ad $var2 af
    global vfs

    foreach row $ad {
	lappend vfs(${dir}dirs) $row
    }
    foreach row $af {
	lappend vfs($dir) $row
    }
}
proc FL_AddFTPItem {row nid column_format {dir 0} {dev 0}} {
    regsub {^~} [string range $row $nid end] \.\/\~ tail
    regsub {^\.\/\~} [file rootname $tail] \~ name
    # name
    lappend item $name
    if {$dir} {
	# ext
	lappend item [file extension $tail]/
	# size
	lappend item "<Dir>"
    } {
	# ext
	lappend item [file extension $tail]
	# size
	lappend item [lindex $row 4]
    }
    # mode
    lappend item [lindex $row 0]
    # mtime
    #if {$dev} {
	#lappend item [lrange $row 6 8]
    #} {
	lappend item [lrange $row 5 7]
    #}
    # owner
    lappend item [lindex $row 2]
    # group
    lappend item [lindex $row 3]
    # link
    lappend item {}
    return $item
}
proc FL_Selection {s} {
    global xf

    set ll {}
    foreach {b e} [$xf(fuf).${s}list tag ranges sel] {
	for {set i $b} {$i < $e} {set i [expr {$i + 1.0}]} {
	    regexp {^[^\.]*} $i ind
	    lappend ll [expr {$ind - 1}]
	}
    }
    return $ll
}

# TODO: extension matching or pattern matching? :)
proc MakeTagMatch {} {
    global tag_match tags xf

    set tag_match "switch -glob -- \$name \{\n"
    foreach t $tags(tags) {
	for {set i 0} {$i < [expr {[llength $tags($t.list)]-1}]} {incr i} {
	    append tag_match "*[lindex $tags($t.list) $i] -\n"
	}
	append tag_match "*[lindex $tags($t.list) $i] \{\$xf(fuf).\$\{s\}list insert \$p \[subst \$xf(cf_\$s)\] $t\}\n"
    }
    append tag_match "default \{\$xf(fuf).\$\{s\}list insert \$p \[subst \$xf(cf_\$s)\]\}\n"
    append tag_match "\}\n"

    foreach s {left right} {
	# default
	eval $xf(fuf).${s}list config $xf(text.attr)
	eval $xf(fuf).${s}list config $tags(DEFAULT.attr)

	# change column header font
	ColumnHeaders $s
	# other tags
	foreach t "DIR $tags(tags)" {
	    $xf(fuf).${s}list tag delete $t
	    eval $xf(fuf).${s}list tag configure $t $tags($t.attr)
	}
    }

}
proc FL_LbInsert {s p name size prot mtim owne grou {dir 0}} {
    global xf tag_match

    if {$dir == 1} {
	#$xf(fuf).${s}list insert $p [subst $column_format] DIR
	$xf(fuf).${s}list insert $p [subst $xf(cf_$s)] DIR
    } {
	eval $tag_match
    }
}
proc FL_CompareMTime {a b} {
    #puts "$a :: $b"
    set rc [string compare [clock scan [lindex $a 4]] [clock scan [lindex $b 4]]]
    if {$rc != 0} {
	return $rc
    } {
	return [string compare $a $b]
    }
}
proc FL_CompareSize {a b} {
    set ai [lindex $a 2]
    set bi [lindex $b 2]
    if {$ai < $bi} {
	return -1
    } elseif {$ai > $bi} {
	return 1
    } {
	return [string compare $a $b]
    }
}
proc FormatFileName {name ext} {
    global xf

    set w [lindex $xf(cf.name) 1]
    set n [string length $name]
    set e [string length $ext]
    if {[set of [expr {$n+$e-$w}]] > 0} {
	if {$n-$of > $e} {
	    return [string range $name 0 [expr {$n-$of-3}]]..$ext
	} elseif {$e-$of > $n} {
	    return $name..[string range $ext [expr {$of+2}] end]
	} {
	    return [string range $name 0 [expr {$n-($of/2)-2}]]..[string range $ext [expr {($of/2)+2}] $e]
	}
    }
    return $name$ext
}
proc SetPaths {s path {nohist 0}} {
    global xf

    #puts "DEBUG: SetPaths($path)"
    if {$nohist == 0} {
	History $s
    }
    # TODO
    #set p [TildeSubst $path $s]
    #switch $xf(fsmode_$s) {
#	0 {set pre {}}
#	1 {set pre zip:/}
#	2 {set pre tar:/}
#	3 {set pre lha:/}
#	4 {set pre ftp:/}
#	5 {set pre rpm:/}
#	6 {set pre rar:/}
    #}
    #set xf(pathi$s) $pre$p
    set xf(pathi$s) [TildeSubst $path $s]
    set xf(backup_$s) $xf(pathi$s)
    set xf(parent_$s) [GetParentDir $xf(pathi$s)]
    after idle [list Log $s "CWD: $xf(pathi$s)" 2]
}

proc BitsProc {f} {
    global tcl_platform

    if {![catch {file stat $f arr}]} {
	if {[string match {unix} $tcl_platform(platform)]} { 
	    switch [file type $f] {
		directory {set d "d"}
		link {
		    set d "l"
		    catch {file lstat $f arr}
		}
		characterSpecial {set d "c"}
		blockSpecial {set d "b"}
		socket {set d "s"}
		fifo {set d "p"}
		default {set d "-"}
	    }
	    set m [format "%03d" [expr {[format "%o" $arr(mode)] % 1000}]]
	    return [GetBitsFromInt $m $d]
	} { ;# windows
	    if {[catch {set ro [file attributes $f -readonly]}]} {
		return ""
	    } {
		if {$ro} {
		    append d "R"
		} {
		    append d "-"
		}
		if {[file attributes $f -hidden]} {
		    append d "H"
		} {
		    append d "-"
		}
		if {[file attributes $f -system]} {
		    append d "S"
		} {
		    append d "-"
		}
		if {[file attributes $f -archive]} {
		    append d "A"
		} {
		    append d "-"
		}
		return $d
	    }
	}
    } {
	return "N/A"
    }
}
proc GetBitsFromInt {int d} {
    for {set i 0} {$i < 3} {incr i} {
	set c [string index $int $i]
	switch $c {
	    7 {append d "rwx"}
	    6 {append d "rw-"}
	    5 {append d "r-x"}
	    4 {append d "r--"}
	    3 {append d "-wx"}
	    2 {append d "-w-"}
	    1 {append d "--x"}
	    0 {append d "---"}
	}
    }
    return $d
}
proc Mount {s dev} {
    global xf

    if {[catch {open /etc/fstab r} fstab]} {
	MessageBox "\[Mount\]: Unable to open file '/etc/fstab'"
	return
    }
    set con [split [read $fstab] \n]
    close $fstab
    set ind [lsearch $con $dev*]
    if {$ind == -1} {
	MessageBox "\[Mount\]: There has to be a line \"$dev\t<mountpoint>\t<filesys>\tdefaults,exec,user 0 0\" in the file /etc/fstab" $s
	return
    }
    cd /
    #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    catch {exec umount $dev} err
    if {[string match {*device is busy*} $err]} {
	MessageBox "\[Mount\]: Somebody is accessing $dev\nUnable to unmount..." $s
	return
    }
    catch {exec mount $dev} err
    if {[string match {*not a valid block device*} $err]} {
	MessageBox "\[Mount\]: The device cannot be mounted! If floppy or cd-rom, please insert the disk and try again." $s
	return
    }
    set dir [lindex [lindex $con $ind] 1]
    #History $s
    SetPaths $s $dir/
    NullSelect $s
    FileList $s $xf(pathi$s)
    DefaultInfo $s
}
proc FileOK {s f button {link {}}} {
    global xf vfs ftp stop_calc TMP vfsmap

    if {$xf(fsmode_$s) == 4 && [string match {Busy*} $ftp($xf(ftp.sock).status)]} {
	# in FTP mode and busy
	#puts "FTP Busy"
	MessageBox "FTP connection is busy!" $s
	return
    }
    
    if {[string compare $s "left"] == 0} {
	set o "right"
    } {
	set o "left"
    }

    #DEBUG "FileOK: <$f>"
    #DEBUG "BUTTON: >$button<"
    if {[string match $f $xf(backup_$s)] && \
	    [$xf(fuf).${s}list index end] > 2.0 && \
	    $xf(smode_$s) == 0} {
	set xf(pathi$s) $f
	$xf(pathEnt_$s) xview moveto 1
	$xf(pathEnt_$s) icursor end
	return
    }

    if {[regexp {^\.\.\/} $f]} {
	if {$xf(MMB_opens_other) && [string compare $button M] == 0} {
	    # open parent to opposite
	    SetPaths $o $xf(pathi$s)
	    dirUp $o
	    DefaultInfo $o
	} {
	    dirUp $s
	    DefaultInfo $s
	}
	return
    }

    if {[string match {/} $f]} {
	dirRoot $s
	DefaultInfo $s
	return
    }
    if {[string compare {} $button] == 0} {
	# path was written, take it as is
	set pathway $f
    } {
	# dir/file was clicked on
	# MKi 15.3.98 cannot use file join here 
	#  (if $f starts with tilde -> trouble)
	if {[regexp {^~} $f]} {
	    set pathway $xf(pathi$s)$f
	} {
	    # we must preserve the trailing slash if one exists
	    if {[string match */ $f]} { 
		set pathway [file join $xf(pathi$s) $f]/
	    } {
		set pathway [file join $xf(pathi$s) $f]
	    }
	}
    }
    #DEBUG $pathway
    if {$xf(fsmode_$s) == 0} {
	#set pathway $xf(pathi$s)$f
	#puts "FileOK: $pathway"
	if {[file isdirectory $pathway]} {
	    set stop_calc 1
	    $xf(fuf).${s}list config \
		    -selectbackground [option get .xfiles selectBg_$s {}]
	    #History $s
	    if {$xf(MMB_opens_other) && [string compare $button M] == 0} {
		# open dir to opposite
		SetPaths $o $pathway
		FileList $o $xf(pathi$o)
		DefaultInfo $o
	    } {
		# normal open
		NullSelect $s
		SetPaths $s $pathway
		
		FileList $s $xf(pathi$s)
	    }
	    DefaultInfo $s
	    return
	} {
	    if {[file exists $pathway]} {
		QuickExe $f $button $xf(pathi$s) $s
		return
	    }
	}
    } {
	# VFS
	#DEBUG "$f :: $pathway"
	if {[string match */ $pathway]} {
	    set stop_calc 1
	    $xf(fuf).${s}list config \
		    -selectbackground [option get .xfiles selectBg_$s {}]
	    if {$xf(fsmode_$s) != 4} {
		# ZIP, TAR, LHA, RPM, RAR
		if {[info exists vfs($pathway)]} {
		    # LB DB1
		    SetPaths $s $pathway
		} elseif {[info exists vfs($f)]} {
		    # path written
		    SetPaths $s $f
		} {
		    InvalidPath $s
		    return
		}
	    } {
		# FTP
		if {[string compare {} $button] == 0} {
		    # path written
		    set xf(pathi$s) $f
		} {
		    # LB DB1
		    set xf(pathi$s) $pathway
		}
	    }
	    NullSelect $s
	    FileList $s $xf(pathi$s)
	    DefaultInfo $s
	    return
	} {
	    # virtual file
	    set cac $xf(fsmode_$s).$pathway
	    if {![info exists vfsmap($cac)]} {
		set cached 0
		# if not already cached
		#puts "VOUTP: new file"
		set tmp $TMP(dir)vfs[incr TMP(idx)]/$f
		file mkdir [file dirname $tmp]

		# get the file out of the VFS
		if {$xf(fsmode_$s) == 4} {
		    # FTP
		    # if link, test whether it is a directory
		    #puts "FTP: <$link>"
		    if {[string compare {} $link] != 0} {
			#puts "FTP: link $link"
			# check for timeout
			if {[FO_CheckFTPTimeOut $s $xf(ftp.sock)]} {
			    return
			}
			if {[FTP_CMD $xf(ftp.sock) "CWD $pathway"] == 1} {
			    # it is directory, action
			    set xf(pathi$s) [string trimright $pathway /]/
			    NullSelect $s
			    FileList $s $xf(pathi$s)
			    DefaultInfo $s
			    return
			}
			# no, is a file
			#if {[regsub -- { -> } $link {} link]} {
			 #   set pathway [file join $xf(pathi$s) $link]
			#}
		    }
		    # show progress bar
		    XF_ProgressBar $xf(ftp.sock)
		}

		if {[VirtualOut $s [string trimleft $pathway /] $tmp]} {
		    # error, msg is already shown
		    XF_PBFinal
		    return
		}
		XF_PBFinal
		# store file name for possible future use
		set vfsmap($cac) $tmp
	    } {
		set cached 1
		#puts "VOUTP: cached file"
	    }
	    QuickExe [file tail $vfsmap($cac)] $button [file dirname $vfsmap($cac)] $s $cached
	    #parray vfsmap
	    DefaultInfo $s
	    return
	}
    }
    #puts "FileOK outo BAA"
    if {[file isdirectory $f]} {
	#puts BAA2 
	set stop_calc 1
	#History $s
	SetPaths $s $f
	NullSelect $s

	FileList $s $f
	DefaultInfo $s
	return
    }
    #puts BAA2.1
    if {[file exists [string trimright $f /]]} {
	#puts BAA3
	SetPaths $s [GetParentDir $f]
	NullSelect $s
	FileList $s $xf(pathi$s)
	DefaultInfo $s
	QuickExe [file tail [file dirname $f]] $button [file dirname [file dirname $f]] $s
	return
    } {
	set stop_calc 1
	InvalidPath $s
	return
    }
}
proc InvalidPath {s {err {}}} {
    global xf

    bell
    $xf(fuf).${s}list config -state normal
    $xf(fuf).${s}list delete 0.0 end
    $xf(fuf).${s}list config -state disabled

    MessageBox "Invalid path or filename!:\n$xf(pathi$s)\n$err" $s
    if {[string compare {} [lindex $xf(history_$xf(fsmode_$s)) 0]] == 0} {
	# no history yet...
	SetPaths $s $xf(backup_$s)
    } {
	SetPaths $s [lindex $xf(history_$xf(fsmode_$s)) 0]
    }
    $xf(pathEnt_$s) xview moveto 1
    $xf(pathEnt_$s) icursor end
    FileList $s $xf(backup_$s)
    #InfoChange $s "Invalid path or filename!"
    after 4000 [list DefaultInfo $s]
}

# returns the index that was clicked
proc FileClick {W x y} {
    global xf

    regexp {^[^\.]*} [ClickIndex $W $x $y] i
    $W tag remove sel $i.0 [expr {$i + 1}].0
    #return [GetFileName $s [expr $i - 1]]
    return [expr {$i - 1}]
}

proc GetFileMTime {s ind {file {}}} {
    global xf vdleft vdright vfleft vfright

    if {[info exists xf(copyto_target)] && \
	    [string compare $file {}] != 0} {
	# CopyTo or MoveTo operation, file contains the name of the file
	if {$xf(fsmode_$s) == 0} {
	    return [clock format [file mtime [file join $xf(copyto_target) $file]] -format "%d %b %y %H:%M"]
	} {
	    # TODO FTP olis työläs, muut hiukan helpompia, tarvitaanko?
	    # VFS
	    return " (N/A) "
	}
    }
    if {[string compare $file {}] != 0 && \
	    [string compare {*} $xf(mask$s)] != 0} {
	# mask is on, get from disk
	if {$xf(fsmode_$s) == 0} {
	    return [clock format [file mtime [file join $xf(pathi$s) $file]] -format "%d %b %y %H:%M"]
	} {
	    # TODO FTP olis työläs, muut hiukan helpompia, tarvitaanko?
	    # VFS
	    return " (N/A) "
	}
    }
    if {$ind < [llength [set vd$s]]} {
	set mtim [lindex [lindex [set vd$s] $ind] 4]
    } {
	set ind [expr {$ind-[llength [set vd$s]]}]
	set mtim [lindex [lindex [set vf$s] $ind] 4]
    }
    if {[string compare $mtim {}] == 0} {
	# no mtime
	return " (N/A) "
    }
    return $mtim
}
proc GetFileLink {s ind} {
    global xf vdleft vdright vfleft vfright

    if {$ind < [llength [set vd$s]]} {
	return [lindex [lindex [set vd$s] $ind] 7]
    } {
	set ind [expr {$ind-[llength [set vd$s]]}]
	return [lindex [lindex [set vf$s] $ind] 7]
    }
}
proc GetFileName {s ind} {
    global xf vdleft vdright vfleft vfright

    if {$ind < [llength [set vd$s]]} {
	set row [lindex [set vd$s] $ind]
	return [lindex $row 0][lindex $row 1]
    } {
	set ind [expr {$ind-[llength [set vd$s]]}]
	set row [lindex [set vf$s] $ind]
	return [lindex $row 0][lindex $row 1]
    }
}
proc GetFileSize {s ind {file {}}} {
    global xf vdleft vdright vfleft vfright

    if {[info exists xf(copyto_target)] && \
	    [string compare $file {}] != 0} {
	# CopyTo or MoveTo operation, file contains the name of the file
	if {$xf(fsmode_$s) == 0} {
	    set tmp [file size [file join $xf(copyto_target) $file]]
	} {
	    # TODO FTP olis työläs, muut hiukan helpompia, tarvitaanko?
	    # VFS
	    return " (N/A) "
	}
    } elseif {[string compare $file {}] != 0 && \
	    [string compare {*} $xf(mask$s)] != 0} {
	# mask is on, get from disk
	if {$xf(fsmode_$s) == 0} {
	    set tmp [file size [file join $xf(pathi$s) $file]]
	} {
	    # TODO FTP olis työläs, muut hiukan helpompia, tarvitaanko?
	    # VFS
	    return " (N/A) "
	}
    } {
	if {$ind < [llength [set vd$s]]} {
	    set tmp [lindex [lindex [set vd$s] $ind] 2]
	} {
	    set ind [expr {$ind-[llength [set vd$s]]}]
	    set tmp [lindex [lindex [set vf$s] $ind] 2]
	}
    }
    if {[regexp {[0-9]+} $tmp size] == 0} {
	set size 1024
    }
    return $size
}

# Returns all filenames in a list for the given side.
# if path is given, extract filenames from there
proc GetFileNames {s path} {
    global xf vdleft vdright vfleft vfright vfs ftp

    #DEBUG "$s: >$path<"
    set list {}
    if {[string compare $path $xf(pathi$s)] == 0 \
	    && [string compare {*} $xf(mask$s)] == 0} {
	# if the path _is_ visible and no mask, get from memory
	foreach row [set vd$s] {
	    lappend list [lindex $row 0][lindex $row 1]
	}
	foreach row [set vf$s] {
	    lappend list [lindex $row 0][lindex $row 1]
	}
    } {
	# if not, get the real McCoy
	switch $xf(fsmode_$s) {
	    0 {
		# if normal FS
		foreach f [glob -nocomplain -- $path{.*,*}] {
		    regsub {^~} [file tail $f] \.\/\~ tail
		    regsub {^\.\/\~} $tail \~ name
		    lappend list $name
		}
	    }
	    4 {
		# FTP TODO
		# check timeout
		if {[FO_CheckFTPTimeOut $s $xf(ftp.sock)]} {
		    return
		}

		if {[FTP_CMD $xf(ftp.sock) "CWD $path"] == -1} {
		    # path not ok
		    InvalidPath $s $ftp($xf(ftp.sock).status)
		    return
		}
		set xf(ftp.enable_count) 1
		after 100 [list FL_FTP_listcount $s]

		# get short list
		if {[FTP_LIST $xf(ftp.sock) 1 $xf(ftp.active)] == -1} {
		    # error, list is empty
		    MessageBox "Unable to get file listing...\n\n$ftp($xf(ftp.sock).status)" $s
		    set xf(ftp.enable_count) 0
		    return
		}
		set xf(ftp.enable_count) 0
		set list [split $ftp($xf(ftp.sock).readed) \n]
		set ftp($xf(ftp.sock).readed) {}

		# change back to current path
		FTP_CMD $xf(ftp.sock) "CWD $xf(pathi$s)"
	    }
	    default {
		# VFS
		foreach row $vfs(${path}dirs) {
		    lappend list [lindex $row 0][lindex $row 1]
		}
		foreach row $vfs($path) {
		    lappend list [lindex $row 0][lindex $row 1]
		}
	    }
	}
    }
    #DEBUG $list
    return $list
}
# Returns filenames for selected items in a list for the given side.
proc GetSelNames {s} {
    global xf

    set lnam {}
    foreach i $xf(selekted$s) {
	lappend lnam [GetFileName $s $i]
    }
    return $lnam
}
proc DefaultInfo {s} {
    global xf tcl_platform

    if {[string match $s "left"]} {
	set o "right"
    } {
	set o "left"
    }

    if {[string compare {} $xf(selekted$s)] != 0} {
	CorrectColor $o xf {} {}
	ShowSelSize $s
	return
    }

    $xf(infoEnt_$s) config -justify center -bg "#404040" -fg "#ffff60"
    # TODO: can we show here something in VFS?
    set xf(df$s) {}
    set xf(devicefree$s) 99999999.0
    set xf(mdos_$s) 0
    if {$xf(smode_$s) == 3} {
	# HyperList mode
	if {$xf(fsmode_$s) == 4} {
	    # FTP
	    set xf(infoA$s) "DOWNLOAD LIST"
	    set xf(fstype$s) FTP
	} {    
	    set xf(infoA$s) HYPERLIST
	    set xf(fstype$s) {}
	}
	return
    }
    switch $xf(fsmode_$s) {
	1 {
	    set xf(fstype$s) ZIP
	    set xf(infoA$s) [string trimleft [file tail $xf(virtualfile)] \./]
	    return
	}
	2 {
	    set xf(fstype$s) TAR
	    set xf(infoA$s) [string trimleft [file tail $xf(virtualfile)] \./]
	    return
	}
	3 {
	    set xf(fstype$s) LHA
	    set xf(infoA$s) [string trimleft [file tail $xf(virtualfile)] \./]
	    return
	}
	4 {
	    set xf(fstype$s) FTP
	    set xf(infoA$s) $xf(ftp.host)
	    return
	}
	5 {
	    set xf(fstype$s) RPM
	    set xf(infoA$s) [string trimleft [file tail $xf(virtualfile)] \./]
	    return
	}
	6 {
	    set xf(fstype$s) RAR
	    set xf(infoA$s) [string trimleft [file tail $xf(virtualfile)] \./]
	    return
	}
    }
    set xf(infoA$s) ""
    $xf(infoEnt_$s) config -justify right

    set fs [string match {*-T*} $xf(DISKFREE)]
    if {[string compare windows $tcl_platform(platform)] == 0} {
	cd [lindex [file split $xf(pathi$s)] 0]
	set tmp [eval exec $xf(CMDSHELL) dir]
	regexp {.*\    (.*)\ bytes free$} $tmp gfg dfsize
	#puts "$gfg, $dfsize"
	# remove commas and spaces
	regsub -all {[ ,]} $dfsize.0 {} dfsize
	#set dfsize -1
	set dfsize [expr {$dfsize / 1024}]
	set fs "Win"
    } {
	set dfsize [ExecGetDfSize $xf(DISKFREE) $xf(pathi$s) fs $s].0
	if {$xf(df_1k) == 0} {
	    set dfsize [expr {$dfsize / 2}]
	}
    }

    if {$dfsize == -1} {
	set xf(fstype$s) {}
	set xf(infoA$s) "Unable to obtain free space information!"
	set xf(devicefree$s) 99999999.0
	set xf(df$s) --
    } {
	set xf(devicefree$s) $dfsize
	regexp {^([^\.]*)\..*$} $dfsize gfg dfsize
	set xf(df$s) "[FormatNumber $dfsize] kb"
	set xf(fstype$s) $fs
	if {[string compare "msdos" $fs] == 0} {
	    set xf(mdos_$s) 1
	} elseif {[string compare "vfat" $fs] == 0} {
	    set xf(mdos_$s) 2
	}
	CorrectColor $s xf {} {}
    }
    catch {cd $xf(pathi$s)}
}
proc ExecGetDfSize {dfree path var s} {
    upvar $var fs

    if {[catch {eval exec $dfree [list $path]} foo]} {
	if {[catch {cd $path;set pwd [pwd]/}]} {
	    set pwd $path
	}
	return [GetDiskFree $pwd $dfree fs $s]
    } {
	return [GetDFSize $foo fs]
    }
}
proc GetDFSize {line var} {
    upvar $var fs
    global xf tcl_platform

    if {[string match {*HP*} $tcl_platform(os)]} {
	set df_l_ind 3
    } {
	set df_l_ind 2
    }
    if {$fs == 1} {
	set fs [lindex $line [expr {[llength $line] - 5 -1}]]
    } {
	set fs ""
    }
    return [lindex $line [expr {[llength $line] - $df_l_ind -1}]]
}
proc GetDiskFree {path cmd var s} {
    upvar $var fs

    if {[catch {eval exec $cmd} foo]} {
	set freespace -1
	tkerror $err $s
    } {
	set lines [split $foo \n]
	set freespace -1
	if {[string match Filesystem* [lindex $lines 0]]} {
	    set a 1
	    set df_sz_ind end
	    set df_l_ind 2
	} {
	    set a 0
	    set df_sz_ind 0
	    set df_l_ind 3
	}
	set l 0
	for {set i $a} {$i < [llength $lines]} {incr i} {
	    set df [lindex $lines $i]
	    set try [lindex $df $df_sz_ind]
	    if {[string compare {} $try] == 0} {
		continue
	    }
	    if {[regexp ^($try) $path tmp]} {
		if {[string length $tmp] > $l} {
		    set l [string length $tmp]
		    set freespace [GetDFSize $df fs]
		}
	    }
	}
    }
    return $freespace
}
proc CorrectColor {s var index op} {
    upvar $var xf

    if {[string match $s left]} {
	set o "right"
    } {
	set o "left"
    }
    if {$xf(selsum$o)/1024 > $xf(devicefree$s)} {
	$xf(fuf).${o}list config -selectbackground red
    } {
	$xf(fuf).${o}list config \
		-selectbackground [option get .xfiles selectBg_$o {}]
    }

}
proc DialogWin {string {xoffset -50} {yoffset -50} {select 1} \
	{X {}} {Y {}} {abort {}} {focus 1}} {
    global prompt ret xf

    set old_focus [focus]
    set f .prompt
    catch {destroy $f}
    toplevel $f -borderwidth 5
    if {[option get .xfiles messages_always_on_top {}] == 1} {
	bind $f <Visibility> [list KeepOnTop $f %W %s]
    }
    wm title $f "X-Files Request"
    if {[string compare {} $X] == 0} {
	set x [expr {[winfo pointerx .] + $xoffset}]
	set y [expr {[winfo pointery .] + $yoffset}]
    } {
	set x [expr {$X + $xoffset}]
	set y [expr {$Y + $yoffset}]
    }
    wm geometry $f "+$x+$y"
    wm resizable $f 0 0
    wm protocol $f WM_DELETE_WINDOW {set ret 0}

    frame $f.m -relief flat -bd 2
    message $f.m.msg -width 150  -justify center -text $string
    set b [frame $f.buttons -bd 3 -relief ridge]
    pack $f.m.msg -side top -fill x
    frame $f.m.fake
    pack $f.buttons -side bottom -fill x
    pack $f.m.fake -side bottom -fill x -ipady 5
    pack $f.m -side top
    set ind 1
    while {[info exists prompt($ind.label)]} {
	frame $f.m.$ind
	entry $f.m.$ind.e -textvariable prompt($ind.result)
	if {[info exists prompt($ind.passwd)]} {
	    # password field
	    $f.m.$ind.e config -show *
	}
	if {[string compare {} $prompt($ind.label)] != 0} {
	    label $f.m.$ind.l -text $prompt($ind.label)
	    pack $f.m.$ind.l -side left
	    pack $f.m.$ind.e -side right -fill x
	} {
	    pack $f.m.$ind.e -side top -fill x
	}
	pack $f.m.$ind -side top -fill x
	$f.m.$ind.e xview moveto 1
	$f.m.$ind.e icursor end
	bind $f.m.$ind.e <Return> [list focus $f.m.[incr ind].e]
    }
    incr ind -1
    bind $f.m.$ind.e <Return> {set ret 1}
    bind $f <Control-c> {set ret 0}
    bind $f <Escape> {set ret 0}
    button $b.ok -width 6 -text OK -command {set ret 1}
    button $b.cancel -width 6 -text Cancel -command {set ret 0}
    pack $b.ok -side left -padx 10 -pady 4
    if {[string compare {} $abort] != 0} {
	button $b.misc -width 6 -text $abort -command {set ret 2}
	pack $b.misc -side right -pady 4
	pack $b.cancel -side right -pady 4
    } {
	pack $b.cancel -side right -padx 10 -pady 4
    }

    tkwait visibility $f
    KeepInScreen $f
    grab $f
    focus $f.m.$focus.e
    if {$select && [string compare {} $prompt(1.result)] != 0} {
	$f.m.1.e select range 0 end
    }
    $f.m.1.e xview moveto 1
    $f.m.1.e icursor end
    tkwait variable ret
    grab release $f
    catch {destroy $f}
    focus $old_focus
    return $ret

}
proc GetCharValue { fid } {
    set byte [read $fid 15]
    set pit [string length $byte]
    if {$pit > 0} {

	for {set i 0} {$i < $pit } {incr i} {
	    scan [string index $byte $i] "%c" resu
	    append t $resu
	}

	if {$pit < 15} {
	    append t 0
	    if {[catch {seek $fid [expr {$pit - 14}] current}]} {
		return -1
	    }
	}
	return $t
    } {
	if {[eof $fid]} {return -1} {return 0}
    }
}
proc String2Integer {s} {
    set pit [string length $s]
    for {set i 0} {$i < $pit } {incr i} {
	scan [string index $s $i] "%c" resu
	append tulo $resu
    }
    return $tulo
}
# params: f - file
#         b - mouse button
#         d - the dir where the file is
#         s - side
proc QuickExe {f b d s {ftpcached 0}} {
    global xf
    set cont 1
    set i "\[Extension\]"
    set pid -1
    SetWaitPointer
    regexp (\[^.]*$) [string tolower $f] ext
    set ext ${ext}$b
    regsub {^~} $f \.\/\~ tail
    set tmp [file rootname $tail]
    while {1} {
	regexp (\[^.]*$) [string tolower $tmp] tmpe
	set tmp [file rootname $tmp]
	if {[lsearch -exact [info globals *$tmpe.$ext*] $tmpe.$ext] < 0} {
	    break
	}
	set ext $tmpe.$ext
    }
    global $ext
    if {[catch {set tmp [set $ext]} eerror]} {
	#if ![file readable "$xf(pathi$s)$f"] {}
	if {![file readable [file join $d $f]]} {
	    MessageBox "Could not complete operation. File is not readable." $s
	    NullSelect $s
	    DefaultInfo $s
	    return $pid
	} {
	    if {$xf(peekheader)} {
		#if [catch {open "$xf(pathi$s)$f" RDONLY} fileId] {}
		if {[catch {open [file join $d $f] RDONLY} fileId]} {
		    bell;tkerror $fileId $s
		    SetArrowPointer
		    return $pid
		} {
		    set cont 0
		    for {set i 0} {$i < 3} {incr i} {
			append tmp3 [GetCharValue $fileId]
		    }
		    set i 0
		    global H header hcomm
		    while {$i < $H($b)} {
			append header($b.$i) *
			if { [string match $header($b.$i) $tmp3] } {
			    Executer $hcomm($b.$i) [list $f] $s "\[Header\]" {} $d
			    break
			}
			incr i
		    }
		    close $fileId
		}

		if {$i == $H($b)} {
		    global txt$b
		    set cont 1
		    set tmp txt$b
		    set tmp [set $tmp]
		    set i "\[NoMatch\]"

		}
	    } {
		global txt$b
		set cont 1
		set tmp txt$b
		set tmp [set $tmp]
		set i "\[NoHeader\]"
	    }
	}
    }
    if {$cont} {
	#puts "Executer $tmp [list $f] $s $i {} $d"
	Executer $tmp [list $f] $s $i {} $d $ftpcached
    }
    SetArrowPointer
    return $pid
}

proc Executer {co f s {info ""} {ot {}} {dir {}} {ftpcached 0}} {
    global xf bg prompt tcl_platform TMP
    set both 0

    # check FTP timeout
    if {$xf(fsmode_$s) == 4 && $ftpcached == 0} {
	if {[FO_CheckFTPTimeOut $s $xf(ftp.sock)]} {
	    return
	}
    }
	
    if {$s == "left"} {
	set d $xf(pathiright)
	set c $xf(pathileft)
	set o "right"
    } {
	set d $xf(pathileft)
	set c $xf(pathiright)
	set o "left"
    }

    set param [lindex $co 0]
    if {[regexp C $param]} {
	if {![AskWin {Confirm operation: Are You Sure ?} -50 -50 {} {} {} Yes No]} {
	    return -1
	}
    }

    # Update both listboxes ?!
    if {[regexp %d $co]} {
	set both 1
    }
    if {[string match $xf(pathileft) $xf(pathiright)]} {
	set both 1
    }

    if {[string match {*%o1*} $co]} {
	set i 1
	while {[set paikka [string first %o$i $co]] >= 0} {
	    set tmp3 [string range $co $paikka end]
	    set e [expr {[string first ' $tmp3] -5}]
	    regexp "%o$i'(.*)'" $tmp3 op op1
	    set op1 ${op1}'
	    set e [expr {[string first %o$i $tmp3]+3}]
	    set tmp3 [string range $tmp3 $e end]
	    set e [expr {[string first ' $op1] -1}]

	    set opt($i) [string range $op1 0 $e]
	    set tmp3 [string range $tmp3 $e end]
	    incr i
	}
	foreach a [array names opt] {
	    regsub $opt($a) $co {} co
	    set prompt($a.label) $opt($a)
	}

	if {[DialogWin "Additional options"]} {
	    foreach a [array names opt] {
		if {[string compare {} $prompt($a.result)] == 0} {
		    regsub "%o$a''" $co {} co
		    continue
		}
		regsub -all { } $prompt($a.result) {\ } o$a
	    }
	} {
	    InfoChange $s "Command aborted!"
	    after 4000 [list DefaultInfo $s]
	    unset prompt
	    return -1
	}
	unset prompt
	regsub -all {''} $co \} co
	regsub -all {%o} $co \$\{o co
    } elseif {[string match *%o* $co]} {
	MessageBox "You have \"%o\"-specifier when you should have \"%o\?\", where \? is a number starting from 1." $s
	return
    }
    # store the command for debugging purposes
    # TODO: the param, or subsituted string?
    set xf(lastcommand) $co

    regsub -all {%} $co {$} co
    regsub "$param " $co {} co
    regsub -all { } $d {\ } d
    set xf(clearselect) 1
    if {[string compare {} $ot] != 0} {
	set f ""
	foreach d $xf(selekted$s) {
	    lappend f $xf(pathi$s)[GetFileName $s $d]
	}
	foreach d $xf(selekted$o) {
	    lappend f $xf(pathi$o)[GetFileName $o $d]
	}
    }
    #catch {cd $xf(pathi$s)}
    if {[string compare {} $dir] == 0} {
	set dir $xf(pathi$s)
    }
    #puts "EXEC: $dir"
    catch {cd $dir}
    update idletasks
    set co [subst -nobackslashes $co]
    switch -exact -- [lindex $co 0] {
	exec {
	    if {[string match {unix} $tcl_platform(platform)]} {
		set ci [lindex $co 1]
	    } {
		set ci [lindex $co 3]
	    }
	}
	ChangeDir {set ci "[lindex $co 0 ] [lindex $co 2]"}
	default {set ci [lindex $co 0]}
    }

    ## Check if bg_exec 
    ## JFo

    if {[string compare [lindex $co 0] bg_exec] == 0} {
	#puts "bg_exec FOUND!"
	
	# OutputWin ?!
	if {[regexp W $param]} {
	    set win 1
	} {
	    set win 0
	}
	
	# Update ?!
	if {[regexp U $param]} {
	    set update 1
	} {
	    set update 0
	}

	set fileid [eval "bg_exec [list [lrange $co 1 end]]\
		{bg_handler $update $s $win $dir $d}"]
	set pid [pid $fileid]
	set bg($fileid.stoptime) "RUNNING!"

	set entry  "\[$pid\] - [lindex $co 1]"

	.xfmenu.bg.m add cascade -label "$entry" \
		-menu .xfmenu.bg.m.$fileid
	menu .xfmenu.bg.m.$fileid -tearoff 0

	.xfmenu.bg.m.$fileid add command -label Kill \
		-command [list bg_killer $fileid $pid]

	.xfmenu.bg.m.$fileid add command -label "More.."\
		-command "bg_panel $fileid"

	after 4000 [list DefaultInfo $s]
	return 1
    }

    if {[catch {set pid [eval $co]} err]} {
	if {![regexp Q $param]} {
	    tkerror $err $s
	} {
	    InfoChange $s "$info $ci: Quiet error!"
	    after 4000 [list DefaultInfo $s]
	}
	return -1
    } {
	if {[regexp W $param]} {
	    OutputWindow $pid [list $dir] [lindex $f 0]
	}
	InfoChange $s "$info Executed: $ci"

	if {[regexp U $param]} {
	    if {$both} {
		after 100 [list UpdateListbox left]
		after 100 [list UpdateListbox right {} 4000]
	    } {
		after 100 [list UpdateListbox $s]
	    }
	} {
	    after 4000 [list DefaultInfo $s]
	}

	return 1
	#SetArrowPointer
    }
}

## Handler for bg_exec
## JFo
proc bg_handler {u s win path other_path fileid} {
    global bg xf

    set bg($fileid.stoptime) [clock format [clock seconds]]

    # Delete BG_Menu-item
    catch {
	.xfmenu.bg.m delete [.xfmenu.bg.m index *$bg($fileid.pid)*]
	destroy .xfmenu.bg.m.$fileid
    }

    # Update ?!
    if {$u} {
	# LEFT-match ?
	if {[string compare $path $xf(pathileft)]  == 0} {
	    after 100 [list UpdateListbox left]
	}
	if {[string compare $other_path $xf(pathileft)] == 0} {
	    after 100 [list UpdateListbox left]
	}	
	# RIGHT-match ?
	if {[string compare $path $xf(pathiright)]  == 0} {
	    after 100 [list UpdateListbox right]
	}
	if {[string compare $other_path $xf(pathiright)] == 0} {
	    after 100 [list UpdateListbox right]
	}	
    }
    
    # OutputWin !?
    if {$win} {
	OutputWindow $bg($fileid.buf) $path ""
    }
    bg_disablepanel $fileid .panel$bg($fileid.pid)
}

proc bg_killer {fileid pid} {
    global bg
    bg_kill $fileid
    catch {
	.xfmenu.bg.m delete [.xfmenu.bg.m index *$pid*]
	destroy .xfmenu.bg.m.$fileid
    }
    set bg($fileid.stoptime) "[clock format [clock seconds]] \[KILLED\]"
    bg_disablepanel $fileid .panel$bg($fileid.pid); update idletasks
}

proc bg_panel {fileid} {
    global bg

    if {[catch {set p [toplevel .panel$bg($fileid.pid)]}]} {
	return
    }

    wm title $p "BG Process info - \[$bg($fileid.pid)\]"
    wm protocol $p WM_DELETE_WINDOW "bg_disablepanel $fileid $p ; destroy $p"
    wm minsize $p 43 1

    frame $p.0 -relief sunken -bd 1
    #label $p.0.0 -text "INFO" -bg "#cccccc" -anchor w 
    label $p.0.1 -text "Command   : $bg($fileid.comm)" \
	    -bg "#cccccc" -anchor w -font fixed
    label $p.0.2 -text "StartTime : $bg($fileid.starttime)" \
	    -bg "#cccccc" -anchor w -font fixed
    label $p.0.3 -text "StopTime  : $bg($fileid.stoptime)" \
	 -bg "#cccccc" -anchor w -font fixed 
    label $p.0.4 -text "OUTPUT:" -anchor w -relief groove
    
    frame     $p.1
    text      $p.1.0 -setgrid 1 -width 80 -height 15 -font fixed -bd 1 -yscrollcommand "$p.1.1 set"
    scrollbar $p.1.1 -command "$p.1.0 yview"
    
    frame  $p.3 -relief groove -bd 2
    label  $p.3.0 -text "Input: "
    entry  $p.3.1 
 
    frame  $p.4 -relief ridge -bd 2
    button $p.4.0 -text "Kill Job!" \
	    -command "bg_killer $fileid [pid $fileid]"
    button $p.4.1 -text Close \
	    -command "bg_disablepanel $fileid $p ; destroy $p"
    
    pack $p.0.1 $p.0.2 $p.0.3 -side top -fill x -expand true
    
    pack $p.1.1 -side right -fill y
    pack $p.1.0 -side left -expand true -fill both 

    pack $p.3.0 -side left -ipadx 2
    pack $p.3.1 -side left -fill x
    
    pack $p.4.0 -side left
    pack $p.4.1 -side right -padx 5
    
    pack $p.4 -ipadx 10 -ipady 1 -side bottom -fill x
    pack $p.0 -side top -fill x  
    pack $p.3 -side bottom -fill x
    pack $p.1 -side top -fill both -expand true


    
    bind $p.3.1 <Return> "bg_sendstdin $fileid $p"

    proc bg_sendstdin {fileid p} {
	$p.1.0 insert end "[$p.3.1 get]\n"
	$p.3.1 delete 0 end
    }

    $p.1.0 insert end $bg($fileid.buf)
    $p.1.0 see end

    trace variable bg($fileid.line) w "bg_updatepanel $fileid $p" 
}

proc bg_updatepanel {fileid p array index op} {
    global bg
    $p.1.0 insert end $bg($fileid.line)
    $p.1.0 see end
    update idletasks
}

proc bg_disablepanel {fileid p} {
    global bg
    
    catch {
	$p.0.3 configure -text "StopTime  : $bg($fileid.stoptime)"
	$p.3.1 configure -state disabled
	$p.3.0 configure -fg "#666666"
    }
    catch {
	trace vdelete bg($fileid.line) w "bg_updatepanel $fileid $p" 
    }
}

proc ButtonFrame { i s bfpath } {
    global bargs xf bcomm bargs

    frame $bfpath.bf($i) -height 30
    set error 0
    set refindex [expr {$i*6}]
    if {[catch {
	for {set n 0} {$n <  $xf(button_cols)} {incr n} {
	    set realindex [expr {$n+$refindex}]
	    set realaction "BAction $realindex $s $bfpath $i $bfpath.bf($i).f($n).b($n)"
	    frame $bfpath.bf($i).f($n) -width 30 -height 30 -bd 0
	    if {[catch {
		eval { button $bfpath.bf($i).f($n).b($n) -comm $realaction\
			-width 1 -highlightthicknes $xf(highlightthicknes) \
		    } $bargs($realindex)}]} {
		incr error 1
		set bcomm($realindex) [list N MessageBox {Please, Configure me !}]
		set bargs($realindex) ""
		eval {
		    button $bfpath.bf($i).f($n).b($n) -relief flat -width 1\
			    -highlightthicknes $xf(highlightthicknes) \
			    -comm "BAction $realindex $s $bfpath $i $bfpath.bf($i).f($n).b($n)"
		}
	    }
	    pack propagate $bfpath.bf($i).f($n) 0
	    pack $bfpath.bf($i).f($n).b($n) -expand true -fill both \
		    -side left
	    pack $bfpath.bf($i).f($n)  -expand true -fill both \
		    -side left
	    bind $bfpath.bf($i).f($n).b($n) <Button-2> "set xf(mb) 2 ; $bfpath.bf($i).f($n).b($n) invoke"
	    bind $bfpath.bf($i).f($n).b($n) <Button-3> "set xf(mb) 3 ; $bfpath.bf($i).f($n).b($n) invoke"
	    bindtags $bfpath.bf($i).f($n).b($n) [list XF $bfpath.bf($i).f($n).b($n) Button . all]
	}
    }  err]} {tkerror $err $s; return -1}
    if {$error != 0} {
	MessageBox "$error invalid button(s) in Your xfiles.buttons -file! \n Use\
		Button Editor to fix the problem!"
    }
}

proc GetButtonIndex {w} {
    regexp {(left|right).*\((.*)\).*\((.*)\).*\((.*)\)}\
	    $w nul side y x
    return [expr {$y * 6 + $x}]
}
proc BAction { i side bfpath framenumber button} {
    global bcomm be xf bargs beparent bindex prompt TMP vfsmap
    if {$xf(editmode) > 0} {
	set tmped $button
	if {$be(editedi) == 2} {
	    set ret [AskWin "You have made changes! Edit another button and forget changes in this button ?" -100 -100 "Save"]
	    switch $ret {
		0 {return}
		2 {ApplyProc $bindex ; ButtonSave}
		default {incr be(editedi) -1}
	    }
	}
	catch {BE_UnSetTrace}
	if {!$xf(helpmode)} {
	    set xf(editbutton) $tmped
	}
	$beparent.menu.toolmenu.m entryconfigure Copy* -state normal
	$beparent.menu.toolmenu.m entryconfigure "Copy Style" -state normal
	regexp {(left|right).*\((.*)\).*\((.*)\).*\((.*)\)}\
		$xf(editbutton) nul be(side) y x
	unset nul be(side)
	set bindex [expr {$y * 6 + $x}]

	if {$xf(editmode) < 2} {
	    pack forget $beparent.menu.msg
	    set bcommtmp $bcomm($bindex)
	    set bargstmp $bargs($bindex)

	    set param [lindex $bcommtmp 0]

	    if {[regexp C $param]} {
		set  be(confirm) C
	    } {
		set  be(confirm) ""
	    }
	    #if [regexp D $param] {
		#set  be(dialog) D
	    #} {
		#set be(dialog) ""
	    #}
	    if {[regexp W $param]} {
		set be(win) W
	    } {
		set be(win) ""
	    }
	    if {[regexp U $param]} {
		set  be(update) U
	    } {
		set be(update) ""
	    }
	    if {[regexp Q $param]} {
		set  be(quiet) Q
	    } {
		set be(quiet) ""
	    }
	    if {[string match {&} [lindex $bcommtmp end]]} {
		set be(bg) "&" ; set bcommtmp [lreplace $bcommtmp end end]
	    } {
		set be(bg) ""
	    }
	    pack  $beparent.menu.toolmenu -side left
	    pack $beparent.entframe -side top -fill y -fill x
	    pack $beparent.middle -fill x -pady 10 -padx 3
	    $beparent.entframe.up.2.cmdentry delete 0 end
	    update idletasks
	    switch -glob -- [lindex $bcommtmp 1] {
		VirtualFTP {
		    set be(cmd) [lrange $bcommtmp 1 2]
		    set be(cmdarg) [lindex $bcommtmp 3]
		}
		VirtualTar {
		    set be(cmd) [lrange $bcommtmp 1 3]
		    set be(cmdarg) [lindex $bcommtmp 4]
		}
		ChangeDir {
		    set be(cmd) [lrange $bcommtmp 1 2]
		    set be(cmdarg) [lindex $bcommtmp 3]
		}
		Mount {
		    set be(cmd) [lrange $bcommtmp 1 2]
		    set be(cmdarg) [lindex $bcommtmp 3]
		}
		exec -
		bg_exec {
		    set be(cmd) [lindex $bcommtmp 1]
		    set be(cmdarg) [lrange $bcommtmp 2 end]
		}

		MessageBox {
		    set be(cmd) exec
		    set be(cmdarg) ""
		    set be(txt) ""
		    $beparent.entframe.up.3.button config -text ""
		}
		default {
		    set be(cmd) [lrange $bcommtmp 1 end]
		    set be(cmdarg) ""
		}
	    }
	    $beparent.entframe.up.2.cmdentry icursor end
	    set be(style) $bargstmp
	    set be(undoargs) $bargstmp
	    set be(undocomm) $bcommtmp
	    switch -glob -- $be(cmd) {
		ChangeDir* { set be(cmdtxt) ChangeDir ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom ;\
			pack forget $beparent.entframe.up.2.bg}
		FileOps*cp* { set be(cmdtxt) Copy ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		CopyAs* { set be(cmdtxt) CopyAs ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		CopyTo* { set be(cmdtxt) CopyTo ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		MoveTo* { set be(cmdtxt) MoveTo ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		FileOps*rm* { set be(cmdtxt) Delete ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		*DirSize* { set be(cmdtxt) DirSize ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		Mount* { set be(cmdtxt) Mount ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom ;\
			pack forget $beparent.entframe.up.2.bg}
		Grep* { set be(cmdtxt) Grep ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		exec { set be(cmdtxt) Execute ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom;\
			pack $beparent.entframe.up.2.bg -side top -anchor nw}
		bg_exec { set be(cmdtxt) BG_Exec ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom;\
			pack forget $beparent.entframe.up.2.bg}
		MkDir*  { set be(cmdtxt) MakeDir ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		FileOps*mv* { set be(cmdtxt) Move ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		PatternSel*  { set be(cmdtxt) PatternSel ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		ProtEdit*  { set be(cmdtxt) ProtEdit ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		ReadFiles*  { set be(cmdtxt) ReadFiles ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		Rename*  { set be(cmdtxt) Rename ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		VirtualRpm*  { set be(cmdtxt) VirtualRpm ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		VirtualRar*  { set be(cmdtxt) VirtualRar ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		VirtualLha*  { set be(cmdtxt) VirtualLha ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		VirtualTar*  { set be(cmdtxt) VirtualTar ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom ;\
			pack forget $beparent.entframe.up.2.bg}
		VirtualZip*  { set be(cmdtxt) VirtualZip ;\
			pack forget $beparent.entframe.up.2.cmdentry ;\
			pack forget $beparent.entframe.up.2.bg}
		VirtualFTP*  { set be(cmdtxt) VirtualFTP ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom ;\
			pack forget $beparent.entframe.up.2.bg}
		default { set be(cmdtxt) Execute ;\
			pack $beparent.entframe.up.2.cmdentry -side bottom;\
			pack $beparent.entframe.up.2.bg -side top -anchor nw}
	    }

	    foreach arg {-relief -bd -fg -bg -activebackground -activeforeground\
		    -font} {
		SetButtonStyle "$arg" [$xf(editbutton) cget "$arg"]
	    }
	    SetScale
	    set be(bd) [$xf(editbutton) cget {-bd}]
	    set be(txt) [$xf(editbutton) cget {-text}]
	    $beparent.entframe.up.1.txtentry icursor end
	    set be(relief) [$xf(editbutton) cget {-relief}]
	    set be(cursor) [$xf(editbutton) cget {-cursor}]
	    $beparent.bottom.undo config -state normal
	    $beparent.bottom.save config -state normal
	    $beparent.bottom.applyframe.apply config -state normal
	    update idletasks
	    if {$be(cursor) == ""} {
		set be(cursor) "Default"
	    }
	    catch {eval {$beparent.entframe.up.3.button config} $be(style)}
	    BE_SetTrace
	    if {[winfo exists .write_help]} {
		WriteHelp_Get .write_help
	    }
	}
	return 0
    } {

	if {$xf(helpmode) == "1" } {
	    HelpInfo_Conf $bfpath $bcomm($i) $i $framenumber
	} {
	    SetWaitPointer
	    if { $side == "L"} {
		set s "left"
		set o "right"
	    } {
		set s "right"
		set o "left"
	    }
	    switch $xf(mb) {
		1 {set selekted $xf(selekted$s)}
		2 {lappend selekted $xf(selekted$s) $xf(selekted$o)}
		3 {set selekted $xf(selekted$o)}
	    }
	    set f_ops 0
	    set none 0
	    if {([string match *FileOps* $bcomm($i)] \
		    || [string match *Rename* $bcomm($i)] \
		    || [string match *CopyAs* $bcomm($i)] \
		    || [string match *ProtEdit* $bcomm($i)] \
		    || [string match *Virtual* $bcomm($i)] \
		    || [string match *DirSize* $bcomm($i)])
	    && ![string match {*VirtualFTP*} $bcomm($i)]} {
		set f_ops 1
		if {[string compare {} $selekted] == 0} {
		    set none 1
		}
	    }
	    unset selekted
	    switch $xf(mb) {
		1 {
		    #puts "Baction, mb 1"
		    #if {$xf(fsmode_$s) > 0 \
			#   && ![string match *PatternSel* $bcomm($i)] \
			#   && ![string match *CopyAs* $bcomm($i)]} {
			#if ![string match *FileOps* $bcomm($i)] {
			#   MessageBox "This does not work with Virtual Filesystem!" $s
			#   return
			    #}
			    #}
		    if {$none} {NoSelect $s;return}
		    if {$xf(fsmode_$s) == 0 || \
			    [string match *PatternSel* $bcomm($i)] || \
			    [string match *Rename* $bcomm($i)] || \
			    [string match *CopyAs* $bcomm($i)] || \
			    [string match *FileOps* $bcomm($i)]} {
			Executer $bcomm($i) [GetSelNames $s] $s "\[A_Button\]"
		    } {
			# VFS, create temp dir
			set tmp [file join $TMP(dir) vfs[incr TMP(idx)]]
			file mkdir $tmp
			
			set files {}
			if {$xf(fsmode_$s) == 4} {
			    # FTP, show progress bar			    
			    XF_ProgressBar $xf(ftp.sock)
			}
			foreach f [GetSelNames $s] int $xf(selekted$s) {
			    set cac $xf(fsmode_$s).$xf(pathi$s)$f
			    if {![info exists vfsmap($cac)]} {
				# if not already cached
				#puts "BA VOUTP: new file $f"
				# get the file out of the VFS
				if {[VirtualOut $s [string trimleft $xf(pathi$s)$f /] $tmp/$f $int]} {
				    # error, msg is already shown
				    break
				}
				# store file name for possible future use
				set vfsmap($cac) $tmp/$f
			    } {
				#puts "BA VOUTP: cached file $f"
			    }
			    lappend files $vfsmap($cac)
			}
			XF_PBFinal
			Executer $bcomm($i) $files $s "\[A_Button\]" {} $TMP(dir)
		    }
		}
		2 {
		    #puts "Baction, mb 2"
		    if {$xf(fsmode_$s) || $xf(fsmode_$o)} {
			MessageBox "Middle mousebutton does not work while using Virtual Filesystem!" $s
			set xf(mb) 1
			return
		    }
		    if {$none} {NoSelect $s;return}
		    if {$f_ops} {
			Executer $bcomm($i) [GetSelNames $s] $s "\[A_Button\]"
			Executer $bcomm($i) [GetSelNames $o] $o "\[A_Button\]"
		    } {
			Executer $bcomm($i) {} $s "\[A_Button\]" $o
		    }
		}

		3 {
		    #puts "Baction, mb 3"
		    if {$none} {NoSelect $o;return}
		    if {$xf(fsmode_$o) == 0 || \
			    [string match *PatternSel* $bcomm($i)] || \
			    [string match *Rename* $bcomm($i)] || \
			    [string match *CopyAs* $bcomm($i)] || \
			    [string match *FileOps* $bcomm($i)]} {
			Executer $bcomm($i) [GetSelNames $o] $o "\[A_Button\]"
		    } {
			# create temp dir
			set tmp [file join $TMP(dir) vfs[incr TMP(idx)]]
			file mkdir $tmp
			
			set files {}
			if {$xf(fsmode_$o) == 4} {
			    # FTP, show progress bar
			    XF_ProgressBar $xf(ftp.sock)
			}
			foreach f [GetSelNames $o] int $xf(selekted$o) {
			    set cac $xf(fsmode_$o).$xf(pathi$o)$f
			    if {![info exists vfsmap($cac)]} {
				# if not already cached
				#puts "BA VOUTP: new file $f"
				# get the file out of the VFS
				if {[VirtualOut $o [string trimleft $xf(pathi$o)$f /] $tmp/$f $int]} {
				    # error, msg is already shown
				    break
				}
				# store file name for possible future use
				set vfsmap($cac) $tmp/$f
			    } {
				#puts "BA VOUTP: cached file $f"
			    }
			    lappend files $vfsmap($cac)
			}
			XF_PBFinal
			Executer $bcomm($i) $files $o "\[A_Button\]" {} $TMP(dir)
		    }
		}
	    }
	    if {$xf(clearselect) == 1} {
		switch $xf(mb) {
		    1 {UnselectAll $s}
		    2 {UnselectAll left; UnselectAll right; DefaultInfo $o}
		    3 {UnselectAll $o}
		}
		update idletasks
		set xf(clearselect) 0
	    }
	    set xf(mb) 1
	    SetArrowPointer
	    return 1
	}
    }
}
proc KeepOnTop {w W s} {
    if {[string match $w $W] \
	    && [string match {*llyObscured} $s]} {
	raise $W
	update idletasks
    }
}
proc KeepOnTop_old {w W s} {
    if {[string match $w $W] \
	    && [string compare VisibilityUnobscured $s]} {
	raise $W
	update idletasks
    }
}
proc KeepInScreen {w} {
    regexp {^([^x]*)x([^\+]*)\+([^\+]*)\+(.*)} [wm geometry $w] all ww wh wx wy
    set pw [winfo screenwidth $w]
    set ph [winfo screenheight $w]
    set xt [expr {($wx+$ww) - $pw}]
    if {$xt > 0} {
	set x [expr {$wx-$xt}]
	set ux 1
    } elseif {$wx < 0} {
	set x 0
	set ux 1
    } {
	set x $wx
	set ux 0
    }
    set yt [expr {($wy+$wh) - $ph}]
    if {$yt > 0} {
	set y [expr {$wy-$yt}]
	set uy 1
    } elseif {$wy < 20} {
	set y 20
	set uy 1
    } {
	set y $wy
	set uy 0
    }
    if {$ux || $uy} {
	wm geometry $w "+$x+$y"
	update idletasks
    }
}

proc MessageBox {string {s {}} {xoffset -50} {yoffset -50} {X {}} {Y {}} {width {200}} {font {}}} {
    global xf res ftp

    catch {destroy .messages}
    SetArrowPointer
    set f [toplevel .messages -borderwidth 5]
    if {[option get .xfiles messages_always_on_top {}] == 1} {
	bind $f <Visibility> [list KeepOnTop $f %W %s]
    }
    if {[string compare {} $X] == 0} {
	set x [expr {[winfo pointerx .] + $xoffset}]
	set y [expr {[winfo pointery .] + $yoffset}]
    } {
	set x [expr {$X + $xoffset}]
	set y [expr {$Y + $yoffset}]
    }
    wm geometry $f "+$x+$y"
    wm title $f "X-Files Message"
    wm resizable $f 0 0
    wm protocol $f WM_DELETE_WINDOW {set res 0}

    frame $f.mf -relief sunken -bd 2 -bg "#cacaca"
    message $f.mf.msg -width $width  -justify left -text $string
    if {[string compare $font {}]} {
	$f.mf.msg config -font $font
    }

    label $f.mf.pic -bitmap info
    set b [frame $f.buttons -bd 10]
    pack $f.mf.pic -side left -padx 10
    pack $f.mf.msg -side right
    pack $f.mf -fill both
    pack $f.buttons -side bottom -fill x

    bind $f <Return> {set res 1}
    bind $f <Control-c> {set res 0}
    bind $f <Escape> {set res 0}
    button $b.ok -text OK -command {set res 1}
    pack $b.ok -side top

    focus $b.ok
    tkwait visibility $f
    KeepInScreen $f
    grab $f
    tkwait variable res
    grab release $f
    if {[string match {*xternal comm*} $string] == 0} {
	if {[string compare {} $s] == 0} {
	    LogBoth $string 0
	} {
	    after idle [list Log $s $string 0]
	}
    }
    # ftp closed kludge
    if {[info exists xf(ftp.host)] == 0} {
	# ftp closed
	catch {unset ftp($xf(ftp.sock).status)}
	catch {unset xf(ftp.sock)}
    }

    catch {destroy $f}
}
# OK/Cancel window, OK returns 1, cancel 0 
# If text is defined, that returns 2
proc AskWin {string {xoffset -50} {yoffset -50} \
	{text {}} {X {}} {Y {}} {yes OK} {no Cancel}} {
    global ret xf
    catch {destroy .prompt}
    set f [toplevel .prompt -borderwidth 5]
    if {[option get .xfiles messages_always_on_top {}] == 1} {
	bind $f <Visibility> [list KeepOnTop $f %W %s]
    }
    if {[string compare {} $X] == 0} {
	set x [expr {[winfo pointerx .] + $xoffset}]
	set y [expr {[winfo pointery .] + $yoffset}]
    } {
	set x [expr {$X + $xoffset}]
	set y [expr {$Y + $yoffset}]
    }
    wm geometry $f "+$x+$y"
    wm title $f "X-Files Query"
    wm resizable $f 0 0
    wm protocol $f WM_DELETE_WINDOW {set ret 0}

    set b [frame $f.buttons -bd 10]
    set mf [frame $f.messages -relief sunken -bd 2]
    label $mf.pic -bitmap question
    message $mf.msg -width 110  -justify left -text $string \
	    -font *helvetica-bold-r-*-*-14*

    pack $mf.pic $mf.msg -side left -pady 5 -padx 5

    pack $f.messages $f.buttons -side top -fill x -expand true

    bind $f <Control-c> {set ret  0}
    bind $f <Escape> {set ret  0}
    button $b.ok -width 6 -text $yes -command {set ret 1}
    button $b.cancel -width 6 -text $no -command {set ret 0}
    pack $b.ok -side left
    pack $b.cancel -side right
    if {[string compare {} $text]} {
	button $b.misc -width 6 -text $text -command {set ret 2}
	pack $b.misc -side right
    }

    tkwait visibility $f
    KeepInScreen $f
    grab $f
    focus $b.cancel
    tkwait variable ret
    grab release $f
    catch {destroy $f}
    return $ret
}
proc ChangeDir {s dirname} {
    global xf

    if {$xf(fsmode_$s) == 0 && [file isdirectory $dirname] == 0} {
	InvalidPath $s
	return
    }

    #History $s
    SetPaths $s $dirname
    NullSelect $s

    $xf(fuf).${s}list config \
	    -selectbackground [option get .xfiles selectBg_$s {}]
    FileList $s $xf(pathi$s)
    DefaultInfo $s
}

# Checks that files to be copied/moved do not exist on the other side. 
# If they do, pop up a question window for replacement.
# returns: 0 - yes
#          1 - no 
#   also variables 'all' and 'none' may be set to 1
#
# Requires that 'files' is a list 
#   (ie. a single file must also be given as a list)
proc FO_CheckOverWrite {s o v_files v_ints others v_all v_none {X {}} {Y {}}} {
    upvar $v_all all $v_none none $v_files files $v_ints ints
    global xf

    set rc $none
    if {[string compare {} $X] == 0} {
	set X [winfo pointerx .]
	set Y [winfo pointery .]
    }
    set newf {}
    set newi {}
    #DEBUG "A: <$files>"
    foreach file $files ind $ints {
	#DEBUG $file
	if {$xf(smode_$s) == 3} {
	    # HyperList mode
	    set idx [lsearch $others [file tail $file]]
	} {
	    # normal
	    set idx [lsearch $others $file]
	}
	#DEBUG "$file, $ind :: $idx"
	#DEBUG $others
	if {$idx > -1} {
	    # exists
	    #incr idx
	    set other [lindex $others $idx]
	    if {$xf(fsmode_$s) == 4 && \
		    ($xf(ftp.shortlist) || $xf(smode_$s) == 3)} {
		set ssize " (N/A) "
	    } {
		set ssize [GetFileSize $s $ind]
	    }
	    set msg "Replace file:\n$other\t\t[GetFileSize $o $idx $other] bytes\nlast modified on  [GetFileMTime $o $idx $other]\n\nwith file:\n$file\t\t$ssize bytes\nlast modified on  [GetFileMTime $s $ind]"
	    #puts $msg
	    if {$none == 0} {
		switch [XF_AskOverWrite $msg -50 -50 $X $Y] {
		    0 {
			#yes, no need to do anything
			#puts yes
			set rc 0
		    }
		    1 {
			#all
			#puts all
			set rc 0
			set all 1
			return $rc
		    }
		    2 {
			#no
			#puts no
			set rc 1
		    } 
		    3 {
			#none
			#puts none
			set rc 1
			set none 1
		    }
		}
	    }
	}
	# remove items not to overwrite from list
	if {$rc == 0} {
	    lappend newf $file
	    lappend newi $ind
	}
	if {[llength $ints] == 1} {
	    #DEBUG "onefile"
	    break
	}
    }
    set files $newf
    set ints $newi
    #DEBUG "B: >$files<"
    return $rc
}

# Question window for replacing files.
proc XF_AskOverWrite {string {xoffset -50} {yoffset -50} \
	{X {}} {Y {}}} {
    global ret xf
    catch {destroy .fo_prompt}
    set f [toplevel .fo_prompt -borderwidth 5]
    if {[option get .xfiles messages_always_on_top {}] == 1} {
	bind $f <Visibility> [list KeepOnTop $f %W %s]
    }
    if {[string compare {} $X] == 0} {
	set x [expr {[winfo pointerx .] + $xoffset}]
	set y [expr {[winfo pointery .] + $yoffset}]
    } {
	set x [expr {$X + $xoffset}]
	set y [expr {$Y + $yoffset}]
    }
    wm geometry $f "+$x+$y"
    wm title $f "X-Files Confirm File Replace"
    wm resizable $f 0 0
    wm protocol $f WM_DELETE_WINDOW {set ret 2}

    set b [frame $f.buttons -bd 10]
    set mf [frame $f.messages -relief sunken -bd 2]
    label $mf.pic -bitmap question
    message $mf.msg -aspect 300 -justify left -text $string \
	    -font {Helvetica 10}

    #pack $mf.pic $mf.msg -side left -pady 5 -padx 5
    grid $mf.pic $mf.msg -sticky news -pady 5 -padx 5

    #pack $f.messages $f.buttons -side top -fill x -expand true

    bind $f <Control-c> {set ret 2}
    bind $f <Escape> {set ret 2}
    button $b.yes -width 6 -text Yes -command {set ret 0}
    button $b.yes_a -width 6 -text "Yes to all" -command {set ret 1}
    button $b.no -width 6 -text No -command {set ret 2}
    button $b.no_a -width 6 -text "No to all" -command {set ret 3}
    grid $b.yes -sticky ew
    grid $b.yes_a -sticky ew -pady 3
    grid $b.no -sticky ew
    grid $b.no_a -sticky ew -pady 3

    grid $mf $b -sticky ew

    tkwait visibility $f
    KeepInScreen $f
    grab $f
    focus $b.no
    tkwait variable ret
    grab release $f
    catch {destroy $f}
    return $ret
}
proc ChkDosNames {files to_mdos} {
    global xf

    set rc 0
    if {$to_mdos == 1} {
	foreach f $files {
	    if {[string length [file extension $f]] > 4 || \
		    [string length [file rootname $f]] > 8} {
		set rc 1
		break
	    }
	}
    }
    return $rc
}
proc SuggestDosName {f} {
    regsub -all -- {\.} [string range [file rootname $f] 0 7] _ root
    regsub -all -- {\.} [string range [file extension $f] 1 3] _ ext
    return $root.$ext
}

proc FileOps { operation s {paths {}} {patho {}} {sel {}} {files {}} {o {}}} {
    global xf vfs vdleft vfleft vdright vfright

    # normally target is opposite directory, CopyTo gives the source, target 
    # selection, files and target side
    if {[string compare {} $paths] == 0} {
	# not a CopyTo operation
	if {[string compare $s left] == 0} {
	    set o "right"
	} {
	    set o "left"
	}
	set paths $xf(pathi$s)
	set patho $xf(pathi$o)
	set files [GetSelNames $s]
	set sel $xf(selekted$s)
    }

    SetWaitPointer
    switch $operation {
	cp {set op "Copying"}
	rm {set op "Deleting"}
	mv {set op "Moving"}
    }

    set rc 0
    switch $xf(fsmode_$s) {
	0 {
	    #cd $paths
	    # remove trailing slashes, because DEC Alpha copies the contents
	    # of the directory if dir has trailing slash
	    regsub {/$} $files {} files
	    if {$xf(turbomode) || $xf(async_fo)}  {
		set rc [FO_Nor_Turbo $s $o $paths $patho $files $sel $xf(fuf).${s}list $operation $op]
	    } {
		set rc [FO_Nor_Noturbo $s $o $paths $patho $files $sel $xf(fuf).${s}list $operation $op]
	    }
	}
	1 {
	    set rc [FO_Zip $s $o $paths $patho $files $sel $operation $op]
	}
	2 {
	    set rc [FO_Tar $s $o $paths $patho $files $sel $operation $op]
	}
	3 {
	    set rc [FO_Lha $s $o $paths $patho $files $sel $operation $op]
	}
	4 {
	    set rc [FO_FTP $s $o $paths $patho $files $sel $operation $op]
	}
	5 {
	    # TODO tarvitaanko tuki kopioinnille?
	    MessageBox "Sorry, only double-click on a file is supported for RPM-packages!" $s
	    set rc 1
	}
	6 {
	    set rc [FO_Rar $s $o $paths $patho $files $sel $operation $op]
	}
    }

    #puts "FOPS rc: $rc"
    # check if directory has changed
#    if {$xf(turbomode) == 1} {
	set uo 0
	if {[string compare $patho $xf(pathi$o)] == 0 \
		&& ([string compare cp $operation] == 0 \
		|| [string compare mv $operation] == 0)} {
	    #if {$rc == 0} {
		# if no error, make changes in memory -> faster
		# TODO toimii, muttei täydellisesti...  oikeudet, mtime, owner ja group saattaa vaihtua... eli lähinnä rm voitais tehdä muistissa
		#puts "FOPS: memory update"
		#if {$xf(fsmode_$s) == 0 && \
			#[string compare $paths $patho] != 0} {
		    # copy selected to the other side
		    #foreach row $xf(selekted$s) {
			#puts "cp: $row"
			#if {$row < $len} {
			    # dir
			#    lappend vd$o [lindex [set vd$s] $row]
			#} {
			    # file
			#    set row [expr $row - $len]
			#    lappend vf$o [lindex [set vf$s] $row]
			#}
		    #}
		    #set xf(redraw$o) 1
		#}
	    #} {
		# if error, force update
		#puts "FOPS: disk update"
	    #}
	    #puts "FOPS cp: disk update"
	    UpdateListbox $o
	    set uo 1
	}
	# if directory is still the same
	if {[string compare $paths $xf(pathi$s)] == 0 \
		&& ([string compare rm $operation] == 0 \
		|| [string compare mv $operation] == 0)} {
	    if {$rc == 0} {
		# if no error, make changes in memory -> faster
		set len [llength [set vd$s]]
		#puts "FOPS rm: memory update"
		# remove selected ones
		#puts "$sel :: $len"
		foreach row [lsort -decreasing -integer $sel] {
		    if {$row < $len} {
			# dir
			set vd$s [lreplace [set vd$s] $row $row]
		    } {
			# file
			set row [expr {$row - $len}]
			#puts "f: $row"
			set vf$s [lreplace [set vf$s] $row $row]
		    }
		}
		set xf(redraw$s) 1
		set pos [expr {[lindex [$xf(fuf).${s}list yview] 0]+0.0001}]
		FileList $s $paths
		#UnselectAll $s
		$xf(fuf).${s}list yview moveto $pos
	    } {
		# if error, force update
		#puts "FOPS rm: disk update"
		UpdateListbox $s
	    }
	    if {$uo == 0 && \
		    [string compare $paths $patho] == 0 && \
		    $xf(fsmode_$o) == 0} {
		if {$rc == 0} {
		    # memory update
		    set vd$o [set vd$s]
		    set vf$o [set vf$s]
		    set xf(redraw$o) 1
		}
		UpdateListbox $o
	    }
	    DefaultInfo $o
	}
#    }

    if {$rc == 0} {
	UnselectAll $s
    } {
	SelectionSize $s
    }
    DefaultInfo $s

    DEBUG "FileOps: done"
    SetArrowPointer
}

proc FO_Nor_Noturbo {s o paths patho filelist intlist list operation op} {
    global xf

    set rc 0
    set n [llength $filelist]
    set index 1
    set cleartrash 1
    set clist {}
    set x [winfo pointerx .]
    set y [winfo pointery .]
    set otherfiles [GetFileNames $o $patho]
    set all 0
    set none 0
    foreach file $filelist int $intlist {
	InfoChange $s "$op: $index / $n"
	if {$operation == "rm" } {
	    if {[DelSingleClipFile $s $file]} {
		continue
	    }
	    if {$xf(safedelete)} {
		if {[string match "$paths" "$xf(trashdir)"]} {
		    MessageBox "Trying to SafeDelete trashcan: Disable SafeDelete or use menuitem Empty Trash!" $s
		    set rc 1
		    break
		}
		if {$cleartrash} {
		    ClearTrashDir
		    .xfmenu.butt.m.del entryconfigure Undo* -state normal
		    set xf(undopath) $xf(pathi$s)
		    SaveUndo
		    set cleartrash 0
		}
		# move
		set rc [MoveFile $s $paths $file $xf(trashdir)]

		if {$rc} {
		    # error, try copy+delete
		    set rc [CopyFile $s $o $paths $file $xf(trashdir)]
		    if {$rc == 0} {
			set rc [DelFile $s $paths $file]
		    }
		}
	    } {
		# not safedelete
		set rc [DelFile $s $paths $file]
	    }
	} {
	    if {$xf(smode_$o) == 3} {
		# other side is HyperList
		HyperList 0 $s
		return 0
	    }
	    switch $xf(fsmode_$o) {
		0 {
		    set newf ""
		    set cancel 0
		    if {[ChkDosNames $file $xf(mdos_$o)]} {
			set newf "a.kissa"
			global prompt
			while {[ChkDosNames $newf $xf(mdos_$o)]} {
			    set prompt(1.label) ""
			    set prompt(1.result) [SuggestDosName $file]
			    if {[DialogWin "Name will be truncated! New name for\n$file" -50 -50 1 $x $y] == 0} {
				set cancel 1
			    }

			    set newf $prompt(1.result)
			}
		    }

		    if {$cancel} {
			lappend clist $int
			#[lindex $intlist 0]
			#set intlist [lreplace $intlist 0 0]
			continue
		    }
		    if {$all == 0} {
			# check overwrite requires that the item is given as list
			if {[string compare {} $newf] != 0} {
			    set item [list $newf]
			} {
			    set item [list $file]
			}
			if {[FO_CheckOverWrite $s $o item int $otherfiles all none $x $y] == 1} {
			    # do not overwrite
			    continue
			}
		    }
		    if {[string compare $operation cp] == 0} {
			# copy
			set rc [CopyFile $s $o $paths $file [file join $patho $newf]]
		    } {
			# move
			set rc [MoveFile $s $paths $file [file join $patho $newf]]
			if {$rc} {
			    # error, try copy+delete
			    set rc [CopyFile $s $o $paths $file [file join $patho $newf]]
			    if {$rc == 0} {
				set rc [DelFile $s $paths $file]
			    }
			}
		    }
		    #if {$rc == 0 && [string match $operation "mv"]} {
			#set rc [DelFile $s $paths $file]
		    #}
		    if {[string compare {} $newf]} {
			set file $newf
		    }
		}
		1 -
		2 -
		3 -
		5 -
		6 -
		4 {
		    set rc [FO_Nor_Virt $s $o $paths $patho "$file" $int $operation $xf(fsmode_$o)]
		    set xf(ftp.update) 1
		}
	    }
	}
	# TODO bg
	if {$rc == 0} {
	    #set item [lindex $intlist 0]
	    $list config -state normal
	    $xf(fuf).${o}list config -state normal
	    switch $operation {
		cp {
		    $list tag remove sel [expr {$int+1}].0 [expr {$int+2}].0
		    #$list selection clear $int
		    $xf(fuf).${o}list insert end ${file}\n
		}
		mv {
		    $list tag remove sel [expr {$int-$index+2}].0 [expr {$int-$index+3}].0
		    #$list selection clear [expr $int-$index+1]
		    $xf(fuf).${o}list insert end $file\n
		    $list delete [expr {$int-$index+2}].0 [expr {$int-$index+3}].0
		}
		rm {
		    $list tag remove sel [expr {$int-$index+2}].0 [expr {$int-$index+3}].0
		    #$list selection clear [expr $int-$index+1]
		    $list delete [expr {$int-$index+2}].0 [expr {$int-$index+3}].0
		}
	    }
	    $list config -state disabled
	    $xf(fuf).${o}list config -state disabled
	} {
	    # error, break loop
	    break
	}
	#set intlist [lreplace $intlist 0 0]
	incr index
    }

#    if {[string compare $operation cp] == 0 || \
#	    [string compare $operation mv] == 0} {
#	switch $xf(fsmode_$o) {
#	    1 {VirtualZip $xf(virtualfile) $o 1}
#	    2 {VirtualTar $xf(virtualfile) $o 1}
#	    3 {VirtualLha $xf(virtualfile) $o 1}
#	    5 {VirtualRpm $xf(virtualfile) $o 1}
#	    6 {VirtualRar $xf(virtualfile) $o 1}
#	}
#    }
    # TODO bg
    if {[string compare {} $clist]} {
	set xf(selekted$s) $clist
	set rc 1
    }
    return $rc
}
proc FO_Nor_Turbo {s o paths patho filelist intlist list operation op} {
    global xf

    InfoChange $s "$op..."
    set rc 0
    if {[string compare $operation rm] == 0} {
	if {$xf(smode_$s) == 3} {
	    set clip [AskWin "Delete from the HyperList only or also from the filesystem?" -50 -50 "Both" {} {} "HyperList"]
	    switch $clip {
		1 -
		2 {
		    foreach f $filelist {
			set idx [lsearch -exact $xf(do_list_$xf(fsmode_$s)) $f]
			set xf(do_list_$xf(fsmode_$s)) [lreplace $xf(do_list_$xf(fsmode_$s)) $idx $idx]
		    }
		    if {$clip == 1} {
			# HyperList only
			return 0
		    }
		}
		0 {
		    # cancel
		    return 1
		}
	    }
	}
	if {$xf(safedelete)} {
	    if {[string match $paths $xf(trashdir)]} {
		MessageBox "Trying to SafeDelete trashcan: Disable SafeDelete or use menuitem Empty Trash!" $s
		return 1
	    }
	    ClearTrashDir
	    .xfmenu.butt.m.del entryconfigure Undo* -state normal
	    set xf(undopath) $xf(pathi$s)
	    SaveUndo
	    # TODO kun tän tekis toisella tapaa, niin voisi palata täältä heti ja ruutu päivittyis myös heti (eli safedeletelle oma callback...tai jotain)
	    set rc [MoveFiles $s $paths $filelist $xf(trashdir)]
	    set rc [FO_WaitSem $rc {} 0 1]
	    if {$rc} {
		# error, try copy+delete
		set rc [CopyFiles $s $o $paths $filelist $xf(trashdir)]
		set rc [FO_WaitSem $rc "SafeDelete"]
		if {$rc == 0} {
		    set rc [DelFiles $s $paths $filelist]
		}
	    }
	} {
	    # not safedelete
	    set rc [DelFiles $s $paths $filelist]
	}
	# wait to see possible error
	if {$rc != 0} {
	    set rc [FO_WaitSem $rc]
	}
    } {
	if {$xf(smode_$o) == 3} {
	    # other side is HyperList
	    HyperList 0 $s
	    return 0
	}
	switch $xf(fsmode_$o) {
	    0 {
		set all 0
		set none 0
		FO_CheckOverWrite $s $o filelist intlist [GetFileNames $o $patho] all none
		if {[string compare {} $filelist] == 0} {
		    # no files
		    return 0
		}

		if {[ChkDosNames $filelist $xf(mdos_$o)]} {
		    if {![AskWin "$op: Some of the file names will be truncated. Proceed?"]} {
			return 1
		    }
		}
		if {[string compare $operation cp] == 0} {
		    set rc [CopyFiles $s $o $paths $filelist $patho]
		    set rc [FO_WaitSem $rc]
		} {
		    set rc [MoveFiles $s $paths $filelist $patho]
		    set rc [FO_WaitSem $rc]
		    if {$rc} {
			# error, try copy+delete
			set rc [CopyFiles $s $o $paths $filelist $patho]
			set rc [FO_WaitSem $rc]
			if {$rc == 0} {
			    set rc [DelFiles $s $paths $filelist]
			}
		    }
		}
		#if {$rc == 0 && [string match $operation "mv"]} {
		 #   set rc [DelFiles $s $paths $filelist]
		#}
	    }
	    1 -
	    2 -
	    3 -
	    5 -
	    6 -
	    4 {
		set rc [FO_Nor_Virt $s $o $paths $patho $filelist $intlist $operation $xf(fsmode_$o)]
		set xf(ftp.update) 1
	    }
	}
    }
    return $rc
}

# wrapper for waiting and releasing the "semaphore"
# if not async mode, return the rc value that was given as parameter
# param infostr contains additional info for error message
# param async allows forced vwait (for VFS bg operations)
# param noerror suppresses error message (for SafeDelete)
proc FO_WaitSem {sem {infostr {}} {async 0} {noerror 0}} {
    global bg xf
    #puts "FO_WaitSem()"
    if {$xf(async_fo) || $async} {
	vwait bg($sem.closed)
	#DEBUG "FO_WaitSem: trigger"
	if {$noerror && $bg($sem.error)} {
	    LogBoth "BACKGROUND ERROR:\n$bg($sem.errormsg)." 1
	} elseif {$bg($sem.error)} {
	    tkerror "$infostr BACKGROUND ERROR:\n$bg($sem.errormsg)"
	}
	return $bg($sem.error)
    }
    return $sem
}

proc FO_bg_exec {s paths patho cmd menustr} {
    global bg TMP xf

    set fileid [eval "bg_exec [list $cmd] \
	    {bg_handler 1 $s 0 $paths $patho} 1 1 $TMP(dir)"]
    set pid [pid $fileid]
    set bg($fileid.stoptime) "RUNNING!"
    
    set entry  "\[$pid\] - INTERNAL $menustr"
    
    .xfmenu.bg.m add cascade -label "$entry" \
	    -menu .xfmenu.bg.m.$fileid
    menu .xfmenu.bg.m.$fileid -tearoff 0
    
    .xfmenu.bg.m.$fileid add command -label Kill \
	    -command [list bg_killer $fileid $pid]
    
    .xfmenu.bg.m.$fileid add command -label "More.."\
	    -command [list bg_panel $fileid]

    return $fileid
}

# if async, returns the semaphore id
# otherwise returns 0, if OK; 1, if error
proc CopyFiles {s o path files dest} {
    global xf errorInfo tcl_platform

    set rc 0
    #puts "Copys $files to $dest"
    if {[string compare windows $tcl_platform(platform)] == 0} {
	foreach f $files {
	    set rc [catch {file copy -force -- $path$f $dest}]
	    # TODO: keskeytetaanko heti vai jatketaanko loppuun
	    if {$rc} {break}
	}
    } {
	cd $path
	if {$xf(async_fo)} {
	    # async
	    return [FO_bg_exec $s $path $dest "$xf(COPY) $files [list $dest]" COPY]
	} {
	    # sync
	    set rc [catch {eval exec $xf(COPY) $files [list $dest]}]
	}
    }
    if {$rc && $xf(mdos_$o) > 0} {
	# CopyCatch also shows error, if needed
	set rc [CopyCatch $s $path $files $dest]
    } elseif {$rc} {
	tkerror $errorInfo $s
    }
    return $rc
}
proc CopyFile {s o path file dest {newf {}}} {
    global xf errorInfo tcl_platform

    set rc 0
    #cd $path
    #puts "Copy $file to $dest"
    if {[string compare windows $tcl_platform(platform)] == 0} {
	set rc [catch {file copy -force -- [file join $path $file] [file join $dest $newf]}]
    } {
	set rc [catch {eval exec $xf(COPY) [list [file join $path $file]] [list [file join $dest $newf]]}]
    }
    if {$rc && $xf(mdos_$o) > 0} {
	# CopyCatch also shows error, if needed
	set rc [CopyCatch $s $path $file $dest $newf]
    } elseif {$rc} {
	tkerror $errorInfo $s
    }
    return $rc
}
proc MoveFiles {s path files dest} {
    global xf errorInfo tcl_platform

    set rc 0
    #puts "Moves $files to $dest"
    if {[string compare windows $tcl_platform(platform)] == 0} {
	foreach f $files {
	    set rc [catch {file rename -force -- $path$f $dest}]
	    # TODO: keskeytetaanko heti vai jatketaanko loppuun
	    if {$rc} {break}
	}
    } {
	cd $path
	if {$xf(async_fo)} {
	    # async
	    return [FO_bg_exec $s $path $dest "$xf(MOVE) $files [list $dest]" MOVE]
	} {
	    # sync
	    set rc [catch {eval exec $xf(MOVE) $files [list $dest]}]
	}
    }
    if {$rc} {
	# TODO why is it not done here?!?!!?
	Log $s "Move failed, trying copy & delete!" 1
	#tkerror $errorInfo $s
    }
    return $rc
}
proc MoveFile {s path file dest {newf {}}} {
    global xf errorInfo tcl_platform

    set rc 0
    #cd $path
    #puts "Move $file to $dest"
    if {[string compare windows $tcl_platform(platform)] == 0} {
	set rc [catch {file rename -force -- [file join $path $file] [file join $dest $newf]}]
    } {
	set rc [catch {eval exec $xf(MOVE) [list [file join $path $file]] [list [file join $dest $newf]]}]
    }
    if {$rc} {
	Log $s "Move failed, trying copy & delete!" 1
	#tkerror $errorInfo $s
    }
    return $rc
}
proc CopyCatch {s paths flist dest {newf {}}} {
    global errorInfo

    # TODO if overwriting and fails...
    set rc 0
    if {[string compare {} $newf] == 0} {
	# multiple files
	foreach f $flist {
	    set rc [AreFilesSame $paths$f $dest$f]
	    #puts "s: <$paths$f> d: <$dest$f> :: $rc"
	    if {$rc} {break}
	}
	#set f [lindex $flist end]
    } {
	set rc [AreFilesSame $paths$flist $dest$newf]
	#set f $newf
    }
    if {$rc} {
	tkerror $errorInfo $s
    }
    #if {[file exists $dest$f] == 1} {
	#set rc 0
    #} {
	#set rc 1
    #}
    return $rc
}
# returns 0 if files are of the same size, 1 otherwise
proc AreFilesSame {files fileo} {
    set rc 1
    if {[file exists $fileo] && \
	    [file size $files] == [file size $fileo]} {
	    set rc 0
    }
    return $rc
}
proc DelFiles {s path files} {
    global xf errorInfo tcl_platform

    #puts "Del $files in $path"
    catch {cd $path}
    set rc 0
    if {[string compare windows $tcl_platform(platform)] == 0} {
	foreach f $files {
	    set rc [catch {file delete -force -- $f}]
	    if {$rc} {break}
	}
    } {
	if {$xf(async_fo)} {
	    # async
	    # give empty destination...
	    return [FO_bg_exec $s $path "xyZZy" "$xf(DEL) $files" DELETE]
	} {
	    # sync
	    set rc [catch {eval exec $xf(DEL) $files}]
	}
    }
    if {$rc} {
	tkerror $errorInfo $s
    }
    return $rc
}
proc DelFile {s path file} {
    global xf errorInfo tcl_platform

    #puts "Del $file in $path"
    #cd $path
    set rc 0
    if {[string compare windows $tcl_platform(platform)] == 0} {
	set rc [catch {file delete -force -- $path$file}]
    } {
	set rc [catch {eval exec $xf(DEL) [list $path$file]}]
    }
    if {$rc} {
	tkerror $errorInfo $s
    }
    return $rc
}
proc TrashCan {undo} {
    global xf

    if {$undo} {
	set xf(no_aud_left) 1
	set xf(no_aud_right) 1
	set wdl $xf(pathileft)
	set sell $xf(selektedleft)
	set wdr $xf(pathiright)
	set selr $xf(selektedright)
	ChangeDir left $xf(trashdir)
	ChangeDir right $xf(undopath)
	$xf(fuf).leftlist config -bg [option get .xfiles undo_mode_bg {}]
	$xf(fuf).rightlist config -bg [option get .xfiles undo_mode_bg {}]
	SelectAll left
	if {[AskWin "\[SafeDelete\]: Undo last deletion?"]} {
	    set files [GetSelNames left]
	    set rc [CopyFiles left right $xf(trashdir) $files $xf(undopath)]
	    set rc [FO_WaitSem $rc]
	    if {$rc  == 0} {
		DelFiles left $xf(trashdir) $files
	    }
	    set done 1
	} {
	    set done 0
	}
	ChangeDir left $wdl
	ChangeDir right $wdr
	if {$done} {
	    if {[string match $xf(pathileft) $xf(trashdir)]} {
		UnselectAll "left"
		UpdateListbox "left"
	    } elseif {[string match $xf(pathileft) $xf(undopath)]} {
		UpdateListbox "left"
	    }
	    if {[string match $xf(pathiright) $xf(trashdir)]} {
		UnselectAll "right"
		UpdateListbox "right"
	    } elseif {[string match $xf(pathiright) $xf(undopath)]} {
		UpdateListbox "right"
	    }
	    DefaultInfo "left"
	    DefaultInfo "right"
	    if {[info exists xf(undopath)]} {
		file delete -force [file join $xf(user_home) xfiles.undopath]
		unset xf(undopath)
	    }
	    .xfmenu.butt.m.del entryconfigure Undo* -state disabled
	}
	set xf(no_aud_left) 0
	set xf(no_aud_right) 0
    } {
	if {[AskWin "This will permanently clear your trashcan. Proceed?" -50 -50 {} {} {} Yes No] == 0} {
	    SetArrowPointer
	    return
	}
	ClearTrashDir
	set done 1
	if {[string match $xf(pathileft) $xf(trashdir)]} {
	    UnselectAll "left"
	    UpdateListbox "left"
	    DefaultInfo "right"
	} elseif {[string match $xf(pathiright) $xf(trashdir)]} {
	    UpdateListbox "right"
	    DefaultInfo "left"
	} {
	    DefaultInfo "left"
	    DefaultInfo "right"
	}
	if {[info exists xf(undopath)]} {
	    file delete -force [file join $xf(user_home) xfiles.undopath]
	    unset xf(undopath)
	}
	.xfmenu.butt.m.del entryconfigure Undo* -state disabled
    }
}

proc ClearTrashDir {} {
    global xf

    set rc [DelFiles left [file dirname $xf(trashdir)] [file tail $xf(trashdir)]]
    set rc [FO_WaitSem $rc "Empty Trash"]
    
    if {$rc == 0} {
	file mkdir [list $xf(trashdir)]
    }	
}

proc ReadFiles {s args} {
    global xf tcl_platform

    if {[string compare {} $args] == 0 \
	    && [string compare {} $xf(selekted$s)] != 0} {
	MessageBox "You are using the old version of internal command \[ReadFiles\]!\n\
		Please open Button Editor, select the button, re-select the item \
		'ReadFiles' and then save." $s
	return
    }
    # TODO why don't we use internal 'read' ??
    if {[string compare {} $args] == 0} {
	OutputWindow "" [list $xf(pathi$s)] "New"
    } {
	if {[string match {windows} $tcl_platform(platform)]} {
	    OutputWindow [eval exec $xf(CMDSHELL) type $args] [list $xf(pathi$s)] ""
	} {
	    OutputWindow [eval exec cat -- $args] [list $xf(pathi$s)] ""
	}
	UnselectAll $s
    }
}

proc Grep {s} {
    global xf prompt

    set prompt(1.label) "String:"
    set prompt(1.result) ""
    set prompt(2.label) "Pattern:"
    set prompt(2.result) "*"
    if {[DialogWin "The <string> will be searched from files matching <pattern> in current directory and its subdirectories."]} {
	if {[string compare {} $prompt(1.result)] == 0 || [string compare {} $prompt(2.result)] == 0} {
	    MessageBox "\[Grep\]: You must give two arguments!" $s
	    unset prompt
	    return
	}
	update idletasks
	cd $xf(pathi$s)
	#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	set files [exec find . -name $prompt(2.result) -print]
	set result ""
	foreach f [split $files \n] {
	    if {[catch {eval exec grep -n -e [list $prompt(1.result)] [list $f]} txt]} {
		continue
	    }
	    append result "$f:\n$txt\n\n"
	}
	if {[string compare {} $result] == 0} {
	    set result "*** No match ***"
	}
	OutputWindow $result [list $xf(pathi$s)]
    }
    unset prompt
}
proc MkDir {s} {
    global prompt xf

    if {[string match $s left]} {
	set o "right"
    } {
	set o "left"
    }

    set xf(clearselect) 0
    set prompt(1.label) ""
    set prompt(1.result) $xf(pathi$s)
    if {[DialogWin "Make directory:\n" -50 -50 0]} {
	set dirri [string trimright $prompt(1.result) /]
	if {[file exists "$dirri"]} {
	    MessageBox "\[MkDir\]: A file or a directory of that name already exists." $s
	} {
	    #if [catch {eval exec $xf(MKDIR) [list $dirri]}] {
		#MakeDirProc "$dirri"
	    #}
	    if {$xf(fsmode_$s) == 0} {
		# normal FS
		file mkdir "$dirri"
	    } {
		# FTP
		if {[FTP_CMD $xf(ftp.sock) "MKD $dirri"] == -1} {
		    MessageBox "FTP: Error creating directory '$dirri'\n\n$ftp($xf(ftp.sock).status)" $s
		}
		set xf(ftp.update) 1
	    }
	    UpdateListbox $s
	    DefaultInfo $o
	}
    }
    unset prompt
}
proc Rename {s} {
    global prompt xf ftp

    # TODO
    if {$xf(fsmode_$s) != 0 && $xf(fsmode_$s) != 4} {
	# allow only for normal and FTP
	MessageBox "Sorry, \[Rename\] only works for normal and FTP modes." $s
	return -1
    }

    if {[string compare {} $xf(selekted$s)] == 0} {
	NoSelect $s
    } {
	if {[string match $s left]} {
	    set o "right"
	} {
	    set o "left"
	}

	catch {cd $xf(pathi$s)}
	#set ind 0

	set x [winfo pointerx .]
	set y [winfo pointery .]
	set xf(clearselect) 0
	set otherfiles [GetFileNames $s $xf(pathi$s)]
	set all 0
	set none 0
	foreach t [GetSelNames $s] ind $xf(selekted$s) {
	    set prompt(1.label) ""
	    set prompt(1.result) $t
	    switch [DialogWin "Rename\n$t\nto:" -50 -50 1 $x $y "Abort!"] {
		0 {}
		1 {
		    # ok
		    # kludge for checking overwrite, it needs to be as a list
		    set newf [list $prompt(1.result)]
		    # check overwrite
		    if {$all == 0} {
			if {[FO_CheckOverWrite $s $s newf ind $otherfiles all none $x $y] == 1} {
			    # do not overwrite
			    continue
			}
		    }
		    if {$xf(fsmode_$s) == 0} {
			# normal
			if {[catch {file rename -force $xf(pathi$s)$t $xf(pathi$s)$prompt(1.result)} err]} {
			    tkerror $err $s
			    return
			}
		    } {
			# FTP
			if {[FTP_RENAME $xf(ftp.sock) $xf(pathi$s)$t $xf(pathi$s)$prompt(1.result)] == -1} {
			    # error
			    tkerror $ftp($xf(ftp.sock).status) $s
			    return
			}
			set xf(ftp.update) 1
		    }

		    #set it [lindex $xf(selekted$s) $ind]
		    $xf(fuf).${s}list tag remove sel [expr {$ind+1}].0 [expr {$ind+2}].0

		    AddSelSize $s $ind "-"
		    ShowSelSize $s
		    #set xf(selekted$s) [lreplace $xf(selekted$s) $ind $ind]
		    continue
		}
		2 {
		    set xf(noinfo) 1
		    after 50 [list set xf(noinfo) 0]
		    after 150 [list InfoChange $s "Command aborted!"]
		    after 4000 [list DefaultInfo $s]
		    break
		}
	    }
	    #incr ind
	}
    }
    set xf(selekted$s) [FL_Selection $s]
    catch {unset prompt}
    if {[string compare $xf(pathileft) $xf(pathiright)] == 0} {
	UpdBoth
    } {
	UpdateListbox $s
    }
}
proc CopyAs {s} {
    global prompt xf TMP

    if {[string compare {} $xf(selekted$s)] == 0} {
	NoSelect $s
    } {
	if {[string match $s left]} {
	    set o "right"
	} {
	    set o "left"
	}

	#set ind 0
	set x [winfo pointerx .]
	set y [winfo pointerx .]
	set xf(clearselect) 0
	set vfs 0
	# TODO RAR, RPM
	switch $xf(fsmode_$o) {
	    4 -
	    0 {}
	    1 {
		set voper $xf(TOZIP)
		set vproc "VirtualZip"
		set vfs 1
	    }
	    2 {
		set voper $xf(TOTAR)
		set vproc "VirtualTar"
		set vfs 1
	    }
	    3 {
		set voper $xf(TOLHA)
		set vproc "VirtualLha"
		set vfs 1
	    }
	    default {return 1}
	}
	if {$vfs} {
	    if {![file writable $xf(virtualfile)]} {
		MessageBox "\[CopyAs\]: You can not write to\n$xf(virtualfile)\nNo write permission." $s
		return
	    }
	}
	set otherfiles [GetFileNames $o $xf(pathi$o)]
	set all 0
	set none 0
	foreach t [GetSelNames $s] ind $xf(selekted$s) {
	    set prompt(1.label) ""
	    set prompt(1.result) $t
	    switch [DialogWin "Copy\n$t\nas:" -50 -50 1 $x $y "Abort!"] {
		0 {}
		1 {
		    # ok
		    # kludge for checking overwrite, it needs to be as a list
		    set newf [list $prompt(1.result)]
		    # check overwrite
		    if {$all == 0} {
			if {[FO_CheckOverWrite $s $o newf ind $otherfiles all none $x $y] == 1} {
			    # do not overwrite
			    continue
			}
		    }
		    if {$xf(fsmode_$s) == 0} {
			# curr side is in normal mode
			switch $xf(fsmode_$o) {
			    0 {
				CopyFile $s $o $xf(pathi$s) $t $xf(pathi$o) $prompt(1.result)
			    }
			    4 {
				# TODO: nor -> FTP
				set rc 0
				#set rc [CopyFile $s $o $xf(pathi$s) $t $TMP(dir) $prompt(1.result)]
				XF_ProgressBar $xf(ftp.sock)
				FO_SetFTPLocalFileSize $s $xf(pathi$s) $t $ind 0
				if {$rc == 0} {
				    #cd $TMP(dir)
				    #XF_ProgressBar $file "Putting" $commSock
				    XF_PBItem $prompt(1.result) "Putting"
				    if {[FTP_PUT $xf(ftp.sock) [file join $xf(pathi$s) $t] $prompt(1.result) $xf(ftp.active)] == -1} {
					# error
					# TODO: askwin? continue put
					MessageBox "FTP: Error copying file '$prompt(1.result)'\n\n$ftp($xf(ftp.sock).status)" $s
					set rc 1
				    }
				    set xf(ftp.update) 1
				}
				# hide progress bar while we process 
				# next file name
				wm iconify .__pbar
			    }
			    default {
				# VFS
				set rc 0
				set temppi [file join $TMP(dir) [string trimleft $xf(pathi$o) /]]
				# create VFS inpath to TMP
				file mkdir $temppi
				set rc [CopyFile $s $o $xf(pathi$s) $t $temppi/ $prompt(1.result)]
				if {$rc == 0} {
				    cd $TMP(dir)
				    set dirri [string trimleft $xf(pathi$o) /]
				    set file [append dirri $prompt(1.result)]
				    eval exec $voper [list $xf(virtualfile)] [list $file]
				    if {$xf(fsmode_$o) == 2} {
					# TAR
					$vproc $xf(virtualfile) $o $xf(tar.decomp) 1
				    } {
					# other
					$vproc $xf(virtualfile) $o 1
				    }
				}
				# get the root of inpath
				if {[string compare / $xf(pathi$o)] == 0} {
				    # in pkg root
				    file delete -force -- [file join $TMP(dir) $prompt(1.result)]
				} {
				    regexp {^/([^/]+)/.*$} $xf(pathi$o) gfg root
				    file delete -force -- [file join $TMP(dir) $root]
				}
			    }
			}
		    } {
			# curr side in VFS-mode
			if {$xf(fsmode_$s) == 4} {
			    # FTP, show progress bar
			    XF_ProgressBar $xf(ftp.sock)
			}

			if {[VirtualOut $s [string trimleft $xf(pathi$s)$t /] $xf(pathi$o)$prompt(1.result)]} {
			    break
			}
		    }
		    #set it [lindex $xf(selekted$s) $ind]
		    $xf(fuf).${s}list tag remove sel [expr {$ind+1}].0 [expr {$ind+2}].0
		    AddSelSize $s $ind "-"
		    ShowSelSize $s
		    #set xf(selekted$s) [lreplace $xf(selekted$s) $ind $ind]
		    continue
		}
		2 {
		    # abort
		    set xf(noinfo) 1
		    after 50 [list set xf(noinfo) 0]
		    after 150 [list InfoChange $s "Command aborted!"]
		    after 4000 [list DefaultInfo $s]
		    break
		}
	    }
	    #incr ind
	}
	XF_PBFinal
    }
    set xf(selekted$s) [FL_Selection $s]
    catch {unset prompt}
    if {[string compare $xf(pathi$s) $xf(pathi$o)] == 0} {
	UpdBoth
    } {
	UpdateListbox $o
    }
}

# This procedure asks the user to select the target directory where 
# the selected files in current ($s) side will be copied to.
proc MoveTo {s} {
    CopyTo $s "mv"
}
# This procedure asks the user to select the target directory where 
# the selected files in current ($s) side will be copied to.
proc CopyTo {s {op cp}} {
    global xf

    #puts "DEB: CopyTo()"

    if {[string compare {} $xf(selekted$s)] == 0} {
	NoSelect $s
	return
    }
    
    if {[string compare cp $op] == 0} {
	set str copy
	set oper "\[CopyTo\]"
    } {
	set str move
	set oper "\[MoveTo\]"
    }

    # save operation parameters 
    # (they may change during the directory selection)
    set paths $xf(pathi$s)
    set sel $xf(selekted$s)
    set files [GetSelNames $s]

    # first, select target
    set xf(smode_left) 2
    set xf(smode_right) 2
    set xf(copyto_side) $s
    # operation is needed when canceling, so we use this...
    set xf(copyto_target) $oper
    $xf(fuf).leftlist config -cursor target
    $xf(fuf).rightlist config -cursor target
    InfoChange $s "Select the directory where to $str the selected files..."

    vwait xf(copyto_target)
    #DEBUG "CopyTo(): $xf(copyto_target)"
    SetArrowPointer $xf(fuf).leftlist
    SetArrowPointer $xf(fuf).rightlist
    set xf(smode_left) 0
    set xf(smode_right) 0

    if {[string compare {} $xf(copyto_target)] != 0} {
	# not canceled operation
	FileOps $op $s $paths $xf(copyto_target) $sel $files $xf(copyto_side)
    } {
	InfoChange $s "$oper canceled..."
	after 4000 [list DefaultInfo $s]
    }
    unset xf(copyto_target) xf(copyto_side)
    #puts "DEB: CopyTo() end"
}

proc PatternSelect {s} {
    global prompt xf vdleft vdright vfleft vfright

    set xf(clearselect) 0
    set prompt(1.label) ""
    set prompt(1.result) "*"
    if {[DialogWin "Select all files matching pattern:" -50 -50 0]} {
	if {[string compare $prompt(1.result) {}] == 0} {
	    unset prompt
	    return
	}
	set ind [llength [set vd$s]]
	foreach row [set vf$s] {
	    if {[string match $prompt(1.result) [lindex $row 0][lindex $row 1]]} {
		$xf(fuf).${s}list tag add sel [expr {$ind+1}].0 [expr {$ind+2}].0
		lappend xf(selekted$s) $ind
	    }
	    incr ind
	}		
	# make selection topmost tag
	$xf(fuf).${s}list tag raise sel
	InfoChange $s "Calculating..."
	after idle [list SelectionSize $s]
    }
    unset prompt
}
proc DirSize {s} {
    global xf vdleft vdright

    cd $xf(pathi$s)
    set dirs {}
    # TODO: question: links that point to directories, do we give
    # zero (as du returns), link size (few bytes) or the size of the directory
    # to which the link points to??
    # Links can be detected by checking if vdleft(ind.link) is empty or not
    set dirlen [llength [set vd$s]]
    foreach i $xf(selekted$s) {
	if {$i >= $dirlen} {break}
	#puts "$i: [GetFileName $s $i]"
	lappend dirs [GetFileName $s $i]
    }
    #DEBUG $dirs
    if {[string compare {} $dirs] == 0} {
	return
    }
    set xf(clearselect) 0
    #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    set res [eval exec $xf(DIRSIZE) $dirs]
    #DEBUG $res
    set n 0
    $xf(fuf).${s}list config -state normal
    foreach line [split $res \n] {
	scan $line "%d" size
	if {$xf(du_1k)} {
	    set size [expr {$size * 1024}]
	} {
	    set size [expr {$size * 512}]
	}
	set p [lindex $xf(selekted$s) $n]
	set row [lindex [set vd$s] $p]
	# change size in internal data
	set row [lreplace $row 2 2 $size]
	set vd$s [lreplace [set vd$s] $p $p $row]
	#incr p
	#$xf(fuf).${s}list delete $p.0 [expr $p +1].0
	#FL_LbInsert $s $p.0 [FormatFileName [lindex $row 0] [lindex $row 1][lindex $row end]] [lindex $row 2] [lindex $row 3] [lindex $row 4] [lindex $row 5] [lindex $row 6] 1
	incr n
    }
    incr n -1
    $xf(fuf).${s}list config -state disabled
    set xf(selekted$s) [lreplace $xf(selekted$s) 0 $n]
    set xf(redraw$s) 1
    UpdateListbox $s
    #after idle [list SelectionSize $s]
}
proc AutoUD {} {
    global xf

    foreach s [list "left" "right"] {
	if {$xf(no_aud_$s) == 0} {
	    if {$xf(fsmode_$s) == 0} {
		# do update only for normal filesystem to avoid extra load
		set tmp 0
		catch {set tmp [file mtime $xf(pathi$s)]}

		if {$xf(${s}autoud) != $tmp} {
		    set xf(${s}autoud) $tmp
		    Log $s "AutoUpdate $s '$xf(pathi$s)'!" 0
		    after 1000 [list UpdateListbox $s]
		}
	    }
	}
    }
    if {$xf(autoupdate)} {
	after 5000 [list AutoUD]
    }
}
proc MenuBar {} {
    global xf

    frame .xfmenu -relief raised -borderwidth 1
    pack .xfmenu -side top -fill x

    menubutton .xfmenu.help -text Help -menu .xfmenu.help.m -underline 0 \
	    -height 1
    set m [menu .xfmenu.help.m]
    $m add check -label "Help mode" \
	    -underline 1 -command HelpProc
    $m add command -label "External commands..." \
	    -underline 1 -command Externals
    $m add separator
    $m add command -label "Main help..." \
	    -underline 0 -command "GetHelp $xf(xf_home)xfiles.manual"
    $m add command -label "FAQ..." \
	    -underline 0 -command "GetHelp $xf(xf_home)xfiles.faq"
    $m add separator
    $m add command -label "About..." -underline 0 \
	    -command {Aboutti}
    pack .xfmenu.help -side right

    menubutton .xfmenu.file -text "File" -menu .xfmenu.file.m -underline 0 \
	    -height 1

    set m [menu .xfmenu.file.m]
    $m add command -label "Append selection to HyperList" -command {HyperList 0} -underline 0
    $m add command -label "Show HyperList" -command {HyperList 1} -underline 3
    # TODO ei futaa kovin hienosti
    $m add command -label "Clear HyperList" -command {ClearHyperList} -underline 0
    $m add separator
    $m add command -label "Save settings" -command SaveSettings -underline 0
    $m add separator
    $m add command -label "Exit program" -underline 0 \
	    -command "Confirm_exit"
    pack .xfmenu.file -side left


    menubutton .xfmenu.config -text Config -menu .xfmenu.config.m \
	    -underline 0 -height 1

    set m [menu .xfmenu.config.m]

    $m add check -label "Edit buttons..."\
	    -underline 5 -command {ButtonEditorProc} -variable xf(be_on)
    $m add check -label "Edit extensions..." \
	    -underline 5 -command {ExtEditor} -variable xf(ee_on)
    $m add check -label "Edit resources..."\
	    -underline 5 -command [list ResourceEditor $xf(rcfile)] \
	    -variable xf(re_on)
    $m add check -label "Edit file groups..." \
	    -underline 10 -command {TagEditor} -variable xf(te_on)
    $m add check -label "Edit FTP aliases..." \
	    -underline 5 -command {FAE} -variable xf(fae_on)

    pack .xfmenu.config -side left

    menubutton .xfmenu.butt -text Options -menu .xfmenu.butt.m -underline 0 \
	    -height 1
    set m [menu .xfmenu.butt.m]
    $m add check -label "Turbo file operations" \
	    -underline 1 -variable xf(turbomode) -command {set xf(turbo_bu) $xf(turbomode)}
    $m add check -label "Async file operations" \
	    -underline 2 -variable xf(async_fo) -command {
	if {$xf(async_fo) == 0} {
	    set xf(turbomode) $xf(turbo_bu)
	    .xfmenu.butt.m entryconfigure Turbo* -state normal
	} {
	    set xf(turbo_bu) $xf(turbomode)
	    set xf(turbomode) 1
	    .xfmenu.butt.m entryconfigure Turbo* -state disabled
	}
    }
    $m add check -label "AutoUpdate" \
	    -underline 0 -variable xf(autoupdate) -command {if {$xf(autoupdate) == 1} { \
	    set xf(leftautoud) [file mtime $xf(pathileft)]; \
	    set xf(rightautoud) [file mtime $xf(pathiright)]; \
	    AutoUD}}
    $m add check -label "Show link destination" \
	    -underline 0 -variable xf(links) \
	    -command UpdBoth
    $m add check -label "MMB opens dir in the other list" \
	    -underline 2 -variable xf(MMB_opens_other)
    $m add command -label "Column setup..." \
	    -underline 0 -command {XF_ColumnSetup}

    $m add separator
    $m add cascade -label "Sort by" -menu $m.sort \
	    -underline 1
    $m add cascade -label "Deleting" -menu $m.del \
	    -underline 0
    $m add cascade -label "Mail check" -menu $m.mail \
	    -underline 0
    $m add cascade -label "Title" -menu $m.sub1 \
	    -underline 0
    $m add cascade -label "Logging" -menu $m.log \
	    -underline 0
    $m add separator
    $m add cascade -label "FTP" -menu $m.ftp \
	    -underline 0
    menu $m.sort -tearoff 0
    $m.sort add radio -label "Extension" -variable xf(sortby) \
	    -value 1 -underline 0 -command RedrawBoth
    $m.sort add radio -label "Group" -variable xf(sortby) \
	    -value 7 -underline 0 -command RedrawBoth
    $m.sort add radio -label "Modification time" -variable xf(sortby) \
	    -value 2 -underline 0 -command RedrawBoth
    $m.sort add radio -label "Name" -variable xf(sortby) \
	    -value 0 -underline 0 -command RedrawBoth
    $m.sort add radio -label "Name case insensitive" -variable xf(sortby) \
	    -value 3 -underline 5 -command RedrawBoth
    $m.sort add radio -label "Owner" -variable xf(sortby) \
	    -value 7 -underline 0 -command RedrawBoth
    $m.sort add radio -label "Protection" -variable xf(sortby) \
	    -value 5 -underline 0 -command RedrawBoth
    $m.sort add radio -label "Size" -variable xf(sortby) \
	    -value 4 -underline 0 -command RedrawBoth
    $m.sort add separator
    $m.sort add radio -label "Ascending" -variable xf(sortorder) \
	    -value "increasing" -underline 0 -command RedrawBoth
    $m.sort add radio -label "Descending" -variable xf(sortorder) \
	    -value "decreasing" -underline 0 -command RedrawBoth
    $m.sort add separator
    $m.sort add check -label "Name header sorts case insensitive" -variable xf(cf_name_case) -underline 5 -onvalue 3 -offvalue 0
    menu $m.sub1 -tearoff 0
    $m.sub1 add check -label "Mem/Swap" -variable xf(memenable) \
	    -underline 0 -command titlemem
    $m.sub1 add check -label "Time" -variable xf(timeenable) \
	    -underline 0 -command titletime
    menu $m.ftp -tearoff 0
    $m.ftp add check -label "Short listing" -variable xf(ftp.shortlist) \
	    -onvalue 1 -offvalue 0 -underline 0 -command {
	if {[info exists xf(bgact.side)]} {
	    # only if mode is FTP
	    if {$xf(fsmode_$xf(bgact.side)) == 4} {
		if {$xf(ftp.shortlist) == 0} {
		    # switching from short to long -> clear cache
		    catch {unset ftpcac}
		}
		FileList $xf(bgact.side) $xf(pathi$xf(bgact.side))
	    }
	}
    }
    $m.ftp add command -label "Clear dir cache" -underline 0 \
	    -command {catch {unset ftpcac}} -state disabled

    menu $m.log -tearoff 0
    $m.log add check -label "Log" -variable xf(log) \
	    -underline 0 -command LogVis
    $m.log add check -label "Log To File" -variable xf(log2file) \
	    -underline 7
    $m.log add separator
    $m.log add command -label "Clear Log Windows" -underline 0 -command ClearLogs
    menu $m.del -tearoff 0
    $m.del add check -label "SafeDelete" -underline 0 \
	    -variable xf(safedelete)
    $m.del add command -label "Undo last deletion" -underline 0 \
	    -command [list TrashCan 1] -state disabled
    $m.del add command -label "Empty trash" -underline 0 \
	    -command [list TrashCan 0]
    menu $m.mail -tearoff 0
    $m.mail add check -label "Enabled" -underline 0 \
	    -variable xf(mailchk) \
	    -underline 0 -command {
	global env;
	if {[info exists env(MAIL)]} {
	    MailChk
	} {
	    MessageBox "Sorry, cannot find Your mail spool. Disabling Mail Check!"
	    .xfmenu.butt.m entryconfigure Mail* -state disabled
	}
	if {$xf(mailchk) == 1} {set st "normal"} {set st "disabled"}
	.xfmenu.butt.m.mail entryconfigure Messa* -state $st
	.xfmenu.butt.m.mail entryconfigure Read* -state $st
    }
    $m.mail add check -label "MessageBox" -underline 0 \
	    -variable xf(mailmsgbox) -command {
	if {$xf(mailmsgbox) == 1} {set t "disabled"} {set t "normal"};
	.xfmenu.butt.m.mail entryconfigure Read* -state $t
    }
    $m.mail add check -label "Read Mail on Ack" -underline 0 \
	    -variable xf(r_mail_on_ack)

    menubutton .xfmenu.lines -text "Buttons" -menu .xfmenu.lines.m \
	    -underline 0 -height 1
    set m [menu .xfmenu.lines.m -tearoff 1]
    $m add command -label "All" -command \
	    {set xf(butsetindic) "";ButtonLineSets {1 2 3 4 5 6 7 8}} -underline 0
    $m add command -label "None" -command {set xf(butsetindic) "";ButtonLineSets} \
	    -underline 0
    $m add separator
    $m add cascade -label "Lines" -menu $m.sub1 \
	    -underline 0
    $m add separator
    $m add radio -label "Set 1 (F9)" -variable xf(butsetindic) \
	    -command {eval {ButtonLineSets $xf(buttonset1)}}
    $m add radio -label "Set 2 (F10)" -variable xf(butsetindic) \
	    -command {eval {ButtonLineSets $xf(buttonset2)}}
    $m add radio -label "Set 3 (F11)" -variable xf(butsetindic) \
	    -command {eval {ButtonLineSets $xf(buttonset3)}}
    $m add radio -label "Set 4 (F12)" -variable xf(butsetindic) \
	    -command {eval {ButtonLineSets $xf(buttonset4)}}
    set m [menu $m.sub1 -tearoff 0]
    $m add check -label "Line 1 (F1)" -variable xf(linz1) \
	    -command {ButtonLines 1}
    $m add check -label "Line 2 (F2)" -variable xf(linz2) \
	    -command {ButtonLines 2}
    $m add check -label "Line 3 (F3)" -variable xf(linz3) \
	    -command {ButtonLines 3}
    $m add check -label "Line 4 (F4)" -variable xf(linz4) \
	    -command {ButtonLines 4}
    $m add check -label "Line 5 (F5)" -variable xf(linz5) \
	    -command {ButtonLines 5}
    $m add check -label "Line 6 (F6)" -variable xf(linz6) \
	    -command {ButtonLines 6}
    $m add check -label "Line 7 (F7)" -variable xf(linz7) \
	    -command {ButtonLines 7}
    $m add check -label "Line 8 (F8)" -variable xf(linz8) \
	    -command {ButtonLines 8}

    pack .xfmenu.butt -side left
    pack .xfmenu.lines -side left

    menubutton .xfmenu.screen -text "Screen" -menu .xfmenu.screen.m \
	    -underline 0 -height 1

    set m [menu .xfmenu.screen.m]
    $m add radio -label "Normal FS" -command XF_Screen -underline 0 \
	    -variable xf(screen) -value 0 -state disabled
    $m add radio -label "FTP FS" -underline 0 \
	    -command XF_Screen -variable xf(screen) -value 1 -state disabled
    pack .xfmenu.screen -side left


    menubutton .xfmenu.bg -text "Jobs" -menu .xfmenu.bg.m \
	    -underline 0 -height 1
    set m [menu .xfmenu.bg.m]
    

    pack .xfmenu.bg -side left

    frame .xfmenu.if
    pack propagate .xfmenu.if 0
    pack .xfmenu.if -side left -expand true -fill both

    label .xfmenu.if.mem -fg "#6060a0"
    button .xfmenu.if.time -fg "#6060a0" -relief flat \
	    -state disabled -disabledforeground "#6060a0" \
	    -highlightthickness 0 -command {
	set xf(mailnotice) 1
	after 2000 [list titlemail 0]
	#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	if {$xf(r_mail_on_ack) == 1} {eval exec xterm -e [option get .xfiles mail_reader {}] &}
    }
    pack .xfmenu.if.time -side right
    pack .xfmenu.if.mem -side left
}
proc SetCnfMenuBg {} {
    global xf

    if {$xf(ee_on) || $xf(be_on) || $xf(re_on)|| $xf(te_on)} {
	.xfmenu.config configure -background #fcbcbc
	.xfmenu.config configure -activebackground #fccccc
	.xfmenu.config configure -relief groove
    } {
	.xfmenu.config configure -background $xf(config_menu_bg)
	.xfmenu.config configure -activebackground $xf(config_menu_abg)
	.xfmenu.config configure -relief flat
    }
}

proc HelpProc {} {
    global xf

    if {$xf(helpmode) == 1} {
	set xf(helpmode) 0
	SetArrowPointer
	if {$xf(editmode) == 0} {
	    foreach var [array names xf Help*] {
		unset xf($var)
	    }
	}
	bindtags $xf(fuf).leftlist {XF XF_Listbox . all}
	bindtags $xf(fuf).rightlist {XF XF_Listbox . all}
    } {
	source $xf(main_pophelp_file)
	source $xf(user_pophelp_file)
	if {![info exists xf(Help.Version)]} {
	    ConvertHelp
	} elseif {$xf(Help.Version) != 2} {
	    ConvertHelp
	}
	set xf(helpmode) 1
	. config -cursor question_arrow
	bindtags $xf(fuf).leftlist {XF}
	bindtags $xf(fuf).rightlist {XF}
    }
}
proc RedrawBoth {} {
    global xf
    
    foreach s {left right} {
	set xf(redraw$s) 1
	set xf(sortby_$s) $xf(sortby)
	set xf(sortorder_$s) $xf(sortorder)
    }
    UpdBoth
}


proc UpdBoth {} {
    SetWaitPointer
    UpdateListbox left
    UpdateListbox right
    SetArrowPointer
}

proc ButtonLines {line {key 0}} {
    global xf

    set xf(butsetindic) ""
    set idx0 [expr {($line-1) * 2}]
    set idx1 [expr {$idx0 + 1}]
    if {$key > 0} {
	if {!$xf(linz$line)} {
	    set xf(linz$line) 1
	} {
	    set xf(linz$line) 0
	}
    }

    if {$xf(linz$line)} {
	pack .xfleft.bf($idx0) -side bottom -expand true -fill x
	pack .xfright.bf($idx1) -side bottom -expand true -fill x
    } {
	pack forget .xfleft.bf($idx0)
	pack forget .xfright.bf($idx1)
	.xfleft config -height 1
	.xfright config -height 1
    }
}
proc ButtonLineSets {{par ""}} {
    global xf
    for {set i 0} {$i < 8} {incr i} {
	set xf(linz[expr {$i +1}]) 0
	pack forget .xfleft.bf([expr {2 * $i}])
	pack forget .xfright.bf([expr {2 * $i +1}])
	.xfleft config -height 1
	.xfright config -height 1
    }
    foreach i $par {
	set xf(linz$i) 1
	pack .xfleft.bf([expr {2 * ($i-1)}])\
		-side bottom -expand true -fill x
	pack .xfright.bf([expr {(2 * ($i-1))+1}])\
		-side bottom -expand true -fill x
    }
}
proc MailChk {} {
    global xf env

    if {$xf(mailchk) == 1} {
	if {![catch {set tmp [file mtime $env(MAIL)]}]} {
	    set tmp2 [file atime $env(MAIL)]
	    if {$tmp != $xf(mailtime)} {
		if {$xf(mailatime) == $tmp2 || $xf(mailatime) == 0} {
		    if {$xf(mailmsgbox) == 1} {
			if {[AskWin "You have new mail !\nRead it now?"]} {
			    #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			    eval exec xterm -e [option get .xfiles mail_reader {}] &
			}
		    } {
			set xf(mailnotice) 0
			titlemail 20
		    }
		}
	    }
	    set xf(mailtime) $tmp
	    if {$xf(mailatime) < $tmp2} {
		set xf(mailatime) $tmp2
	    }
	}
	after 10000 MailChk
    }
}
proc titlemail {t} {
    global xf
    if {$t > 0} {
	after 2000 {
	    if {$xf(mailnotice) == 0} {
		if {$xf(timeenable) == 1} {
		    set dt [string range [clock format [clock seconds] -format %c] 0 15]
		    .xfmenu.if.time config -text " < $dt > " -fg "#6060a0" \
			    -relief flat -state normal \
			    -disabledforeground "#6060a0"\
			    -highlightthickness 0\
			    -fg "#6060a0"
		    update idletasks
		} {
		    .xfmenu.if.time config -text "             "
		}
		after 1000 {
		    .xfmenu.if.time config -text "< New Mail >" \
			    -state normal -fg #ff3333
		    update idletasks
		}
	    }
	}
	incr t -1
	if {$xf(mailnotice) == 1} {
	    titlemail 0
	} {
	    after 3000 [list titlemail $t]
	}
    } {
	if {$xf(timeenable) == 1} {
	    set dt [string range [clock format [clock seconds] -format %c] 0 15]
	    .xfmenu.if.time config -text " < $dt > " -fg "#6060a0" \
		    -relief flat -state disabled \
		    -disabledforeground "#6060a0" \
		    -highlightthickness 0
	    update idletasks
	} {
	    .xfmenu.if.time config -text ""
	    update idletasks
	}
    }
}
proc titletime {} {
    global xf

    if {$xf(timeenable) == 1} {
	set dt [string range [clock format [clock seconds] -format %c] 0 15]
	.xfmenu.if.time config -text " < $dt > " -fg "#6060a0"
	after 30000 titletime
    } {
	.xfmenu.if.time config -text ""
    }
}
proc titlemem {} {
    global xf tcl_platform

    if {$xf(memenable) == "1" && [string compare unix $tcl_platform(platform)] == 0 && [file exists /proc/meminfo]} {
	set fh [open /proc/meminfo r]
	set ms [read $fh]
	close $fh
	set mem [lindex $ms [expr {[lsearch -exact $ms MemFree:] + 1}]]
	set swp [lindex $ms [expr {[lsearch -exact $ms SwapFree:] + 1}]]
	unset ms
	.xfmenu.if.mem config -text "< Mem: [FormatNumber [expr {$mem * 1024}]] Swap: [FormatNumber [expr {$swp * 1024}]] >"
	after 3000 titlemem
    } {
	.xfmenu.if.mem config -text ""
    }
}
proc Aboutti {} {
    global xf
    set w .about
    catch {destroy $w}
    set bg "#661d73"
    set abg "#772d83"
    set afg "#afffff"
    toplevel $w -bg $bg
    if {[option get .xfiles messages_always_on_top {}] == 1} {
	bind $w <Visibility> [list KeepOnTop $w %W %s]
    }
    wm title $w "About X-Files"
    wm iconname $w "About X-Files"
    wm geometry $w +300+300
    wm protocol $w WM_DELETE_WINDOW  {image delete xfimage; destroy .about}

    frame $w.text -bg $bg -relief raised -bd 2
    frame $w.buttons -bg $bg
    pack  $w.buttons -side bottom -expand y -fill x -pady 2m
    button $w.buttons.dismiss -bg $bg -fg "#afffff" -text Dismiss \
	    -activebackground $abg -activeforeground $afg -bd 2\
	    -padx 1 -pady 1 -command {image delete xfimage; destroy .about}
    pack $w.buttons.dismiss  -side left -expand 1

    catch {image delete xfimage}
    image create photo xfimage -file "$xf(xf_home)xflogo.gif"
    label $w.im -image xfimage -relief flat -bg $bg

    text $w.text.tx -bg $abg -fg $afg -height 14 -width 10 -font fixed


    $w.text.tx tag configure versioni -font *-times-bold-r-*-12-*\
	    -foreground "#ffafff" -justify center -spacing3 10
    $w.text.tx tag configure prog -font *-times-*-r-*-18-*\
	    -foreground "#efefa0" -underline 1
    $w.text.tx tag configure name -font -*-times-*-r-*-*-18-*-*-*-*-*-*-*\
	    -foreground "#dfdfff"
    $w.text.tx tag configure all -lmargin1 5 -spacing1 5


    $w.text.tx insert end "Version: $xf(A_VERSION) $xf(reg)\n" versioni

    $w.text.tx insert end "Programming & Copyrights: \n" prog
    $w.text.tx insert end "Juha Forsten \n" name
    $w.text.tx insert end "Mikko Kiviniemi \n" name
    $w.text.tx insert end "\n"
    $w.text.tx insert end "Email: $xf(mail)\n"
    $w.text.tx insert end "WWW  : http://java.inf.tu-dresden.de/X-Files/\n"
    #$w.text.tx insert end "WWW  : http://pinhead.tky.hut.fi/~xf_adm/\n"
    $w.text.tx insert end "WWW  : http://www.hut.fi/u/mkivinie/X-Files/\n"
    #$w.text.tx insert end "FTP  : ftp://java.inf.tu-dresden.de/pub/unix/X-Files/\n"
    $w.text.tx insert end "\n"

    $w.text.tx tag add all 2.0 5.0

    pack $w.im -side top -padx .5m -pady .5m
    pack $w.text -side top -pady 10 -fill x
    pack $w.text.tx -fill x
    $w.text.tx configure -state disabled
}

proc Confirm_exit {} {
    global xf TMP
    if {[AskWin "Exit X-Files ?!" -50 -50 {} {} {} Yes No] == 1} {
	if {[info exists xf(undopath)]} {
	    SaveUndo
	}
	History left
	History right
	if {[catch {set fh [open [file join $xf(user_home) xfiles.history] w]} err]} {
	    MessageBox "Unable to save directory history information:\n\n$err"
	} {
	    puts $fh $xf(history_0)
	    close $fh
	}
	file delete -force -- $TMP(dir)
	exit 0
    }
}
proc Xf_variable_dumb {} {
    global xf tk_patchLevel tcl_patchLevel ftp
    set tmp "TK-version: $tk_patchLevel"
    set tmp "$tmp\nTCL-version: $tcl_patchLevel\n"
    set tmp "$tmp\nX-Files variables & values:\n---------------------------\n\n"
    foreach idx [lsort [array names xf]] {
	# do not display ftp username or passwd
	if {[string compare ftp.user $idx] != 0 && [string compare ftp.pass $idx] != 0} {
	    set tmp  "$tmp xf($idx): $xf($idx)\n"
	}
    }
    OutputWindow $tmp
    #parray ftp
}

proc HelpInfo { x y hwidget } {
    global helppop xf
    if {[info exists xf(Help$hwidget)] == 1} {
	if {[info exists xf(Help$hwidget)] == 1} {
	    catch {destroy $helppop}
	    set helppop [menu .help -bg "#303080" \
		    -tearoff 0 -disabledforeground "#f0f0b0" -relief ridge]
	    $helppop  add command -state disabled \
		    -font *Helvetica*-12-* \
		    -label [lindex $xf(Help$hwidget) 0]
	    set temp [lreplace $xf(Help$hwidget) 0 0 ]
	    $helppop add separator
	    foreach line $temp {
		$helppop  add command -state disabled \
			-label $line
	    }
	    tk_popup $helppop \
		    [expr {[winfo rootx $hwidget] + 10}]\
		    [expr {[winfo rooty $hwidget] + 10}]
	}
    }
}

proc HelpInfo_Conf {bfpath comm i framenumber} {

    catch {destroy .ahpop} err
    regsub " exec" $comm "" resp
    regsub "%s" $resp "" resp
    set rops ""
    set ops [lindex $resp 0]
    set resp [lreplace $resp 0 0]
    set actionhelp [menu .ahpop -bg "#cccccc" \
	    -tearoff 0 -disabledforeground "#000000" -relief ridge]
    $actionhelp add command -state disabled -label \
	    "ActionButton - Configuration:" \
	    -font *Helvetica*-12-*
    $actionhelp add separator
    $actionhelp add command -state disabled -font fixed -label \
	    [format "%-8s %s" "Command:" $resp]
    if {[regexp N $ops]} {
	set rops "<NONE>"
    }
    if {[regexp C $ops]} {
	set rops "${rops}Confirm "
    }
    if {[regexp D $ops]} {
	set rops "${rops}Dialog "
    }
    if {[regexp W $ops]} {
	set rops "${rops}OutputWin "
    }
    if {[regexp U $ops]} {
	set rops "${rops}Update "
    }
    if {[regexp Q $ops]} {
	set rops "${rops}Quiet "
    }
    $actionhelp add command -state disabled -font fixed \
	    -label [format "%-8s %s" "Options:" $rops]
    set ahwidget $bfpath.bf($framenumber).f([expr {$i-$framenumber*6}]).b([expr {$i-$framenumber*6}])
    tk_popup $actionhelp [expr {[winfo rootx $ahwidget] + 10}]\
	    [expr {[winfo rooty $ahwidget] + 10}]
}

proc GetHelp {file} {
    global xf
    set manual [open $file r]
    OutputWindow [read $manual]
    close $manual
}
proc OutputWindow { txt {dir ""} {file ""}} {
    global xf xf_image env tk_version
    if {![string compare $dir ""]} {
	set dir "$env(HOME)/"
    }
    incr xf(outwin_num)
    set n $xf(outwin_num)
    set xf(outwin_changed$n) 0
    set w .$xf(outwin_num)
    set  xf(outwin_tagcol$n) "Yellow"
    catch {destroy $w}
    toplevel $w
    wm title $w "X-Files <Output Window: \#$xf(outwin_num)>"
    wm iconname $w "XF-OutWin"
    wm protocol $w WM_DELETE_WINDOW [list OW_Close $w $n $dir $file]

    frame $w.buttons -relief sunken  -bd 2
    pack  $w.buttons -side bottom -fill x -pady 2
    button $w.buttons.close -text Close -command [list OW_Close $w $n $dir $file]
    button $w.buttons.save -text "SaveToFile" \
	    -command "SaveToFileProc $xf(outwin_num) $dir [list $file]"
    pack $w.buttons.save -side left -fill x -padx 10
    if {[set tk_version] > 4.0} {
	button $w.buttons.mail -text Mail -command "OW_Mail $xf(outwin_num)"
	pack $w.buttons.mail -side left -fill x -padx 3
    }

    pack $w.buttons.close -side right -fill x -padx 10

    frame $w.tx
    text $w.tx.text -relief sunken -bd 2 -yscrollcommand "$w.tx.sc.scroll set"\
	    -setgrid 1 -height 30
    frame $w.tx.sc
    scrollbar $w.tx.sc.scroll -command "$w.tx.text yview"
    button $w.tx.sc.t -image $xf_image(topimage) -padx 0 -pady 0\
	    -command "$w.tx.text yview 0" -bd 1
    button $w.tx.sc.b -image $xf_image(bottomimage) -padx 0 -pady 0\
	    -command "$w.tx.text yview end" -bd 1
    pack $w.tx.sc.t -side top
    pack $w.tx.sc.b -side bottom
    pack $w.tx.sc.scroll -side top -fill y -expand 1
    pack $w.tx.sc -side right -fill y -fill y
    pack $w.tx.text -expand yes -fill both -side left

    $w.tx.text insert 0.0 $txt

    $w.tx.text tag configure "Yellow$n" -relief raised -borderwidth 1\
	    -background "#ffffaf"

    $w.tx.text tag configure "Red$n" -relief raised -borderwidth 1\
	    -background "#ffbfbf"

    $w.tx.text tag configure "Green$n" -relief raised -borderwidth 1\
	    -background "#bfffbf"

    $w.tx.text tag configure "Blue$n" -relief raised -borderwidth 1\
	    -background "#dfdfff"

    frame $w.entry -relief groove -bd 3
    checkbutton $w.entry.mod -variable xf(outwin_changed$n) -bd 1\
	    -state disabled
    label $w.entry.lab -text "Search string:"
    label $w.entry.co -fg #992222 -text ""
    entry $w.entry.e -textvariable xf(outwin_search$n) -width 14

    button $w.entry.search -text "Search" -bd 1\
	    -command "SearchProc2 $w $n" -pady 1

    button $w.entry.searchall -text "SearchAll" -bd 1\
	    -command "SearchProc $w $n" -pady 1

    button $w.entry.ct -text "Clear" -bd 1 -command "SearchClear $w $n" -pady 1

    menubutton $w.entry.tc -textvariable xf(outwin_tagcol$n)\
	    -menu $w.entry.tc.menu -relief raised -bd 1 -bg "#ffffaf"\
	    -pady 1 -activebackground #ffffdf -indicatoron true
    set m [menu $w.entry.tc.menu -tearoff 1]
    $m add radio -label "Yellow" -variable xf(outwin_tagcol$n) -command\
	    "$w.entry.tc config -bg #ffffaf -activebackground #ffffdf"\
	    -activebackground "#ffffbf"
    $m add radio -label "Red" -variable xf(outwin_tagcol$n) -command\
	    "$w.entry.tc config -bg #ffbfbf -activebackground #ffdfdf"\
	    -activebackground "#ffcfcf"
    $m add radio -label "Green" -variable xf(outwin_tagcol$n) -command\
	    "$w.entry.tc config -bg #bfffbf -activebackground #dfffdf"\
	    -activebackground "#cfffcf"
    $m add radio -label "Blue" -variable xf(outwin_tagcol$n) -command\
	    "$w.entry.tc config -bg #dfdfff -activebackground #efefff"\
	    -activebackground "#cfcfff"
    pack $w.entry.mod -side left -padx 1 -pady 1
    pack $w.entry.lab -side left -padx 10
    pack $w.entry.e -side left -padx 0
    pack $w.entry.search -side left -fill x -padx 3\
	    -pady 0
    pack $w.entry.searchall -side left -fill x -padx 3\
	    -pady 0
    pack $w.entry.co -side left
    pack $w.entry.ct -side right -fill x -padx 10 -pady 0
    pack $w.entry.tc -side right -fill x -padx 0 -pady 0

    pack $w.entry -fill both -side bottom
    pack $w.tx -side bottom -fill both -expand true

    bind $w.entry.e <Return> "SearchProc2 $w $n"
    bind $w <Control-x> { }
    bind $w <Control-x><Control-s> \
	    "SaveToFileProc $xf(outwin_num) $dir [list $file]"
    bind $w <Control-x><Control-c> \
	    [list OW_Close $w $n $dir $file]
    bind $w <Control-s> "SearchProc2 $w $n"
    bind $w <Up> {catch {FixFocus %W};break}
    bind $w <Down> {catch {FixFocus %W};break}
    bind $w <Next> {catch {FixFocus %W};break}
    bind $w <Prior> {catch {FixFocus %W};break}
    bind $w.tx.text <Key> [list OW_ChkKey $n %K %s]

    proc OW_ChkKey {n K s} {
	global xf
	if {($s == "4") && (($K == "x") || ($K == "s") || ($K == "c"))} {
	    return
	}
	if {!([string match $K Up] || \
		[string match $K Down] || \
		[string match $K Left] || \
		[string match $K Right] || \
		[string match $K Next] || \
		[string match $K Prior] || \
		[string match $K Home] || \
		[string match $K End] || \
		[string match {Shift_*} $K] || \
		[string match {Alt_*} $K] || \
		[string match {Control_*} $K] || \
		[string match $K Caps_Lock] || \
		[string match $K Mode_switch] || \
		[string match $K Escape] || \
		[string match $K Num_Lock])} {
	    set xf(outwin_changed$n) 1
	}
    }

    proc OW_Close {w num d {f ""}} {
	global xf
	if {$xf(outwin_changed$num)} {
	    set ret [AskWin "You have made changes! Close the editor without saving?" -100 -100 "Save"]
	    switch $ret {
		0 {return}
		2 {SaveToFileProc $num $d $f}
		default {}
	    }
	}
	destroy $w
	unset xf(outwin_search$num)
	unset xf(outwin_changed$num)
	unset xf(outwin_tagcol$num)
	if {[winfo exists .fs]} {
	    if {![string compare "FileSelector#$num" [wm title .fs]]} {
		destroy .fs
	    }
	}

    }

    proc OW_Mail {num} {
	global env smtp prompt xf
	set mtxt [.$num.tx.text get 0.0 end-1c]
	catch {unset prompt}
	set prompt(1.label) "Receiver:"
	set prompt(2.label) "Subject:"

	while 1 {
	    if {[DialogWin "Sender: $xf(user_email)\n" -80 -190] == 0} {
		catch {unset prompt}
		return
	    }
	    if {[string compare $prompt(1.result) ""]} {
		break
	    }
	}

	if {[catch {SMTP_SendMail $xf(user_email) $prompt(1.result)\
		$prompt(2.result) $mtxt} err]} {
	    MessageBox "PROBLEM: [lindex [split $err "\n"] 0]\n\nFIX: Try to set proper hostname to resource 'mailserver' !"
	} {
	    if {[info exists smtp(failure)]} {
		MessageBox "MAIL NOT SENT!! (message from server: $smtp(failure))"
	    }
	}
	catch {unset prompt}
    }

    proc FixFocus { w } {

	regexp {^.*([0-9])} $w b
	catch {focus $b.tx.text}
    }

    proc SaveToFileProc {num dir {f ""}} {
	global xf
	if {[winfo exists .fs]} {
	    MessageBox "Cannot open more than one FileSelector !"
	    return
	}
	global xf
	set fname [FS $num $dir save $f $xf(do_backup)]
	if {$fname == ""} {
	    return 0
	}
	if {![winfo exists .$num]} {
	    MessageBox "Can't save the file! Output Window\#$num don't exists any\
		    more !"
	    return -1
	} {
	    set stxt [.$num.tx.text get 0.0 end-1c]
	    set sfileid [open $fname w 0600]
	    puts $sfileid $stxt
	    close $sfileid
	    set xf(outwin_changed$num) 0
	    UpdateListbox "right"
	    UpdateListbox "left"
	}
    }

    proc SearchProc {w n} {
	global xf
	$w.entry.co config -text ""
	set i [string length $xf(outwin_search$n)]
	set tagcol $xf(outwin_tagcol$n)
	if {$xf(outwin_search$n) != ""} {
	    SetWaitPointer $w
	    SetWaitPointer $w.entry.e
	    set pos 1.0
	    set i 0
	    while 1 {
		set pos [$w.tx.text search -count length $xf(outwin_search$n) $pos end]
		if {$pos == ""} {
		    if {$i == 0} {
			SetArrowPointer $w
			$w.entry.e config -cursor xterm
			MessageBox "String not found!"
			return
		    }
		    break
		}
		$w.tx.text tag add "$tagcol$n" $pos "$pos + $length char"
		set pos [$w.tx.text index "$pos + $length char"]
		incr i
	    }
	    SetArrowPointer $w
	    $w.entry.e config -cursor xterm
	    $w.entry.co config -text "Found: $i"
	}
    }




    proc SearchProc2 {w n} {
	global xf
	$w.entry.co config -text ""
	set i [string length $xf(outwin_search$n)]
	set tagcol $xf(outwin_tagcol$n)
	if {$xf(outwin_search$n) != ""} {
	    SetWaitPointer $w
	    SetWaitPointer $w.entry.e
	    set pos [$w.tx.text search $xf(outwin_search$n) insert]

	    if {$pos != ""} {
		$w.tx.text mark set nemo $pos
		$w.tx.text see $pos
		tkTextSetCursor $w.tx.text "nemo + $i chars"
		$w.tx.text tag add  "$tagcol$n"  "insert - $i chars"\
			"nemo + $i chars"
		$w.tx.text mark unset nemo
		raise $w
		SetArrowPointer $w
		$w.entry.e config -cursor xterm
	    } {
		SetArrowPointer $w
		$w.entry.e config -cursor xterm
		MessageBox "String not found!"
	    }
	}
    }

    proc SearchClear {w n} {
	global xf
	$w.tx.text tag remove $xf(outwin_tagcol$n)$n 1.0 end
    }

    tkTextSetCursor $w.tx.text 0.0
    focus $w.buttons.close

}
proc bgerror {err} {
    tkerror $err
}
proc tkerror {err {s {}}} {
    global xf errorCode errorInfo xf_image

    if {[string match "*tk_menuSetFocus*" $errorInfo]} {
	return
    }
    DEBUG "$err :: $errorInfo"

    set xf(errorInfo) $errorInfo
    set xf(errorCode) $errorCode

    SetArrowPointer
    bell
    set mail 1
    set more 1
    # TODO onko hyvä?
    if {[string match {*BACKGROUND*} $err]} {
	# async error
	set mail 0
	set more 0
    } elseif {[string match {*ermission denied*} $err]} {
	set err "Could not complete operation, permission denied!"
	set mail 0
    }
    if {[string match {*ENOENT*} $errorCode]} {
	set mail 0
    }
    if {[string compare {} $s] == 0} {
	LogBoth $err 1
    } {
	after idle [list Log $s $err 1]
    }
    if {[string match {*left*} [focus]]} {
	set s "left"
    } {
	set s "right"
    }

    $xf(pathEnt_$s) xview moveto 1
    $xf(pathEnt_$s) icursor end
    DefaultInfo $s
    set e [toplevel .er]
    if {[option get .xfiles messages_always_on_top {}] == 1} {
	bind $e <Visibility> [list KeepOnTop $e %W %s]
    }
    set error(ok) 0
    frame $e.up -relief sunken -bd 2
    wm geometry $e +[expr {[winfo pointerx .] - 50}]+[expr {[winfo pointery .] - 50}]
    wm title $e "X-Files Error"
    wm protocol $e WM_DELETE_WINDOW {set error(ok) 1}

    message $e.up.msg -text $err -aspect 400
    label $e.up.img -image $xf_image(errorimage)

    frame $e.buttons -relief raised -bd 0
    frame $e.buttons.dum -relief sunken -bd 1
    button $e.buttons.dum.ok -text OK! -command {set error(ok) 1}
    button $e.buttons.mail -text "Mail..." -command {if {[ERR_Mail]} {.er.buttons.mail flash}}
    button $e.buttons.more -text "More..." -command {
	OutputWindow $xf(errorInfo)
    }
    button $e.buttons.save -text Save -command {ERR_Save; .er.buttons.save flash}

    pack $e.up.img -side left -padx 15 -pady 20
    pack $e.up.msg -side right -fill both -expand 1
    pack $e.up -side top -fill both -expand 1 -padx 4

    pack $e.buttons.dum -side left -padx 10 -pady 5
    pack $e.buttons.dum.ok -padx 4 -pady 4
    pack $e.buttons.save $e.buttons.mail $e.buttons.more -side right
    pack $e.buttons -side bottom -fill x

    if {!$mail} {
	$e.buttons.mail config -state disabled
    }
    if {!$more} {
	$e.buttons.more config -state disabled
    }
    focus $e.buttons.dum.ok
    tkwait visibility $e
    KeepInScreen $e
    #grab $e
    tkwait variable error(ok)
    #grab release $e
    catch {destroy .er}
}

proc ERR_Msg {{m ""}} {
    global xf be ee env tk_patchLevel tcl_patchLevel

    set m "$m\n*****************************************************"
    catch {set m  "$m\nDATE: [clock format [clock seconds] -format %c]"}
    set m "$m\n*****************************************************"

    set m "$m\n\nTK_ERRORMSG:"
    set m "$m\n-------------------\n"
    set m "$m\n[set xf(errorCode)]\n"
    set m "$m\n[set xf(errorInfo)]"

    set m "$m\nENV_VARS:"
    set m "$m\n-------------------\n"

    foreach idx [list USER USERNAME HOSTNAME TERM HOSTTYPE PATH HOME SHELL OSTYPE XF_HOME] {
	if {[info exists env($idx)]} {
	    set m "$m\n$idx:  $env($idx)"
	}
    }

    set m "$m\n\nXF_VARS:"
    set m "$m\n-------------------\n"
    set m "$m\ntk_version:  $tk_patchLevel"
    set m "$m\ntcl_version:  $tcl_patchLevel"
    foreach idx [lsort [array names xf]] {
	if {[string compare ftp.user $idx] != 0 && [string compare ftp.pass $idx] != 0} {
	    set m  "$m\n$idx:  $xf($idx)"
	}
    }
    set m "$m\n"

    set m "$m\n\nBE_VARS:"
    set m "$m\n-------------------\n"
    foreach idx [lsort [array names be]] {
	set m  "$m\n$idx:  $be($idx)"
    }
    set m "$m\n"

    set m "$m\n\nEE_VARS:"
    set m "$m\n-------------------\n"
    foreach idx [lsort [array names ee]] {
	set m  "$m\n$idx:  $ee($idx)"
    }
    set m "$m\n"

    return $m
}

proc ERR_Mail {} {
    global xf ret subject

    set subject "X-Files errorCode: $xf(errorCode)"
    set top [toplevel .mail -borderwidth 5]
    wm title $top "X-Files Error Mail"
    wm resizable $top 0 0
    wm geometry $top +[expr {[winfo pointerx .] - 50}]+[expr {[winfo pointery .] - 500}]
    wm protocol $top WM_DELETE_WINDOW {set ret 0}

    set war {}
    if {$xf(fsmode_left) == 4 || $xf(fsmode_right) == 4} {
	set war "\n\nIf this error is FTP related, your username and password are NOT sent!"
    }

    message $top.info -aspect 500 -text "When you click 'Send', this error will be sent to the X-Files Administrators. The error-mail will include all X-Files internal variables and some system variables. If you could write a brief description of what led to this error, it would help our job of hunting down the bug... Thank you!$war"
    pack $top.info -expand 1

    set f [frame $top.top -relief ridge -bd 3]
    frame $f.1
    label $f.1.l -text "Mail to:" -width 8
    entry $f.1.e -textvariable xf(mail) -state disabled -relief flat
    pack $f.1.l -side left
    pack $f.1.e -side left -fill x -expand 1
    pack $f.1 -fill x -expand 1
    frame $f.2
    label $f.2.l -text "Subject:" -width 8
    entry $f.2.e -textvariable subject -state disabled -relief flat
    pack $f.2.l -side left
    pack $f.2.e -side left -fill x -expand 1
    pack $f.2 -fill x -expand 1
    pack $f -fill both -expand 1

    set f [frame $top.bottom -relief groove -bd 3]
    frame $f.h
    label $f.h.l -text "Additional info:"
    pack $f.h.l -side left
    pack $f.h -fill x
    set t [text $f.t -height 10 -width 40 -wrap word]
    pack $t -fill both -expand 1
    pack $f -fill both -expand 1

    set f [frame $top.buttons -relief ridge -bd 3]
    button $f.send -text "Send" -width 6 -command {set ret 1}
    button $f.cancel -text "Cancel" -width 6 -command {set ret 0}
    pack $f.send -side left -padx 10 -pady 10
    pack $f.cancel -side right -padx 10 -pady 10
    pack $f -fill both -expand 1

    focus $t
    tkwait visibility $top
    KeepInScreen $top
    grab $top
    tkwait variable ret
    grab release $top
    if {$ret == 0} {
	catch {destroy $top}
	return 0
    }
    set addinfo [$t get 0.0 end]
    set stream [open "|mail $xf(mail)" w]
    puts $stream [ERR_Msg "Subject: $subject\n\nBUG-MAIL:\n\n$addinfo\n"]
    close $stream
    catch {destroy $top}
    return 1
}

proc ERR_Save {} {
    global xf
    MakeSaveDir
    set fileid [open $xf(user_home)ErrorLog {WRONLY APPEND CREAT}]
    puts $fileid [ERR_Msg "BUG-SAVE:"]
    close $fileid
}


proc SMTP_ReadSocket {sock} {
    global smtp
    set l [gets $sock]
    if { [string index $l 0] == "5"} {
	set smtp(ok) -1
	set smtp(failure) $l
	return
    } {
	set smtp(ok) 0
	return
    }
}

proc SMTP_SendMail {from to subject data {host 127.0.0.1} {port 25}} {

    global smtp ok
    set s [socket $host $port]
    fileevent $s readable [list SMTP_ReadSocket $s]
    fconfigure $s -buffering line

    vwait smtp(ok)
    if {$smtp(ok) == -1} {
	return -1
    }
    set header "MAIL FROM: <$from>\nRCPT TO: <$to>\nDATA"
    set end ".\nQUIT"
    foreach line [split $header "\n"] {
	puts $s $line
	flush $s
	vwait smtp(ok)
	if {$smtp(ok) == -1} {
	    return -1
	}
    }
    puts $s "Subject: $subject"
    foreach line [split $data "\n"] {
	puts $s $line
    }
    foreach line [split $end "\n"] {
	puts $s $line
	flush $s
	vwait smtp(ok)
	if {$smtp(ok) == -1} {
	    return -1
	}
    }
    fileevent $s readable {}
    fileevent $s writable {}
    close $s
    unset smtp
}

###########################################################################
# XF_PopMenu v1.0 (c) Juha Forsten (7/Jan/98)
# =========================================================================
# 
# It pops up a 'scroll-menu' with 'auto-scan' (run the test get the idea!)
# 
# Usage: XF_PopMenu <toplevel-name> <itemlist> <min-width> <max-height> 
#                    <x-position> <y-position> {<scroll-bar-enable>} 
#
# * Width and height in characters
# * HotKeys: Up, Down, PageUp, PageDown, Home, End, Esc, Return
# 
############################################################################

proc XF_PopMenu { pop_name lst pop_x_size pop_y_size pop_x_pos pop_y_pos {bar 0}} {

    global pm
#    set pm(x_size) $pop_x_size
#    set pm(y_size) $pop_y_size
#    set pm(x_pos) $pop_x_pos
#    set pm(y_pos) $pop_y_pos
    set pm(name) $pop_name
    set pm(lst) $lst
    set pm(focus) 0
    
    ## JFo
    set prev_focus [focus]

    catch {destroy $pop_name}
    toplevel $pop_name
    wm withdraw $pop_name
    wm overrideredirect $pop_name 1

    frame $pop_name.f -relief raised -bd 3
    listbox $pop_name.f.lb -width 15 -height 20 -relief raised -bd 0 \
		-font -*-fixed-bold-r-*-*-12-*-*-*-*-*-*-* -cursor arrow \
		-exportselection 0 -selectbackground "#ffffff" \
		-selectforeground "#000000" -selectborderwidth 1\
		-highlightthickness 0

    # Use scrollbar, if requested...
    #################################
    if {$bar} {
	scrollbar $pop_name.f.sc -command "$pop_name.f.lb yview" -width 10 -bd 1
	$pop_name.f.lb configure  -yscrollcommand "$pop_name.f.sc set"
	pack $pop_name.f.sc -side left -fill y
	bind $pop_name.f.sc <Enter> {
	    global tkPriv
	    after cancel $tkPriv(afterId)
	}
    }
    
    # Inser list to listbox & calculate LB-max-width
    ############################################
    foreach i $lst {
	set l [string length $i]
	if {$l > $pop_x_size} {
	    set pop_x_size $l
	}
	$pop_name.f.lb insert end $i
    }
    
    # Calculate LB-max-height
    #########################
    set h [llength $lst]
    if {$h < $pop_y_size} {
	set pop_y_size $h
    }
    
    $pop_name.f.lb configure -width [expr {$pop_x_size + 1}] -height $pop_y_size
    wm geometry $pop_name +${pop_x_pos}+${pop_y_pos}

    pack $pop_name.f.lb -side right
    pack $pop_name.f

    # toplevel bindings
    ###################
    bind $pop_name <Enter>  "set pm(focus) 1 ; focus $pop_name.f.lb"
    bind $pop_name <Leave>  "set pm(focus) 0"
    bind $pop_name <Return> "set pm(focus) 1 ; pwGetSelected %W"
    bind $pop_name <Escape> "set pm(focus) 0 ; pwGetSelected %W"
    bind $pop_name <Button-2> {break}
    bind $pop_name <Button-3> {break}
    bind $pop_name <Visibility> "raise $pop_name"

    # frame bindings
    ###################
    bind $pop_name.f <Leave> {
	set tkPriv(x) 0
	set tkPriv(y) %y
	pwAutoScan %W.lb 
    }
    
    ## JFo
    bind $pop_name.f <Button-1> {}
    bind $pop_name.f <Key> "focus $pop_name.f.lb"
    bind $pop_name.f <ButtonRelease-1> {pwGetSelected %W.lb}

    # listbox bindings
    ###################

    bind $pop_name.f.lb <Motion> {
	## JFo
	## FIX for unknown error :-/
	set tkPriv(relief) flat
	set tkPriv(x) %x
	set tkPriv(y) %y
	pwMotion %W [%W index @%x,%y]
    }
    bind $pop_name.f.lb <Enter> {
	%W select clear 0 end
	%W select set [%W nearest %y]
    }
    bind $pop_name.f.lb <Button-3> {}
    ## JFo
    bind $pop_name.f.lb <ButtonRelease-1> {pwGetSelected %W}
    bind $pop_name.f.lb <Button-1> {pwGetSelected %W}
    bind $pop_name.f.lb <Key> {
	after cancel $tkPriv(afterId)
    }
    bind $pop_name.f.lb <Prior> {
	%W yview scroll -1 pages
	%W activate @0,0
	%W select clear 0 end
	%W select set active
	break
    }
    bind $pop_name.f.lb <Next> {
	%W yview scroll 1 pages
	%W activate @0,0
	%W select clear 0 end
	%W select set active
	break
    }
    bind $pop_name.f.lb <Home> {
	%W yview 0
	%W activate 0
	%W select clear 0 end
	%W select set 0
	break
    }
    bind $pop_name.f.lb <End> {
	%W yview end
	%W activate end
	%W select clear 0 end
	%W select set end
	break
    }

    wm deiconify $pop_name
    raise $pop_name
    tkwait visibility $pop_name.f.lb
    grab $pop_name.f
    raise $pop_name
    vwait pm(selected)
    grab release $pop_name
    catch {destroy $pop_name}
    ## JFo
    focus -force $prev_focus
    return $pm(selected)
}

proc pwGetSelected {w} {
    global pm

    # JFo - Return without any action, if Button-Release in path-entry
    if {[string match .ff.* [focus]]} {return}
    if {!$pm(focus)} {
	set pm(selected) ""
    } {
	if {[catch {set pm(selected) [$w get [$w curselection]]}]} {
	    set pm(selected) ""
	}
    }
}

proc pwAutoScan {w} {
    global tkPriv
    if {![winfo exists $w]} return
    set x $tkPriv(x)
    set y $tkPriv(y)
    if {$y >= [winfo height $w]} {
	$w yview scroll 1 units
    } elseif {$y < 0} {
	$w yview scroll -1 units
    } elseif {$x >= [winfo width $w]} {
	$w xview scroll 2 units
    } elseif {$x < 0} {
	$w xview scroll -2 units
    } else {
	return
    }
    pwMotion $w [$w index @$x,$y]
    set tkPriv(afterId) [after 20 pwAutoScan $w]
}
proc pwMotion {w el} {
    global tkPriv
    if {$el == $tkPriv(listboxPrev)} {
	return
    }
    set anchor [$w index anchor]
    $w activate $el
    $w selection clear 0 end
    $w selection set $el
    set tkPriv(listboxPrev) $el
}

set vdleft {}
set vdright {}
set vfleft {}
set vfright {}
set stop_calc 0
lappend auto_path $xf(xf_home)

MAIN $argc $argv
