#!/bin/sh
# the next line restarts using wish \
exec wish "$0" "$@"
#########################################################
# Easy IPCHAINS/IPFWADM Visual interface
#
# Daniel Roche, <daniel.roche@bigfoot.com>
# Ladislas HAJNAL pour l'adaptation  ipchains <hajnal@enac.fr>
#########################################################

if { $tk_version < 8.0 } {
    puts "easyfw need tcl/tk version 8.0 mininum , aborting !"
    exit
}

#########################################################
#
# general look options
#
#########################################################

option add *highlightThickness 0
option add *font -*-helvetica-medium-r-*-*-14-*-*-*-*-*-iso8859-1
option add *wrapLength 600

set Look(gencolor) gray60
set Look(entrycolor) gray70
set Look(titlecolor) navy
set Look(selectbgcol) gray40
set Look(selectfgcol) white
set Look(titlecolor) navy
set Look(titlefn1) 10x20
set Look(titlefn2) 9x15bold
set Look(titlefn3) 12x24
set Look(titlefn4) 6x10
set Look(fixfont) 8x13

tk_setPalette $Look(gencolor)

#########################################################
#
# global variable
#
#########################################################

set easyfwlib [ file join / usr local lib easyfw ]
if ![ file isdirectory $easyfwlib ] {
 set easyfwlib [ file join / opt easyfw ]
 if ![ file isdirectory $easyfwlib ] {
  set easyfwlib [ pwd ]
  if ![ file isdirectory $easyfwlib/predefs ] {
   puts "cannot find application directory !"
   exit 1
  }
 }
}

variable Mode

set mypid [pid]
set Extern(applyfile) "/tmp/efw$mypid.sh"
set Extern(applyboot1) "/etc/rc.d/init.d/easyfw"
set Extern(applyboot2) {/etc/rc.d/rc$rlvl.d/S95easyfw}
set Extern(ipchains) "/sbin/ipchains"
set Extern(ipfwadm) "/sbin/ipfwadm"
set Extern(ifconfig) "/sbin/ifconfig"
set Extern(insmod) "/sbin/insmod"
set Extern(rmmod) "/sbin/rmmod"
set Extern(runlevel) "/sbin/runlevel"
set Extern(easyrc) "~/.easyfwrc"
set Extern(mmodpath) "/lib/modules/$tcl_platform(osVersion)/ipv4/ip_masq_*"

set Status(systemok) 0
set Status(aboutflg) 0
set Status(getnetadrflg) 0
set Status(dispnetdev) 0
set Status(rulepropflg) 0
set Status(portlistflg) 0
set Status(decodepredefflg) 0
set Status(debfin) {}
set Status(tmplng) "GB"
set Status(setlngflg) 0
set Status(setmskmflg) 0
set Status(applyflg) 0
set Status(applynow) 0
set Status(applyfile) 0
set Status(applyboot) 0

variable tabport

set batpolicy(accept)     0
set batpolicy(ACCEPT)     0
set batpolicy(deny)       1
set batpolicy(DENY)       1
set batpolicy(reject)     2
set batpolicy(REJECT)     2
set batpolicy(masquerade) 3
set batpolicy(accept/masquerade) 3
set batpolicy(MASQ)       3

set batprotocol(tcp)  1
set batprotocol(udp)  2
set batprotocol(icmp) 3

set optsyntax(pol,0,ipfwadm)      "accept"
set optsyntax(pol,1,ipfwadm)      "deny"
set optsyntax(pol,2,ipfwadm)      "reject"
set optsyntax(pol,3,ipfwadm)      "masquerade"
set optsyntax(dst,ipfwadm)        "-D"
set optsyntax(prot,ipfwadm)       "-P"
set optsyntax(src,ipfwadm)        "-S"
set optsyntax(dst,ipfwadm)        "-D"
set optsyntax(prot,ipfwadm)       "-P"
set optsyntax(flushin,ipfwadm)    "-I -f"
set optsyntax(flushout,ipfwadm)   "-O -f"
set optsyntax(flushfw,ipfwadm)    "-F -f"
set optsyntax(defpolin,ipfwadm)   "-I -p"
set optsyntax(defpolout,ipfwadm)  "-O -p"
set optsyntax(defpolfw,ipfwadm)   "-F -p"
set optsyntax(addin,ipfwadm)      "-I -a"
set optsyntax(addout,ipfwadm)     "-O -a"
set optsyntax(addfw,ipfwadm)      "-F -a"
set optsyntax(syn,ipfwadm)        "-y"

set optsyntax(pol,0,ipchains)     "ACCEPT"
set optsyntax(pol,1,ipchains)     "DENY"
set optsyntax(pol,2,ipchains)     "REJECT"
set optsyntax(pol,3,ipchains)     "MASQ"
set optsyntax(src,ipchains)       "-s"
set optsyntax(dst,ipchains)       "-d"
set optsyntax(prot,ipchains)      "-p"
set optsyntax(flushin,ipchains)   "-F input"
set optsyntax(flushout,ipchains)  "-F output"
set optsyntax(flushfw,ipchains)   "-F forward"
set optsyntax(defpolin,ipchains)  "-P input"
set optsyntax(defpolout,ipchains) "-P output"
set optsyntax(defpolfw,ipchains)  "-P forward"
set optsyntax(addin,ipchains)     "-A input -j"
set optsyntax(addout,ipchains)    "-A output -j"
set optsyntax(addfw,ipchains)     "-A forward -j"
set optsyntax(syn,ipchains)       "-y"

set mskbits(255) 8
set mskbits(254) 7
set mskbits(252) 6
set mskbits(248) 5
set mskbits(240) 4
set mskbits(224) 3
set mskbits(192) 2
set mskbits(128) 1
set mskbits(0) 0

variable Messages

#########################################################
#
# other files
#
#########################################################

source [file join $easyfwlib balloon.tcl]

#########################################################
#
# messages
#
#########################################################

proc InitDefaultMessages {} {
    global Messages

    set Messages(titre)              "Easy FireWall"
    set Messages(info)               "Information"
    set Messages(apropos)            "About"
    set Messages(quitter)            "Quit"
    set Messages(config)             "Configuration"
    set Messages(setlng)             "Set language"
    set Messages(masqmod)            "Set Masquerade Modules"
    set Messages(automskmod)         "Use ipautofw (automatic masquerading of protocols)"
    set Messages(lnkio)              "Link Input and Output operations"
    set Messages(par)                "by"
    set Messages(outside)            "Outside"
    set Messages(inside)             "Inside"
    set Messages(ipnet)              "Ip Address :"
    set Messages(ipset)              "Set"
    set Messages(ruleI)              "Input Rules"
    set Messages(ruleO)              "Output Rules"
    set Messages(ruleF)              "Forwarding Rules"
    set Messages(predef)             "Predefined Configuration :"
    set Messages(precho)             "Choose"
    set Messages(reset)              "Reset"
    set Messages(cancel)             "Cancel"
    set Messages(apply)              "Apply"
    set Messages(rescan)             "Rescan"
    set Messages(defpol)             "Default policy :"
    set Messages(polacc)             "accept"
    set Messages(polden)             "deny"
    set Messages(polrej)             "reject"
    set Messages(polmsk)             "masquerade"
    set Messages(actadd)             "Add"
    set Messages(actdel)             "Delete"
    set Messages(actmod)             "Modify"
    set Messages(getnettitle)        "Network Address :"
    set Messages(netipadr)           "IP Address :"
    set Messages(netadr)             "address :"
    set Messages(netmsk)             "mask :"
    set Messages(ok)                 " OK "
    set Messages(cancel)             "Cancel"
    set Messages(error)              "Error"
    set Messages(warning)            "Warning"
    set Messages(badip)              "Bad IP Address"
    set Messages(ruleproptitle)      "Rule Parameters :"
    set Messages(rul1I)              "Input Rule :"
    set Messages(rul1O)              "Output Rule :"
    set Messages(rul1F)              "Forwarding Rule :"
    set Messages(where)              "Add :"
    set Messages(debut)              "at the beginning"
    set Messages(fin)                "at the end"
    set Messages(policy)             "policy :"
    set Messages(protocol)           "protocol :"
    set Messages(all)                "all"
    set Messages(sourcip)            "source :"
    set Messages(destip)             "destination :"
    set Messages(port)               "port :"
    set Messages(portlisttitle)      "IP Ports"
    set Messages(syntcp)             "Tcp connection request (SYN & ! ACK)"
    set Messages(toomuch)            "Too many (10) ports selected, excess discarded !"
    set Messages(onesel)             "Select 1 item and only one !"
    set Messages(ipfirst)            "You have to set inside and outside ip address first !"
    set Messages(pbapply1)           "Cannot open script for writing  !"
    set Messages(tcpudpprot)         "You have to specify UDP or TCP protocol when giving ports numbers !"
    set Messages(noprot)             "You have to specify a protocol when giving ports numbers !"
    set Messages(help)               "help"
    set Messages(manual)             "manual"
    set Messages(require)            "requirements"
    set Messages(todo)               "to do"
    set Messages(license)            "license"
    set Messages(chdev)              "choose an existing network device"
    set Messages(chman)              "or set network address manually"
    set Messages(lng)                "Language :"

    set Messages(applynow)           "Apply now"
    set Messages(applyfile)          "Save in a file :"
    set Messages(applyboot)          "Apply at boot time"
    set Messages(htitle)             "On line Help"
    
    set Messages(sysnook)            "Your system does not fit requirements !\n All system functions will be disabled !\n Have a look to the help for requirements !"

    set Messages(b_outip)            "Outside Firewall network address"
    set Messages(b_inip)             "Inside Firewall network address"
    set Messages(b_setoip)           "Set outside Firewall network address"
    set Messages(b_setiip)           "Set inside Firewall network address"
    set Messages(b_filpdf)           "Predefined configuration file"
    set Messages(b_setpdf)           "Choose predefined configuration file"
    set Messages(b_txtpdf)           "Predefined configuration description"
    set Messages(b_lstiru)           "Input rules"
    set Messages(b_lstoru)           "Output rules"
    set Messages(b_lstfru)           "Forwarding rule"
    set Messages(b_addiru)           "Add an input rule"
    set Messages(b_addoru)           "Add an output rule"
    set Messages(b_addfru)           "Add a forwarding rules"
    set Messages(b_deliru)           "Delete selected input rules"
    set Messages(b_deloru)           "Delete selected output rules"
    set Messages(b_delfru)           "Delete selected forwarding rules"
    set Messages(b_modiru)           "Modify selected input rule"
    set Messages(b_modoru)           "Modify selected output rule"
    set Messages(b_modfru)           "Modify selected forwarding rule"
    set Messages(b_poliru)           "Input rules default policy"
    set Messages(b_poloru)           "Output rules default policy"
    set Messages(b_polfru)           "Forwarding rule default policy"
    set Messages(b_bapply)           "Apply this configuration"
    set Messages(b_breset)           "Reset the configuration"
    set Messages(b_brescan)          "Rescan the actual configuration"

    set Messages(b2_pol)             "Select policy for this rule"
    set Messages(b2_prot)            "Select protocol for this rule"
    set Messages(b2_syn)             "Tcp connection request packet only"
    set Messages(b2_neg)             "Negation"
    set Messages(b2_sip)             "Source ip address"
    set Messages(b2_spt)             "Source ip port"
    set Messages(b2_dip)             "Destination ip address"
    set Messages(b2_dpt)             "Destination ip port"
}
    
proc ReadMessagesFile {} {
    global Config Messages easyfwlib

    if { ![ string compare $Config(lng) "GB" ]} { 
	InitDefaultMessages
    } else {
	set flng [file join $easyfwlib "message.$Config(lng)" ]
	if [ file isfile $flng] {
	    set fid [ open $flng r]
	    set len [gets $fid line]
	    while {! [eof $fid]} {
		if { $len != 0 } {
		    if {! [regexp "^\[#!\]" $line 0] } {
			set indx [string first ":" $line]
			if { $indx != -1 } {
			    set varname [ string range $line 0 [ expr $indx -1]]
			    set message [ string range $line [ expr $indx +1] end ]
			    set message [ string trimleft $message " " ]
			    if { $varname == "__font__" } {
				option add *font $message
			    } else {
				eval set Messages($varname) \"$message\"
			    }
			}
		    }
		}
		set len [gets $fid line]
	    }
	    close $fid
	} else {
	    InitDefaultMessages
	}
    }
} 

#########################################################
#
# pixmap creation
#
#########################################################
image create photo world -file [file join $easyfwlib world.gif]
image create photo fwall -file [file join $easyfwlib fwall.gif]
image create photo home -file [file join $easyfwlib home.gif]
image create photo moi -file [file join $easyfwlib dan.gif]
 
#########################################################
#
# widget creation
#
#########################################################
proc CreateWidgets {} {
    global Messages Look Status Config

    wm title . $Messages(titre)
    wm geometry . 750x500

    #
    # menus
    #

    menu .mbar -tearoff 0 -type menubar

    .mbar add cascade -menu .mbar.easyfw -label $Messages(titre) -foreground yellow
    menu .mbar.easyfw -tearoff 0
    .mbar.easyfw add command -label $Messages(apply) -command "Apply"
    .mbar.easyfw add command -label $Messages(reset) -command "ResetRules"
    .mbar.easyfw add command -label $Messages(rescan) -command "RescanRules"
    .mbar.easyfw add separator
    .mbar.easyfw add command -label $Messages(quitter) -command "Exit"

    .mbar add cascade -menu .mbar.config -label $Messages(config)
    menu .mbar.config -tearoff 0
    .mbar.config add command -label $Messages(setlng) -command "SetLng"
    .mbar.config add command -label $Messages(masqmod) -command "SetMasqMod"
    .mbar.config add separator
    .mbar.config add checkbutton -label $Messages(lnkio) -variable Config(linkio) \
	    -offvalue 0 -onvalue 1 

    .mbar add cascade -menu .mbar.help -label $Messages(help)
    menu .mbar.help -tearoff 0
    .mbar.help add command -label $Messages(apropos) -command "Apropos"
    .mbar.help add command -label $Messages(manual) \
	    -command [list Help $Messages(manual) manual]
    .mbar.help add command -label $Messages(require) \
	    -command [list Help $Messages(require) require]
    .mbar.help add command -label $Messages(todo) \
	    -command [list Help $Messages(todo) todo]
    .mbar.help add command -label $Messages(license) \
	    -command [list Help $Messages(license) gpl]

    . configure -menu .mbar

    #
    # banner & pictures
    #

    frame .banner -borderwidth 0 -height 84
    pack .banner -fill x -side top -anchor n
    frame .banner.banL -borderwidth 0
    label .banner.picfwl -image fwall -borderwidth 2 -relief raised -anchor n
    frame .banner.banR -borderwidth 0
    set sx [expr [image width fwall] + 4]
    set sy [expr [image height fwall] + 4]
    place .banner.picfwl -relx 0.5 -x [ expr - $sx / 2] -rely 0 -relheight 1
    place .banner.banL -relx 0 -relwidth 0.5 -width [ expr - $sx / 2] -rely 0 \
	    -relheight 1
    place .banner.banR -relx 0.5 -x [ expr + $sx / 2] -relwidth 0.5 \
	    -width [ expr - $sx / 2] -rely 0 -relheight 1

    frame .banner.banL.pic -relief raised -borderwidth 2
    frame .banner.banR.pic -relief raised -borderwidth 2
    frame .banner.banL.adr -relief raised -borderwidth 2
    frame .banner.banR.adr -relief raised -borderwidth 2
    pack .banner.banL.pic -side top -fill x 
    pack .banner.banR.pic -side top -fill x 
    pack .banner.banL.adr -side top -fill both -expand 1 
    pack .banner.banR.adr -side top -fill both -expand 1

    label .banner.banL.pic.picwrd -image world -borderwidth 0
    label .banner.banR.pic.pichom -image home -borderwidth 0
    label .banner.banL.pic.outside -text $Messages(outside) -borderwidth 0 \
	    -font $Look(titlefn1) -fg $Look(titlecolor)
    label .banner.banR.pic.inside -text $Messages(inside) -borderwidth 0 \
	    -font $Look(titlefn1) -fg $Look(titlecolor)
    pack .banner.banL.pic.picwrd -side left 
    pack .banner.banR.pic.pichom -side right
    pack .banner.banL.pic.outside -side left -padx 50
    pack .banner.banR.pic.inside -side right -padx 50

    #
    # outside network
    #

    label .banner.banL.adr.lip -text $Messages(ipnet)
    entry .banner.banL.adr.eip -background $Look(entrycolor)
    button .banner.banL.adr.bip -text $Messages(ipset) \
	    -command "SetNetworkAddr .banner.banL.adr.eip 1"
    set_balloon .banner.banL.adr.eip $Messages(b_outip)
    set_balloon .banner.banL.adr.bip $Messages(b_setoip)
    pack .banner.banL.adr.lip -side left -pady 2 -padx 4
    pack .banner.banL.adr.bip -side right -pady 2 -padx 4
    pack .banner.banL.adr.eip -side left -pady 2 -expand 1 -fill x -padx 4

    #
    # inside network
    #

    label .banner.banR.adr.lip -text $Messages(ipnet)
    entry .banner.banR.adr.eip -background $Look(entrycolor) 
    button .banner.banR.adr.bip -text $Messages(ipset) \
	    -command "SetNetworkAddr .banner.banR.adr.eip 1"
    set_balloon .banner.banR.adr.eip $Messages(b_inip)
    set_balloon .banner.banR.adr.bip $Messages(b_setiip)
    pack .banner.banR.adr.lip -side left -pady 2 -padx 4
    pack .banner.banR.adr.bip -side right -pady 2 -padx 4
    pack .banner.banR.adr.eip -side left -pady 2 -expand 1 -fill x -padx 4

    #
    # predefined configs
    #

    frame .predef -borderwidth 2 -relief raised -height 100
    pack .predef -side top -fill x 

    frame .predef.f1 -borderwidth 0
    label .predef.f1.title -text $Messages(predef) -font $Look(titlefn2) \
	    -fg $Look(titlecolor)
    entry .predef.f1.config  -background $Look(entrycolor)
    button .predef.f1.choose -text $Messages(precho) -command "ChoosePredef"
    set_balloon .predef.f1.config $Messages(b_filpdf)
    set_balloon .predef.f1.choose $Messages(b_setpdf)

    pack .predef.f1 -side top -fill x 
    pack .predef.f1.title -side left -pady 6 -padx 6
    pack .predef.f1.choose -side right -pady 6 -padx 6
    pack .predef.f1.config -side left -pady 6 -padx 6 -fill x -expand 1

    scrolled1text .predef.f2 -borderwidth 0 -height 60
    set_balloon .predef.f2.text $Messages(b_txtpdf)
    pack .predef.f2 -side top -fill both -expand 1

    #
    # input/output/forward frames
    #

    frame .rule0 -borderwidth 0
    pack .rule0 -side top -fill both -expand 1

    frame .rule0.ruleI -borderwidth 2 -relief raised
    frame .rule0.ruleO -borderwidth 2 -relief raised
    frame .rule0.ruleF -borderwidth 2 -relief raised

    place .rule0.ruleI -relx 0 -relwidth 0.33 -rely 0 -relheight 1
    place .rule0.ruleO -relx 0.33 -relwidth 0.33 -rely 0 -relheight 1
    place .rule0.ruleF -relx 0.66 -relwidth 0.34 -rely 0 -relheight 1

    #
    # input rules
    #

    label .rule0.ruleI.title -text $Messages(ruleI) -font $Look(titlefn2) \
	    -fg $Look(titlecolor)
    pack .rule0.ruleI.title -side top -fill x 
    frame .rule0.ruleI.fpol -borderwidth 0
    pack .rule0.ruleI.fpol -side top -fill x -pady 6
    label .rule0.ruleI.fpol.lpol -text $Messages(defpol)
    buttonedmenu .rule0.ruleI.fpol.mpol ChangePolicy2 \
	    [list $Messages(polacc) $Messages(polden) $Messages(polrej)]
    set_balloon .rule0.ruleI.fpol.mpol $Messages(b_poliru)
    pack .rule0.ruleI.fpol.lpol -side left
    pack .rule0.ruleI.fpol.mpol -side left -pady 0 -padx 10
    frame .rule0.ruleI.fact -borderwidth 0 -height 26
    pack .rule0.ruleI.fact -side top -fill x -pady 2
    button .rule0.ruleI.fact.add -text $Messages(actadd) \
	    -command "AddRule .rule0.ruleI.flst.list"
    set_balloon .rule0.ruleI.fact.add $Messages(b_addiru)
    button .rule0.ruleI.fact.del -text $Messages(actdel) \
	    -command "DelRule .rule0.ruleI.flst.list"
    set_balloon .rule0.ruleI.fact.del $Messages(b_deliru)
    button .rule0.ruleI.fact.mod -text $Messages(actmod) \
	    -command "ModRule .rule0.ruleI.flst.list"
    set_balloon .rule0.ruleI.fact.mod $Messages(b_modiru)
    place .rule0.ruleI.fact.add  -relx 0.01 -relwidth 0.34 -rely 0 -relheight 1
    place .rule0.ruleI.fact.del  -relx 0.35 -relwidth 0.32 -rely 0 -relheight 1
    place .rule0.ruleI.fact.mod  -relx 0.67 -relwidth 0.32 -rely 0 -relheight 1
    scrolled2listbox .rule0.ruleI.flst -borderwidth 0
    set_balloon .rule0.ruleI.flst.list $Messages(b_lstiru)
    pack .rule0.ruleI.flst -side top -fill both -expand 1

    #
    # output rules
    #

    label .rule0.ruleO.title -text $Messages(ruleO) -font $Look(titlefn2) \
	    -fg $Look(titlecolor)
    pack .rule0.ruleO.title -side top -fill x 
    frame .rule0.ruleO.fpol -borderwidth 0
    pack .rule0.ruleO.fpol -side top -fill x -pady 6
    label .rule0.ruleO.fpol.lpol -text $Messages(defpol)
    buttonedmenu .rule0.ruleO.fpol.mpol ChangePolicy2 \
	    [list $Messages(polacc) $Messages(polden) $Messages(polrej)]
    set_balloon .rule0.ruleO.fpol.mpol $Messages(b_poloru)
    pack .rule0.ruleO.fpol.lpol -side left
    pack .rule0.ruleO.fpol.mpol -side left -pady 0 -padx 10
    frame .rule0.ruleO.fact -borderwidth 0 -height 26
    pack .rule0.ruleO.fact -side top -fill x -pady 2
    button .rule0.ruleO.fact.add -text $Messages(actadd) \
	    -command "AddRule .rule0.ruleO.flst.list"
    set_balloon .rule0.ruleO.fact.add $Messages(b_addoru)
    button .rule0.ruleO.fact.del -text $Messages(actdel) \
	    -command "DelRule .rule0.ruleO.flst.list"
    set_balloon .rule0.ruleO.fact.del $Messages(b_deloru)
    button .rule0.ruleO.fact.mod -text $Messages(actmod) \
	    -command "ModRule .rule0.ruleO.flst.list"
    set_balloon .rule0.ruleO.fact.mod $Messages(b_modoru)
    place .rule0.ruleO.fact.add  -relx 0.01 -relwidth 0.34 -rely 0 -relheight 1
    place .rule0.ruleO.fact.del  -relx 0.35 -relwidth 0.32 -rely 0 -relheight 1
    place .rule0.ruleO.fact.mod  -relx 0.67 -relwidth 0.32 -rely 0 -relheight 1
    scrolled2listbox .rule0.ruleO.flst -borderwidth 0
    set_balloon .rule0.ruleO.flst.list $Messages(b_lstoru)
    pack .rule0.ruleO.flst -side top -fill both -expand 1

    #
    # forward rules
    #

    label .rule0.ruleF.title -text $Messages(ruleF) -font $Look(titlefn2) \
	    -fg $Look(titlecolor)
    pack .rule0.ruleF.title -side top -fill x 
    frame .rule0.ruleF.fpol -borderwidth 0
    pack .rule0.ruleF.fpol -side top -fill x -pady 6
    label .rule0.ruleF.fpol.lpol -text $Messages(defpol)
    buttonedmenu .rule0.ruleF.fpol.mpol ChangePolicy2 \
	    [list $Messages(polacc) $Messages(polden) $Messages(polrej) \
	    $Messages(polmsk)]
    set_balloon .rule0.ruleF.fpol.mpol $Messages(b_polfru)
    pack .rule0.ruleF.fpol.lpol -side left
    pack .rule0.ruleF.fpol.mpol -side left -pady 0 -padx 10
    frame .rule0.ruleF.fact -borderwidth 0 -height 26
    pack .rule0.ruleF.fact -side top -fill x -pady 2
    button .rule0.ruleF.fact.add -text $Messages(actadd) \
	    -command "AddRule .rule0.ruleF.flst.list"
    set_balloon .rule0.ruleF.fact.add $Messages(b_addfru)
    button .rule0.ruleF.fact.del -text $Messages(actdel) \
	    -command "DelRule .rule0.ruleF.flst.list"
    set_balloon .rule0.ruleF.fact.del $Messages(b_delfru)
    button .rule0.ruleF.fact.mod -text $Messages(actmod) \
	    -command "ModRule .rule0.ruleF.flst.list"
    set_balloon .rule0.ruleF.fact.mod $Messages(b_modfru)
    place .rule0.ruleF.fact.add  -relx 0.01 -relwidth 0.34 -rely 0 -relheight 1
    place .rule0.ruleF.fact.del  -relx 0.35 -relwidth 0.32 -rely 0 -relheight 1
    place .rule0.ruleF.fact.mod  -relx 0.67 -relwidth 0.32 -rely 0 -relheight 1
    scrolled2listbox .rule0.ruleF.flst -borderwidth 0
    set_balloon .rule0.ruleF.flst.list $Messages(b_lstfru)
    pack .rule0.ruleF.flst -side top -fill both -expand 1

    #
    # buttons bar
    #

    frame .bbar -borderwidth 2 -relief raised
    pack .bbar -side top -fill x

    button .bbar.reset -text $Messages(reset) -command "ResetRules"
    set_balloon .bbar.reset $Messages(b_breset)
    button .bbar.apply -text $Messages(apply) -command "Apply"
    set_balloon .bbar.apply $Messages(b_bapply)
    button .bbar.rescan -text $Messages(rescan) -command "RescanRules"
    set_balloon .bbar.rescan $Messages(b_brescan)

    pack .bbar.apply .bbar.reset .bbar.rescan -side left -padx 10 -pady 4
}

proc scrolled1text {w args} {
    eval frame $w $args
    text $w.text -yscrollcommand "$w.scb set"
    scrollbar $w.scb -command "$w.text yview"
    set scw 16
    place $w.text -x 4 -relwidth 1.0 -width [expr -$scw - 8 ] \
	    -y 4  -relheight 1.0 -height -8
    place $w.scb -relx 1.0 -x [expr -$scw - 4 ] -width $scw \
	    -y 4  -relheight 1.0 -height -8
}

proc scrolled2text {w args} {
    eval frame $w $args
    text $w.txt -wrap none \
	    -yscrollcommand "$w.sbv set" \
	    -xscrollcommand "$w.sbh set"
    scrollbar $w.sbv -command "$w.txt yview"
    scrollbar $w.sbh -orient horizontal -command "$w.txt xview"
    button $w.sbx -text " " -borderwidth 1 -command "
	$w.txt xview moveto 0
	$w.txt yview moveto 0
    "
    set scw 16
    place $w.txt -x 4 -relwidth 1.0 -width [expr -$scw - 8 ] \
	    -y 4  -relheight 1.0 -height [ expr -$scw - 8 ]
    place $w.sbv -relx 1.0 -x [expr -$scw - 4 ] -width $scw \
	    -y 4  -relheight 1.0 -height [ expr -$scw - 8 ]
    place $w.sbh -rely 1.0 -y [expr -$scw - 4 ] -height $scw \
	    -x 4  -relwidth 1.0 -width [ expr -$scw - 8 ]
    place $w.sbx -rely 1.0 -y [expr -$scw - 4 ] -height $scw \
	    -relx 1.0 -x [expr -$scw - 4 ]   -width $scw
}

proc scrolled2listbox {w args} {
    global Look
    eval frame $w $args
    listbox $w.list -selectbackground $Look(selectbgcol) \
	    -selectforeground $Look(selectfgcol) \
	    -selectmode extended -yscrollcommand "$w.sbv set" \
	    -xscrollcommand "$w.sbh set"
    scrollbar $w.sbv -command "$w.list yview"
    scrollbar $w.sbh -orient horizontal -command "$w.list xview"
    button $w.sbx -text " " -borderwidth 1 -command "
	$w.list xview 0
	$w.list yview 0
    "
    set scw 16
    place $w.list -x 4 -relwidth 1.0 -width [expr -$scw - 8 ] \
	    -y 4  -relheight 1.0 -height [ expr -$scw - 8 ]
    place $w.sbv -relx 1.0 -x [expr -$scw - 4 ] -width $scw \
	    -y 4  -relheight 1.0 -height [ expr -$scw - 8 ]
    place $w.sbh -rely 1.0 -y [expr -$scw - 4 ] -height $scw \
	    -x 4  -relwidth 1.0 -width [ expr -$scw - 8 ]
    place $w.sbx -rely 1.0 -y [expr -$scw - 4 ] -height $scw \
	    -relx 1.0 -x [expr -$scw - 4 ]   -width $scw

}

proc scrolled1listbox {w args} {
    global Look
    eval frame $w $args
    listbox $w.list -selectbackground $Look(selectbgcol) \
	    -selectforeground $Look(selectfgcol) \
	    -selectmode extended -yscrollcommand "$w.sbv set"
    scrollbar $w.sbv -command "$w.list yview"
    set scw 16
    place $w.list -x 4 -relwidth 1.0 -width [expr -$scw - 8 ] \
	    -y 4  -relheight 1.0 -height -8
    place $w.sbv -relx 1.0 -x [expr -$scw - 4 ] -width $scw \
	    -y 4  -relheight 1.0 -height -8
}

proc buttonedmenu {w callback list} {
    menubutton $w -text [lindex $list 0] -relief raised -indicatoron 1 \
	    -menu $w.m 
    menu $w.m -tearoff 0 
    foreach entry $list {
	$w.m add command -label $entry -command "$callback $w $entry"
    }
}

#########################################################
#
# fonctions
#
#########################################################

proc Exit {} {

    WriteConfig

    set mypid [pid]
    file delete "/tmp/efw$mypid.sh"
    exit
}

proc Apropos {} {
    global Messages Status Look

    if { $Status(aboutflg) != 0 } {
	return
    }
    set Status(aboutflg) 1 
    toplevel .apropos
    label .apropos.tit -text "    $Messages(titre)    " \
	    -font $Look(titlefn3) -foreground yellow
    label .apropos.ver -text "version 2.2"
    label .apropos.by -text $Messages(par)
    label .apropos.ico -image moi
    label .apropos.txt -text "Daniel Roche"
    label .apropos.mail -text "<dan@lectra.com>" -font $Look(titlefn4)
    label .apropos.tec -text "-- Tcl/Tk --"
    button .apropos.clic -text "OK" -command {
	destroy .apropos
	set Status(aboutflg) 0
    } 
    
    wm title .apropos $Messages(info)
    pack .apropos.tit .apropos.ver .apropos.by .apropos.ico \
	    .apropos.txt .apropos.mail .apropos.tec .apropos.clic -pady 4
    
}

proc Usage {} {
    puts "usage : easyfw \[-i inside_ip\] \[-o outside_ip\]"
    puts "where :"
    puts " -i ipadr   : set the inside firewall ip address"
    puts " -o ipadr   : set the outside firewall ip address"
    exit
}

proc SetLng {} {
    global Messages Config Status 

    if { $Status(setlngflg) } {
	return
    }
    set Status(setlngflg) 1

    toplevel .lng
    wm title .lng $Messages(setlng)
    
    set Status(tmplng) $Config(lng)

    frame .lng.f1 -borderwidth 0 
    pack .lng.f1 -padx 2 -pady 2 -expand 1 -fill both

    frame .lng.btf -borderwidth 2 -relief groove
    pack .lng.btf -padx 0 -pady 0 -fill x

    button .lng.btf.ok -text $Messages(apply) -command { OkLng }
    button .lng.btf.no -text $Messages(cancel) -command { 
	set Status(setlngflg) 0
	destroy .lng
    }
    
    pack .lng.btf.ok .lng.btf.no -side left -padx 8 -pady 4

    set frm .lng.f1
    grid columnconf $frm 0 -weight 1
    grid columnconf $frm 1 -weight 2
    grid rowconf $frm 3 -weight 1

    label $frm.lb -text $Messages(lng) -anchor w
    grid $frm.lb -row 0 -column 0 -sticky nsew -padx 6 -pady 0

    frame $frm.fl -borderwidth 0 -relief flat
    grid $frm.fl -row 0 -column 1 -sticky nsew -padx 6 -pady 0

    menubutton $frm.fl.mb -textvariable Status(tmplng) \
	    -indicatoron 1 -relief raised -menu $frm.fl.mb.m
    menu $frm.fl.mb.m -tearoff 0
    $frm.fl.mb.m add command -label "GB" \
	 -command "set Status(tmplng) {GB}"
    set lnglst [ GetLangList ]
    foreach lng $lnglst {
	$frm.fl.mb.m add command -label "$lng" \
		-command "set Status(tmplng) $lng"
    }
    pack $frm.fl.mb -side left -padx 2 -pady 2 

}
    
proc SetMasqMod {} {
    global Messages Config Status Extern

    if { $Status(setmskmflg) } {
	return
    }
    set Status(setmskmflg) 1

    toplevel .mskm
    wm title .mskm $Messages(masqmod)
    wm geometry .mskm 420x180
    
    set Status(tmpautomod) $Config(automskmod)

    frame .mskm.f1 -borderwidth 0 
    pack .mskm.f1 -padx 2 -pady 2 -expand 1 -fill both

############################################################
# Seem to be useless, since the ip_masq_autofw is in the list
# with the other modules. 
# moreover , ip_masq_autofw require ipmasqadm to work and i don't
# understand clearly which protocol require this ! since everything
# seems to work well without !
#
#    checkbutton .mskm.f1.auto -text $Messages(automskmod) \
#	    -variable Status(tmpautomod) -offvalue "no" -onvalue "yes" \
#	    -anchor w -command {
#	if { $Status(tmpautomod) == "no" } {
#	    pack .mskm.f1.lm  -padx 4 -pady 4 -expand 1 -fill both
#	} else {
#	    pack forget .mskm.f1.lm 
#	}
#    }
#
#    pack .mskm.f1.auto -padx 2 -pady 6 -fill x
#############################################################

    frame .mskm.btf -borderwidth 2 -relief groove
    pack .mskm.btf -padx 0 -pady 0 -fill x

    button .mskm.btf.ok -text $Messages(apply) -command { OkMasqMod }
    button .mskm.btf.no -text $Messages(cancel) -command { 
	set Status(setmskmflg) 0
	destroy .mskm
    }
    
    pack .mskm.btf.ok .mskm.btf.no -side left -padx 8 -pady 4

    set frm .mskm.f1
    scrolled1listbox $frm.lm
    if { $Status(tmpautomod) == "no" } {
	pack $frm.lm -padx 4 -pady 4 -expand 1 -fill both
    }

    # re get the complete modules list
    foreach mod [glob -nocomplain $Extern(mmodpath)] {
	$frm.lm.list insert end [file rootname [file tail $mod]]
    }
    
    # show the currently selected modules
    set max [$frm.lm.list size]
    foreach mod $Config(masqmods) {
	for {set x 0} {$x < $max} {incr x} {
	    set tmp [$frm.lm.list get $x]
	    if { ! [string compare $tmp $mod] } {
		$frm.lm.list selection set $x
	    } 
	}
    }

}
    
proc GetLangList {} {
    global easyfwlib
    
    cd $easyfwlib
    set ficlst [ glob -nocomplain message.* ]
    set lnglst {}
    foreach fic $ficlst {
	lappend lnglst [string trimleft [file extension $fic] .]
    }
    return $lnglst
}

proc OkLng {} {
    global Config Status

    set Config(lng) $Status(tmplng)
    set Status(setlngflg) 0
    destroy .lng
}

proc OkMasqMod {} {
    global Config Status

    # get the currently selected modules
    set tmp [.mskm.f1.lm.list curselection]
    set tmplim {}
    foreach mdi $tmp {
	lappend tmplim [.mskm.f1.lm.list get $mdi]
    }

    set Config(automskmod) $Status(tmpautomod)
    set Config(masqmods) $tmplim
    set Status(setmskmflg) 0
    destroy .mskm
}

proc ChoosePredef {} {
    global easyfwlib Messages
    
    set ipout [.banner.banL.adr.eip get]
    set ipin [.banner.banR.adr.eip get]
    
    if { ! [string length $ipin] || ! [string length $ipout] } {
	tk_messageBox -icon warning -title $Messages(warning) -message $Messages(ipfirst)
	return
    }
    set predefdir [file join $easyfwlib "predefs" ]
    set predef [tk_getOpenFile -initialdir $predefdir]
    if [ string length $predef ] {
	ResetRules
	.predef.f1.config insert end [file tail $predef]
	DecodePredef $predef $ipin $ipout
    }
}

proc ChangePolicy { widget entry } {
    $widget configure -text $entry
}

proc ChangePolicy2 { widget entry } {
    global Status
    
    if { $Status(decodepredefflg) == 0 } {
	ResetPreDef
    }
    $widget configure -text $entry
}

proc ChangePolicy3 { widget entry } {
    global Status
    
    if { [string compare $entry "tcp"] == 0 } {
	.ruleprop.f0.fq.syn configure -state normal
    } else {
	.ruleprop.f0.fq.syn configure -state disabled
    }
    $widget configure -text $entry
}

proc SetNetworkAddr { widget {mode 0} } {
    if { $mode } {
	set naddr [ DisplayNetworkDev ]
	if { ![string length $naddr ] } {
	    return
	}
    } else {
	set naddr "manual"
    }
    if { ![ string compare $naddr "manual"] } {
	set naddr [ GetNetworkAddr ]
    }
    if [ string length $naddr ] {
	$widget delete 0 end
	$widget insert end $naddr
    }
}

proc GetMaskBits {m1 m2 m3 m4} {
    global mskbits

    set bitcnt 0
    set flg 0
    foreach mx [list $m1 $m2 $m3 $m4] {
	if { $flg && $mx != 0 } {
	    set bitcnt -1
	    break
	}
	if { $mx != 255 } {
	    set flg 1
	}
	if { [info exists mskbits($mx) ] } {
	    incr bitcnt $mskbits($mx)
	} else {
	    set bitcnt -1
	    break
	}
    }
    if { $bitcnt == -1 } {
	set res "$m1.$m2.$m3.$m4"
    } else {
	set res $bitcnt 
    }
    return $res
}

proc GetNetworkAddr {} {
    global Messages Look Status mskbits

    if { $Status(getnetadrflg) != 0 } {
	return ""
    }
    toplevel .getnetadr
    label .getnetadr.title -text $Messages(netipadr) -relief raised \
	    -anchor nw -font $Look(titlefn1) -fg $Look(titlecolor)
    frame .getnetadr.frm -borderwidth 2 -relief raised -width 250 -height 64
    frame .getnetadr.but -borderwidth 2 -relief raised
    pack .getnetadr.title -side top -fill x
    pack .getnetadr.frm -side top -fill both -expand 1
    pack .getnetadr.but -side bottom -fill x 
    label .getnetadr.frm.adr -text $Messages(netadr) -anchor ne
    entry .getnetadr.frm.ip1 -background $Look(entrycolor)
    entry .getnetadr.frm.ip2 -background $Look(entrycolor)
    entry .getnetadr.frm.ip3 -background $Look(entrycolor)
    entry .getnetadr.frm.ip4 -background $Look(entrycolor)
    label .getnetadr.frm.msk -text $Messages(netmsk) -anchor ne
    entry .getnetadr.frm.mk1 -background $Look(entrycolor)
    entry .getnetadr.frm.mk2 -background $Look(entrycolor)
    entry .getnetadr.frm.mk3 -background $Look(entrycolor)
    entry .getnetadr.frm.mk4 -background $Look(entrycolor)
    place .getnetadr.frm.adr -x 2 -relwidth 0.42 -y 4 -relheight 0.5 -height -8
    place .getnetadr.frm.ip1 -relx 0.43 -relwidth 0.14 -y 4 -relheight 0.5 -height -8
    place .getnetadr.frm.ip2 -relx 0.57 -relwidth 0.14 -y 4 -relheight 0.5 -height -8
    place .getnetadr.frm.ip3 -relx 0.71 -relwidth 0.14 -y 4 -relheight 0.5 -height -8
    place .getnetadr.frm.ip4 -relx 0.85 -relwidth 0.14 -y 4 -relheight 0.5 -height -8
    place .getnetadr.frm.msk -x 2 -relwidth 0.42 -rely 0.5 -y 4 -relheight 0.5 -height -8
    place .getnetadr.frm.mk1 -relx 0.43 -relwidth 0.14 -rely 0.5 -y 4 \
	    -relheight 0.5 -height -8
    place .getnetadr.frm.mk2 -relx 0.57 -relwidth 0.14 -rely 0.5 -y 4 \
	    -relheight 0.5 -height -8
    place .getnetadr.frm.mk3 -relx 0.71 -relwidth 0.14 -rely 0.5 -y 4 \
	    -relheight 0.5 -height -8
    place .getnetadr.frm.mk4 -relx 0.85 -relwidth 0.14 -rely 0.5 -y 4 \
	    -relheight 0.5 -height -8
    
    button .getnetadr.but.cancel -text $Messages(cancel) \
	    -command {set Status(getnetadrflg) 2}
    button .getnetadr.but.save -text $Messages(ok) \
	    -command {set Status(getnetadrflg) 3}
    pack .getnetadr.but.cancel .getnetadr.but.save -side left -pady 2 -padx 10
    wm title .getnetadr $Messages(getnettitle)
    
    set previous ".getnetadr.frm.mk4"
    foreach field {.getnetadr.frm.ip1 .getnetadr.frm.ip2 .getnetadr.frm.ip3 \
	    .getnetadr.frm.ip4 .getnetadr.frm.mk1 .getnetadr.frm.mk2 \
	    .getnetadr.frm.mk3  .getnetadr.frm.mk4 } {
	bind $previous <Key> "FilterInput %W %A %K $field" 
	bind $previous <Button> "focus %W" 
	bindtags $previous "$previous"
	set previous $field
    }
    
    focus .getnetadr.frm.ip1
    
    set ret "bad"
    set Status(getnetadrflg) 1
    while { $ret == "bad" } {
	tkwait variable Status(getnetadrflg)
	if { $Status(getnetadrflg) == 2 } {
	    set ret ""
	} else {
	    set ip1 [.getnetadr.frm.ip1 get]
	    set ip2 [.getnetadr.frm.ip2 get]
	    set ip3 [.getnetadr.frm.ip3 get]
	    set ip4 [.getnetadr.frm.ip4 get]
	    set mk1 [.getnetadr.frm.mk1 get]
	    set mk2 [.getnetadr.frm.mk2 get]
	    set mk3 [.getnetadr.frm.mk3 get]
	    set mk4 [.getnetadr.frm.mk4 get]
	    set bad 0
	    set bcnt 0
	    foreach val "$ip1 $ip2 $ip3 $ip4 $mk1 $mk2 $mk3 $mk4" {
		if { $val > 255 } {
		    incr bcnt
		}
	    }
	    if { $bcnt == 0 } {
		set msk [GetMaskBits $mk1 $mk2 $mk3 $mk4]
		set ret "$ip1.$ip2.$ip3.$ip4/$msk"
	    } else {
		tk_messageBox -title $Messages(error) -icon error \
			-message $Messages(badip)
	    }
	}
    }
    destroy .getnetadr
    set Status(getnetadrflg) 0
    return $ret
}

proc DisplayNetworkDev {} {
    global Messages Look Status

    if { $Status(dispnetdev) != 0 } {
	return ""
    }
    toplevel .dispnetdev
    label .dispnetdev.lab -text $Messages(chdev) -anchor w
    frame .dispnetdev.fls -relief sunken -borderwidth 2
    listbox .dispnetdev.fls.lst -relief flat -height 3 -font $Look(fixfont) \
	    -yscrollcommand {.dispnetdev.fls.sbv set}
    scrollbar .dispnetdev.fls.sbv  -width 12 \
	    -command {.dispnetdev.fls.lst yview}
    pack .dispnetdev.fls.lst -side left -fill both -expand 1
    pack .dispnetdev.fls.sbv -side right -fill y 
    button .dispnetdev.btn -text $Messages(chman) -anchor w \
	    -command { set Status(dispnetdev) 2} 
    pack .dispnetdev.lab .dispnetdev.fls -fill x -side top -padx 4 -pady 2
    pack .dispnetdev.btn -fill x -side top -padx 4 -pady 4
    frame .dispnetdev.fbn -relief groove -borderwidth 2
    pack .dispnetdev.fbn -fill x -side bottom -padx 0 -pady 0
    button .dispnetdev.fbn.xit -text $Messages(cancel) \
	    -command { set Status(dispnetdev) 4} 
    pack .dispnetdev.fbn.xit -side left -padx 4 -pady 2
    wm title .dispnetdev $Messages(getnettitle)
    bind .dispnetdev.fls.lst <Button-1> { set Status(dispnetdev) 3 }
    #bindtags .dispnetdev.fls.lst [list Listbox .dispnetdev.fls.lst]

    foreach ndev [ GetExistingInterface ] {
	.dispnetdev.fls.lst insert end $ndev
    }

    set ret "bad"
    set Status(dispnetdev) 1
    while { $ret == "bad" } {
	tkwait variable Status(dispnetdev)
	if { $Status(dispnetdev) == 2 } {
	    set ret "manual"
	} elseif { $Status(dispnetdev) == 3 } {
	    set ind [.dispnetdev.fls.lst curselection]
	    set elem [.dispnetdev.fls.lst get $ind]
	    set ret [lindex $elem 1]
	} else {
	    set ret ""
	}
    }
    destroy .dispnetdev
    set Status(dispnetdev) 0
    return $ret
}

proc GetExistingInterface {} {
    global Extern env
    
    # set default language ( decoding ifconfig output ) 
    foreach evar "LC_ALL LANG LANGUAGE" {
	if { [info exists env($evar)] } {
	    set svlng($evar) $env($evar)
	    set env($evar) {C}
	}
    }

    set fid ""
    catch {set fid [open "| $Extern(ifconfig)" r]} err
    if { ![ string length $fid ] } {
	return {}
    } 
    
    set res {}
    gets $fid line
    while { ! [eof $fid] } {
	if [ regexp {(^[a-zA-Z0-9:]+) } $line ml m1 ] {
	    set current $m1
	} elseif [ regexp {inet addr:([0-9\.]*) *(Bcast|P-t-P):([0-9\.]*) *Mask:([0-9\.]*)} \
		$line ml adr typ bct msk ] {
	    regexp {([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)} $adr al a1 a2 a3 a4
	    regexp {([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)} $msk ml m1 m2 m3 m4
	    
	    set n1 [expr $a1 & $m1]
	    set n2 [expr $a2 & $m2]
	    set n3 [expr $a3 & $m3]
	    set n4 [expr $a4 & $m4]
	    
	    set bmsk [GetMaskBits $m1 $m2 $m3 $m4]
	    if [string compare $current "lo" ] {
		lappend res [format "%-8s %d.%d.%d.%d/%s" $current $n1 $n2 $n3 $n4 $bmsk]
	    }
	}
	gets $fid line
    }
    catch {close $fid} err

    foreach evar "LC_ALL LANG LANGUAGE" {
	if { [info exists svlng($evar)] } {
	    set env($evar) $svlng($evar)
	}
    }
    
    return $res
}

proc MyFocus {widget} {
    if { $widget == ".getnetadr.frm.mk1" } { 
	set lm1 [string length [.getnetadr.frm.mk1 get]]
	set lm2 [string length [.getnetadr.frm.mk2 get]]
	set lm3 [string length [.getnetadr.frm.mk3 get]]
	set lm4 [string length [.getnetadr.frm.mk4 get]]
	if { $lm1 == 0 && $lm2 == 0 && $lm3 == 0 && $lm4 == 0 } {
	    set ip1 [.getnetadr.frm.ip1 get]
	    set ip2 [.getnetadr.frm.ip2 get]
	    set ip3 [.getnetadr.frm.ip3 get]
	    set ip4 [.getnetadr.frm.ip4 get]
	    if { $ip1 >= 0 && $ip1 <= 127 } {
		# Class A
		set mk1 255
		set mk2 0
		set mk3 0
		set mk4 0
	    } elseif { $ip1 >= 128 && $ip1 <= 191 } { 
		# Class B
		set mk1 255
		set mk2 255
		set mk3 0
		set mk4 0
	    } elseif { $ip1 >= 192 && $ip1 <= 223 } {
		# Class C
		set mk1 255
		set mk2 255
		set mk3 255
		set mk4 0
	    } else {
		# Reserved normally not used ! but behave as Class C
		set mk1 255
		set mk2 255
		set mk3 255
		set mk4 0
	    }
	    .getnetadr.frm.mk1 delete 0 end
	    .getnetadr.frm.mk1 insert end $mk1
	    .getnetadr.frm.mk2 delete 0 end
	    .getnetadr.frm.mk2 insert end $mk2
	    .getnetadr.frm.mk3 delete 0 end
	    .getnetadr.frm.mk3 insert end $mk3
	    .getnetadr.frm.mk4 delete 0 end
	    .getnetadr.frm.mk4 insert end $mk4
	}
    }
    focus $widget
}

proc FilterInput {widget char keysym nextwid} {
    if { $char >= "0" && $char <= "9" } {
	set len [ string length [$widget get] ] 
	if { $len < 3 } {
	    $widget insert insert $char
	}
	set len [ string length [$widget get] ] 
	if { $len >= 3 } {
	    MyFocus $nextwid
	}
    } elseif { $char == "" || $keysym == "BackSpace" } {
	set ind [ expr [$widget index insert] - 1]
	$widget delete $ind insert
    } elseif { $char == "" || $keysym == "Delete"  } {
	set ind [ expr [$widget index insert] + 1]
	$widget delete insert $ind
    } elseif { $char == "" || $keysym == "Left" } {
	set ind [ expr [$widget index insert] - 1]
	$widget icursor $ind
    } elseif { $char == "" || $keysym == "Right" } {
	set ind [ expr [$widget index insert] + 1]
	$widget icursor $ind
    } elseif { $keysym == "Tab" || $keysym == "KP_Enter" \
	    || $keysym == "Return" || $char == "." } {
	MyFocus $nextwid
    }
}

proc GetPolicy { widget } {
    set tmp [$widget.m index [$widget cget -text]]
    return $tmp
}

proc ResetPreDef {} {
    .predef.f1.config delete 0 end
    .predef.f2.text delete 0.0 end
}

proc ResetRules {} {
    .rule0.ruleI.fpol.mpol.m invoke 0
    .rule0.ruleO.fpol.mpol.m invoke 0
    .rule0.ruleF.fpol.mpol.m invoke 0
    .rule0.ruleI.flst.list delete 0 end
    .rule0.ruleO.flst.list delete 0 end
    .rule0.ruleF.flst.list delete 0 end
    ResetPreDef
}

proc DelRule {listwid} {
    set cursel [$listwid curselection]
    set nbe [ llength $cursel ]
    if { $nbe == 0 } { 
	return
    }

    set lesruc {}
    for {set ind [expr $nbe - 1]} {$ind >= 0} {incr ind -1} {
	lappend lesruc [ lindex $cursel $ind ]
    }
    
    ResetPreDef
    foreach elem $lesruc {
	$listwid delete $elem
    }
}

proc AddRule {widget} {
    global Status Config
    
    set rule [ShowRuleProp $widget 1 {} ]
    if [ string length $rule ] {
	ResetPreDef
	if { $Status(debfin) == 1 } {
	    $widget insert 0 $rule
	} else {
	    $widget insert end $rule
	}
	if { $Config(linkio) } {
	    set widgetbis [ReverseInOutWidget $widget]
	    if [ string length $widgetbis ] {
		set rulebis [ReverseInOutRule $rule]
		if { $Status(debfin) == 1 } {
		    $widgetbis insert 0 $rulebis
		} else {
		    $widgetbis insert end $rulebis
		}
	    }
	}
    }
}

proc ModRule {widget} {
    global Messages
    
    set cursel [$widget curselection]
    set nbr [llength $cursel]
    if { $nbr != 1 } {
	tk_messageBox -icon error -title $Messages(error) -message $Messages(onesel)
	return
    }
    set prerule [$widget get $cursel]
    set rule [ShowRuleProp $widget 0 $prerule ]
    if [ string length $rule ] {
	if [ string compare $rule $prerule ] {
	    ResetPreDef
	    $widget delete $cursel
	    $widget insert $cursel $rule
	}
    }
}

proc ShowRuleProp {widget mode rule} {
    global Messages Look Status Mode
    global batpolicy batprotocol optsyntax
    global NegSip NegSpt NegDip NegDpt SynTcp
    
    if { $Status(rulepropflg) != 0 } {
	return ""
    }
    toplevel .ruleprop
    if { $widget == ".rule0.ruleI.flst.list" } {
	set titre $Messages(rul1I)
	set mskf 0
    } elseif { $widget == ".rule0.ruleO.flst.list" } {
	set titre $Messages(rul1O)
	set mskf 0
    } else {
	set titre $Messages(rul1F)
	set mskf 1
    }
    label .ruleprop.lab -text $titre -borderwidth 2 -relief raised \
	    -anchor nw -font $Look(titlefn1) -fg $Look(titlecolor)
    frame .ruleprop.f0 -borderwidth 2 -relief raised
    frame .ruleprop.but -borderwidth 2 -relief raised
    pack .ruleprop.lab -side top -fill x 
    pack .ruleprop.f0 -side top -fill both -expand 1
    pack .ruleprop.but -side bottom -fill x 
    
    if { $mode == 1 } {
	frame .ruleprop.f0.fw -borderwidth 0 
	pack .ruleprop.f0.fw -side top -fill x
	label .ruleprop.f0.fw.lab -text $Messages(where)
	radiobutton .ruleprop.f0.fw.deb -text $Messages(debut) -variable Status(debfin) -value 1
	radiobutton .ruleprop.f0.fw.fin -text $Messages(fin) -variable Status(debfin) -value 2
	pack .ruleprop.f0.fw.lab .ruleprop.f0.fw.deb .ruleprop.f0.fw.fin \
		-side left -padx 4 -pady 6
	set Status(debfin) 2
    }
    frame .ruleprop.f0.fp -borderwidth 0 
    pack .ruleprop.f0.fp -side top -fill x
    label .ruleprop.f0.fp.l1 -text $Messages(policy)
    set mlst [list $Messages(polacc) $Messages(polden) $Messages(polrej)]
    if { $mskf == 1 } {
	lappend mlst $Messages(polmsk) 
    }
    buttonedmenu .ruleprop.f0.fp.mpol ChangePolicy $mlst
    set_balloon .ruleprop.f0.fp.mpol $Messages(b2_pol)
    pack .ruleprop.f0.fp.l1 .ruleprop.f0.fp.mpol -side left -padx 4 -pady 6

    frame .ruleprop.f0.fq -borderwidth 0 
    pack .ruleprop.f0.fq -side top -fill x
    label .ruleprop.f0.fq.l2 -text $Messages(protocol)
    buttonedmenu .ruleprop.f0.fq.mpro ChangePolicy3 [list $Messages(all) tcp udp icmp]
    set_balloon .ruleprop.f0.fq.mpro $Messages(b2_prot)
    checkbutton .ruleprop.f0.fq.syn -text $Messages(syntcp) -indicatoron 1 \
	    -variable SynTcp -state disabled
    set_balloon .ruleprop.f0.fq.syn $Messages(b2_syn)
    pack .ruleprop.f0.fq.l2 .ruleprop.f0.fq.mpro -side left -padx 4 -pady 6
    pack .ruleprop.f0.fq.syn -side right -padx 6 -pady 6

    frame .ruleprop.f0.fs -borderwidth 0 
    pack .ruleprop.f0.fs -side top -fill x
    label .ruleprop.f0.fs.lip -text $Messages(sourcip)
    frame .ruleprop.f0.fs.f1 -borderwidth 0
    if { [string compare $Mode "ipchains"] == 0 } {
	checkbutton .ruleprop.f0.fs.f1.nip -indicatoron 0 -text "!" \
		-selectcolor $Look(entrycolor) -variable NegSip
	set_balloon .ruleprop.f0.fs.f1.nip $Messages(b2_neg)
    }
    entry .ruleprop.f0.fs.f1.eip  -width 20 -background $Look(entrycolor)
    button .ruleprop.f0.fs.f1.bip -text $Messages(ipset) \
	    -command "SetNetworkAddr .ruleprop.f0.fs.f1.eip"
    set_balloon .ruleprop.f0.fs.f1.eip $Messages(b2_sip)
    set_balloon .ruleprop.f0.fs.f1.bip $Messages(b2_sip)
    label .ruleprop.f0.fs.lpt -text $Messages(port)
    frame .ruleprop.f0.fs.f2 -borderwidth 0 
    if { [string compare $Mode "ipchains"] == 0 } {
	checkbutton .ruleprop.f0.fs.f2.npt -indicatoron 0 -text "!" \
		-selectcolor $Look(entrycolor) -variable NegSpt
	set_balloon .ruleprop.f0.fs.f2.npt $Messages(b2_neg)
    }
    entry .ruleprop.f0.fs.f2.ept -width 10 -background $Look(entrycolor)
    button .ruleprop.f0.fs.f2.bpt -text $Messages(ipset) \
	    -command "SetPorts .ruleprop.f0.fs.f2.ept" 
    set_balloon .ruleprop.f0.fs.f2.ept $Messages(b2_spt)
    set_balloon .ruleprop.f0.fs.f2.bpt $Messages(b2_spt)
    pack .ruleprop.f0.fs.f2 .ruleprop.f0.fs.lpt \
	    .ruleprop.f0.fs.f1 .ruleprop.f0.fs.lip \
	    -side right -padx 6 -pady 6
    if { [string compare $Mode "ipchains"] == 0 } {
	pack .ruleprop.f0.fs.f1.nip -side left -padx 0 -pady 0 -fill y -expand 1
	pack .ruleprop.f0.fs.f2.npt -side left -padx 0 -pady 0 -fill y -expand 1
    }
    pack .ruleprop.f0.fs.f1.eip .ruleprop.f0.fs.f1.bip \
	    -side left -padx 0 -pady 0 -fill y -expand 1
    pack .ruleprop.f0.fs.f2.ept .ruleprop.f0.fs.f2.bpt \
	    -side left -padx 0 -pady 0 -fill y -expand 1
    frame .ruleprop.f0.fd -borderwidth 0 
    pack .ruleprop.f0.fd -side top -fill x
    label .ruleprop.f0.fd.lip -text $Messages(destip)
    frame .ruleprop.f0.fd.f1 -borderwidth 0
    if { [string compare $Mode "ipchains"] == 0 } {
	checkbutton .ruleprop.f0.fd.f1.nip -indicatoron 0 -text "!" \
		-selectcolor $Look(entrycolor) -variable NegDip
	set_balloon .ruleprop.f0.fd.f1.nip $Messages(b2_neg)
    }    
    entry .ruleprop.f0.fd.f1.eip  -width 20 -background $Look(entrycolor)
    button .ruleprop.f0.fd.f1.bip -text $Messages(ipset) \
	    -command "SetNetworkAddr .ruleprop.f0.fd.f1.eip"
    set_balloon .ruleprop.f0.fd.f1.eip $Messages(b2_dip)
    set_balloon .ruleprop.f0.fd.f1.bip $Messages(b2_dip)
    label .ruleprop.f0.fd.lpt -text $Messages(port)
    frame .ruleprop.f0.fd.f2 -borderwidth 0 
    if { [string compare $Mode "ipchains"] == 0 } {
	checkbutton .ruleprop.f0.fd.f2.npt -indicatoron 0 -text "!" \
		-selectcolor $Look(entrycolor) -variable NegDpt
	set_balloon .ruleprop.f0.fd.f2.npt $Messages(b2_neg)
    }    
    entry .ruleprop.f0.fd.f2.ept -width 10 -background $Look(entrycolor)
    button .ruleprop.f0.fd.f2.bpt -text $Messages(ipset) \
	    -command "SetPorts .ruleprop.f0.fd.f2.ept"
    set_balloon .ruleprop.f0.fd.f2.ept $Messages(b2_dpt)
    set_balloon .ruleprop.f0.fd.f2.bpt $Messages(b2_dpt)
    pack .ruleprop.f0.fd.f2 .ruleprop.f0.fd.lpt \
	    .ruleprop.f0.fd.f1 .ruleprop.f0.fd.lip \
	    -side right -padx 6 -pady 6
    if { [string compare $Mode "ipchains"] == 0 } {
	pack .ruleprop.f0.fd.f1.nip -side left -padx 0 -pady 0 -fill y -expand 1
	pack .ruleprop.f0.fd.f2.npt -side left -padx 0 -pady 0 -fill y -expand 1
    }
    pack .ruleprop.f0.fd.f1.eip .ruleprop.f0.fd.f1.bip \
	    -side left -padx 0 -pady 0 -fill y -expand 1
    pack .ruleprop.f0.fd.f2.ept .ruleprop.f0.fd.f2.bpt \
	    -side left -padx 0 -pady 0 -fill y -expand 1
    
    button .ruleprop.but.cancel -text $Messages(cancel) \
	    -command {set Status(rulepropflg) 2}
    button .ruleprop.but.save -text $Messages(ok) \
	    -command {set Status(rulepropflg) 3}
    pack .ruleprop.but.cancel .ruleprop.but.save -side left -pady 2 -padx 10
    
    wm title .ruleprop $Messages(ruleproptitle)
    
    set NegSip 0
    set NegSpt 0
    set NegDip 0
    set NegDpt 0
    set SynTcp 0

    if [ string length $rule ] {
	set args [split $rule]
	set action [lindex $args 0]
	.ruleprop.f0.fp.mpol.m invoke $batpolicy($action)
	set nbind [llength $args]
	set ind 1
	while { $ind < $nbind } {
	    set carg [lindex $args $ind]
	    if { $carg == $optsyntax(prot,$Mode) } {
		incr ind
		set carg [lindex $args $ind]
		.ruleprop.f0.fq.mpro.m invoke $batprotocol($carg)
		incr ind
	    } elseif { $carg == $optsyntax(src,$Mode) } {
		incr ind
		set carg [lindex $args $ind]
		if { $carg == "!" } {
		    set NegSip 1
		    incr ind
		    set carg [lindex $args $ind]
		}
		if { $carg != "0.0.0.0/0" } {
		    .ruleprop.f0.fs.f1.eip insert end $carg
		}
		incr ind 
		set carg [lindex $args $ind]
		if { $carg == "!" } {
		    set NegSpt 1
		    incr ind
		    set carg [lindex $args $ind]
		}
		while { [string index $carg 0] != "-" && $ind < $nbind } {
		    .ruleprop.f0.fs.f2.ept insert end "$carg "
		    incr ind
		    set carg [lindex $args $ind]
		}
	    } elseif { $carg == $optsyntax(dst,$Mode) } {
		incr ind
		set carg [lindex $args $ind]
		if { $carg == "!" } {
		    set NegDip 1
		    incr ind
		    set carg [lindex $args $ind]
		}
		if { $carg != "0.0.0.0/0" } {
		    .ruleprop.f0.fd.f1.eip insert end $carg
		}
		incr ind 
		set carg [lindex $args $ind]
		if { $carg == "!" } {
		    set NegDpt 1
		    incr ind
		    set carg [lindex $args $ind]
		}
		while { [string index $carg 0] != "-" && $ind < $nbind } {
		    .ruleprop.f0.fd.f2.ept insert end "$carg "
		    incr ind
		    set carg [lindex $args $ind]
		}
	    } elseif { $carg == $optsyntax(syn,$Mode) } {
		set SynTcp 1
		incr ind
	    }
	}
    }
    
    set ret "bad"
    set Status(rulepropflg) 1
    while { $ret == "bad" } {
	set flgprot 0
	set flgport 0
	tkwait variable Status(rulepropflg)
	if { $Status(rulepropflg) == 2 } {
	    set ret ""
	} else {
	    set tmp [GetPolicy .ruleprop.f0.fp.mpol]
	    set ret $optsyntax(pol,$tmp,$Mode)
	    set prot [GetPolicy .ruleprop.f0.fq.mpro]
	    if { $prot } {
		append ret " $optsyntax(prot,$Mode) [.ruleprop.f0.fq.mpro cget -text]"
		incr flgprot
		if { $prot == 1 } {
		    if { $SynTcp } {
			append ret " $optsyntax(syn,$Mode)"
		    }
		}
	    }
	    set src [.ruleprop.f0.fs.f1.eip get]
	    if [ string length $src] {
		append ret " $optsyntax(src,$Mode)"
		if { $NegSip } {
		    append ret " !"
		}
		append ret " $src"
	    } else {
		append ret " $optsyntax(src,$Mode) 0.0.0.0/0"
	    }
	    set sprt [.ruleprop.f0.fs.f2.ept get]
	    if [ string length $sprt] {
		if { $NegSpt } {
		    append ret " !"
		}
		append ret " $sprt"
		incr flgport
	    }
	    set dst [.ruleprop.f0.fd.f1.eip get]
	    if [ string length $dst] {
		append ret " $optsyntax(dst,$Mode)"
		if { $NegDip } {
		    append ret " !"
		}
		append ret " $dst"
	    } else {
		append ret " $optsyntax(dst,$Mode) 0.0.0.0/0"
	    }
	    set dprt [.ruleprop.f0.fd.f2.ept get]
	    if [ string length $dprt] {
		if { $NegDpt } {
		    append ret " !"
		}
		append ret " $dprt"
		incr flgport
	    }
	}
	if { $flgprot == 0 && $flgport != 0 } {
	    tk_messageBox -icon warning -title $Messages(warning) \
		    -message $Messages(noprot)
	    set ret "bad"
	}
    }
    destroy .ruleprop
    set Status(rulepropflg) 0
    return $ret
}

proc SetPorts { widget } {
    global Messages
    set prot [GetPolicy .ruleprop.f0.fq.mpro]
    if { $prot } {
	switch -exact -- [.ruleprop.f0.fq.mpro cget -text] {
	    "tcp" {
		set plst [ GetPortList tcp]
	    }
	    "udp" {
		set plst [ GetPortList udp]  
	    }
	    default {
		tk_messageBox -icon warning -title $Messages(warning) \
			-message $Messages(tcpudpprot)
		set plst ""
	    }
	}
	if [ string length $plst ] {
	    $widget delete 0 end
	    $widget insert end $plst
	}
    } else {
	tk_messageBox -icon warning -title $Messages(warning) \
		-message $Messages(noprot)
    }
}

proc GetPortList {proto} {
    global Messages Look Status
    global tabport
    global NumPort
    
    if { $Status(portlistflg) != 0 } {
	return ""
    }
    toplevel .portlist
    label .portlist.lab -text $Messages(portlisttitle) -borderwidth 2 -relief raised \
	    -anchor nw -font $Look(titlefn1) -fg $Look(titlecolor)
    frame .portlist.f0 -borderwidth 2 -relief sunken -width 250 -height 250
    frame .portlist.but -borderwidth 2 -relief raised
    pack .portlist.lab -side top -fill x 
    pack .portlist.f0 -side top -fill both -expand 1 -padx 4 -pady 4
    pack .portlist.but -side bottom -fill x 
    
    text .portlist.f0.tx -borderwidth 0 -yscrollcommand ".portlist.f0.sb set"
    scrollbar .portlist.f0.sb -command ".portlist.f0.tx yview"
    set scw 16
    place .portlist.f0.tx -x 0 -relwidth 1.0 -width [expr -$scw ] -y 0 -relheight 1.0 
    place .portlist.f0.sb -relx 1.0 -x [expr -$scw ] -width $scw -y 0 -relheight 1.0 
    unset scw
    
    button .portlist.but.cancel -text $Messages(cancel) \
	    -command {set Status(portlistflg) 2}
    button .portlist.but.save -text $Messages(ok) -command {set Status(portlistflg) 3}
    pack .portlist.but.cancel .portlist.but.save -side left -pady 2 -padx 10
    
    wm title .portlist $Messages(portlisttitle)
    
    set NumPort {}
    set fid [open "/etc/services" r]
    set ind 0
    gets $fid line
    while { ! [eof $fid] } {
	set first [string index $line 0]
	if { $first != "#" && $first != "" } {
	    regsub \/ $line " " line2
	    set lst0 [eval list $line2]
	    if {  [lindex $lst0 2] == $proto } {
		set lout [format "%5d   %s (%s)" \
			[lindex $lst0 1] [lindex $lst0 0] [lindex $lst0 2] ]
		radiobutton .portlist.f0.tx.prt$ind -text $lout -variable NumPort \
			-value [lindex $lst0 1]
		.portlist.f0.tx window create end -window .portlist.f0.tx.prt$ind
		.portlist.f0.tx.prt$ind deselect
		.portlist.f0.tx insert end "\n"
		incr ind
	    }
	}
	gets $fid line
    }
    close $fid
    set nbr $ind

    set ret "bad"
    set Status(portlistflg) 1
    while { $ret == "bad" } {
	tkwait variable Status(portlistflg)
	if { $Status(portlistflg) == 2 } {
	    set ret ""
	} else {
	    set ret ""
	    set cnt 0
	    if { [string length $NumPort] } { 
		append ret "$NumPort" 
	    }
	}
    }
    destroy .portlist
    set Status(portlistflg) 0
    return $ret
}

proc DecodePredef { file insideip outsideip } {
    global batpolicy Status Config Mode optsyntax
    
    set Status(decodepredefflg) 1
    set widsect(input) ".rule0.ruleI"
    set widsect(output) ".rule0.ruleO"
    set widsect(forward) ".rule0.ruleF"
    
    set fid [open $file r]
    set current none
    gets $fid line
    while { ! [eof $fid] } {
	set fchar [string index $line 0]
	if { $fchar != "#" && $fchar != "" } {
	    set lst0 [eval list $line ]
	    set fword [lindex $lst0 0]
	    if { $fword == "Section" } {
		set current [lindex $lst0 1]
		set cnt 0
	    } else { 
		if { $current == "comment" } {
		    if { $fword == $Config(lng) } {
			set msg [join [lrange $lst0 1 end]]
			.predef.f2.text insert end "$msg\n"
			incr cnt
		    } elseif { $fword == "ANY" && $cnt == 0 } {
			set msg [join [lrange $lst0 1 end]]
			.predef.f2.text insert end "$msg\n"
		    }
		} else {
		    set father $widsect($current)
		    if { $fword == "Default" } {
			$father.fpol.mpol.m invoke $batpolicy([lindex $lst0 1])
		    } elseif { $fword == "Accept" || $fword == "Deny" || \
			    $fword == "Reject" || $fword == "Masq" } {
			regsub -all Accept $line $optsyntax(pol,0,$Mode) line
			regsub -all Deny $line $optsyntax(pol,1,$Mode) line
			regsub -all Reject $line $optsyntax(pol,2,$Mode) line
			regsub -all Masq $line $optsyntax(pol,3,$Mode) line
			regsub -all IPINSIDE $line $insideip line
			regsub -all IPOUTSIDE $line $outsideip line
			regsub -all -- -prot $line $optsyntax(prot,$Mode) line
			regsub -all -- -src $line $optsyntax(src,$Mode) line
			regsub -all -- -dest $line $optsyntax(dst,$Mode) line
			$father.flst.list insert end $line
		    } else {
			puts "bad predefined rule"
		    }
		}
	    }
	}
	gets $fid line
    }
    close $fid
    set Status(decodepredefflg) 0
}

proc Apply {} {
    global Messages Config Status Look Extern

    if { $Status(applyflg) } {
	return
    }
    set Status(applyflg) 1

    toplevel .apply
    wm title .apply $Messages(apply)
    
    frame .apply.frm -borderwidth 0 
    pack .apply.frm -padx 2 -pady 2 -expand 1 -fill both

    frame .apply.btf -borderwidth 2 -relief groove
    pack .apply.btf -padx 0 -pady 0 -fill x

    button .apply.btf.ok -text $Messages(apply) -command { 
	if { $Status(applyfile) } {
	    set Extern(applyfile) [.apply.frm.ffil.e get]
	}
	set Status(applyflg) 0
	destroy .apply
	RealApply
    }
    button .apply.btf.no -text $Messages(cancel) -command { 
	set Status(applyflg) 0
	destroy .apply
    }
    
    pack .apply.btf.ok .apply.btf.no -side left -padx 8 -pady 4

    set frm .apply.frm

    checkbutton $frm.now -text $Messages(applynow) -variable Status(applynow) \
	    -anchor nw
    pack $frm.now -padx 2 -pady 4 -fill x
    frame $frm.ffil 
    pack $frm.ffil -fill x
    checkbutton $frm.ffil.flg -text $Messages(applyfile) \
	    -variable Status(applyfile) -anchor nw
    entry $frm.ffil.e -background $Look(entrycolor)
    button $frm.ffil.b -text $Messages(precho) -command {
	set tmpfil [tk_getOpenFile ]
	if [ string length $tmpfil ] {
	    .apply.frm.ffil.e delete 0 end
	    .apply.frm.ffil.e insert 0 $tmpfil
	}
    }
    pack $frm.ffil.flg -side left -padx 2 -pady 2
    pack $frm.ffil.e  -side left -padx 2 -pady 2 -expand 1 -fill x
    pack $frm.ffil.b -side left -padx 2 -pady 2
    checkbutton $frm.boot -text $Messages(applyboot) -variable Status(applyboot) \
	    -anchor nw
    pack $frm.boot -padx 2 -pady 4 -fill x

}

proc RealApply {} {
    global Messages Extern Status Config Mode
    global optsyntax
    
    if { ! $Status(systemok) } {
	return
    }

    set fid [open $Extern(applyfile) w]
    if { ![ string length $fid ] } {
	tk_messageBox -icon error -title $Messages(error) \
		-message $Messages(pbapply1)
	return
    } 
    puts $fid "#!/bin/sh"
    puts $fid ""
    
    if { $Config(automskmod) == "no" } {
	puts $fid "#"
	puts $fid "# Remove used Masquerading Modules"
	puts $fid "#"
	puts $fid {cat /proc/modules | grep ip_masq > /tmp/ipmapp$$}
	puts $fid {while read LINE}
	puts $fid {do}
	puts $fid { set $LINE none none none}
	puts $fid { if [ "$1" != "none" ]}
	puts $fid { then}
	puts $fid "  $Extern(rmmod) \$1"
	puts $fid { fi}
	puts $fid {done < /tmp/ipmapp$$}
	puts $fid {rm -f /tmp/ipmapp$$}
	puts $fid ""
    }

    puts $fid "#"
    puts $fid "# Input Rules"
    puts $fid "#"
    puts $fid "$Extern($Mode) $optsyntax(flushin,$Mode)"
    set tmp [GetPolicy .rule0.ruleI.fpol.mpol]
    puts $fid "$Extern($Mode) $optsyntax(defpolin,$Mode) $optsyntax(pol,$tmp,$Mode)"
    set max [.rule0.ruleI.flst.list size]
    for {set ind 0} {$ind < $max} {incr ind} {
	set tmp [.rule0.ruleI.flst.list get $ind]
	puts $fid "$Extern($Mode) $optsyntax(addin,$Mode) $tmp"
    }
    puts $fid ""
    
    puts $fid "#"
    puts $fid "# Output Rules"
    puts $fid "#"
    puts $fid "$Extern($Mode) $optsyntax(flushout,$Mode)"
    set tmp [GetPolicy .rule0.ruleO.fpol.mpol]
    puts $fid "$Extern($Mode) $optsyntax(defpolout,$Mode) $optsyntax(pol,$tmp,$Mode)"
    set max [.rule0.ruleO.flst.list size]
    for {set ind 0} {$ind < $max} {incr ind} {
	set tmp [.rule0.ruleO.flst.list get $ind]
	puts $fid "$Extern($Mode) $optsyntax(addout,$Mode) $tmp"
    }
    puts $fid ""
    
    puts $fid "#"
    puts $fid "# Forwarding Rules"
    puts $fid "#"
    puts $fid "$Extern($Mode) $optsyntax(flushfw,$Mode)"
    set countf 0
    set tmp [GetPolicy .rule0.ruleF.fpol.mpol]
    puts $fid "$Extern($Mode) $optsyntax(defpolfw,$Mode) $optsyntax(pol,$tmp,$Mode)"
    set max [.rule0.ruleF.flst.list size]
    for {set ind 0} {$ind < $max} {incr ind} {
	set tmp [.rule0.ruleF.flst.list get $ind]
	if { [lindex $tmp 0] == $optsyntax(pol,3,$Mode) } {
	    incr countf
	}
	puts $fid "$Extern($Mode) $optsyntax(addfw,$Mode) $tmp"
    }
    puts $fid ""
    if { $countf != 0 && $Config(automskmod) == "no" } {
	puts $fid "#"
	puts $fid "# Load Usefull Masquerading Modules"
	puts $fid "#"
	foreach mod $Config(masqmods) {
	    puts $fid "$Extern(insmod) $mod"
	}
    }
    
    close $fid
    
    file attributes $Extern(applyfile) -permissions 00755

    if { $Status(applynow) } {
	exec $Extern(applyfile)
    }
    if { $Status(applyboot) } {
	file copy -force $Extern(applyfile) $Extern(applyboot1) 
	
	set fid ""
	catch {set fid [open "| $Extern(runlevel)" r]} err
	if { ![ string length $fid ] } {
	    return
	} 
	gets $fid line
	close $fid
	regexp {(.*) (.*)} $line ml prev rlvl
	set tmp [subst -nobackslashes -nocommands $Extern(applyboot2)]
	exec ln -s $Extern(applyboot1) $tmp
    }

}

proc ReverseInOutRule { rule } {
    global Mode optsyntax

    set li1 [split $rule]
    set ix1 [lsearch -exact $li1 $optsyntax(src,$Mode)]
    set ix2 [lsearch -exact $li1 $optsyntax(dst,$Mode)]
    set lp1 [lrange $li1 0 [expr $ix1 - 1]]
    set lp2 [lrange $li1 [expr $ix1 + 1] [expr $ix2 - 1]]
    set lp3 [lrange $li1 [expr $ix2 + 1] end]
    set li2 [concat $lp1 $optsyntax(src,$Mode) $lp3 $optsyntax(dst,$Mode) $lp2]
    set rule2 [join $li2] 
    return $rule2
}

proc ReverseInOutWidget { widget } {
    if { $widget == ".rule0.ruleI.flst.list" } {
	set widgetbis ".rule0.ruleO.flst.list"
    } elseif { $widget == ".rule0.ruleO.flst.list" } {
	set widgetbis ".rule0.ruleI.flst.list"
    } else {
	set widgetbis ""
    }
    return $widgetbis
}

proc ReadRulesFromIpUtils {} {
    global Mode Status

    if { ! $Status(systemok) } {
	return
    }
    
    if { [string compare $Mode "ipfwadm"] == 0 } {
	ReadRulesFromIpfwadm
    } else {
	ReadRulesFromIpchains
    }
}

proc ReadRulesFromIpfwadm {} {
    global Extern batpolicy

    foreach letter {I O F} {

	set fid ""
	catch {set fid [open "| $Extern(ipfwadm) -$letter -l -n" r]} err
	if { ![ string length $fid ] } {
	    return
	} 
	gets $fid line
	while { ! [eof $fid] } {
	    set lst0 [eval list $line]
	    set firstw [lindex $lst0 0]
	    if { $firstw == "IP" } {
		set ind [lsearch -exact $lst0 "policy:"]
		incr ind
		set tmp [lindex $lst0 $ind]
		.rule0.rule$letter.fpol.mpol.m invoke $batpolicy($tmp)
	    } elseif { $firstw == "deny" || $firstw == "acc" || \
		    $firstw == "rej" || $firstw == "acc/m" } {
		set res [DecodeIpfwadmRule $line]
		.rule0.rule$letter.flst.list insert end $res
	    }
	    gets $fid line
	}
	catch {close $fid} err
    }
}

proc ReadRulesFromIpchains {} {
    global Extern batpolicy
    
    foreach word {input output forward} letter {I O F} {
	set fid ""
	catch {set fid [open "| $Extern(ipchains) -L $word -n" r]} err
	if { ![ string length $fid ] } {
	    puts "$Extern(ipchains) error : $err"
	    return
	} 
	gets $fid line
	while { ! [eof $fid] } {
	    set lst0 [eval list $line]
	    set firstw [lindex $lst0 0]
	    if { $firstw == "Chain" } {
		if [regexp "Chain $word \\(policy (.*)\\):" $line l0 pol] {
		    .rule0.rule$letter.fpol.mpol.m invoke $batpolicy($pol)
		}
	    } elseif { $firstw == "DENY" || $firstw == "ACCEPT" || \
		    $firstw == "REJECT" || $firstw == "MASQ" } {
		set res [DecodeIpchainsRule $line]
		.rule0.rule$letter.flst.list insert end $res
	    }
	    gets $fid line
	}
	catch {close $fid} err
    }
	
}

proc DecodeIpfwadmRule { iprule } {

    set lst [eval list $iprule]
    set firstw [lindex $lst 0]
    
    if { $firstw == "deny" } {
	set res "DENY"
    } elseif { $firstw == "acc" } {
	set res "ACCEPT"
    } elseif { $firstw == "rej" } {
	set res "REJECT"
    } else {
	set res "MASQ"
    }
    
    set tmp [lindex $lst 1]
    if { $tmp != "all" } {
	set res "$res -P $tmp"
    }
    set tmp [lindex $lst 2]
    set res "$res -S $tmp"
    set tmp [lindex $lst 4]
    if { $tmp != "n/a" } {
	if { $tmp != "*" } {
	    regsub -all \, $tmp " " tmp2
	    set res "$res $tmp2"
	}
    }
    set tmp [lindex $lst 3]
    set res "$res -D $tmp"
    set tmp [lindex $lst 4]
    if { $tmp != "n/a" } {
	set tmp [lindex $lst 6]
	if { $tmp != "*" } {
	    regsub -all \, $tmp " " tmp2
	    set res "$res $tmp2"
	}
    }
    return $res
}

proc DecodeIpchainsRule { iprule } {

    set lst [eval list $iprule]
    set firstw [lindex $lst 0]
    
    # silly test but may change !
    if { $firstw == "DENY" } {
	set res "DENY"
    } elseif { $firstw == "ACCEPT" } {
	set res "ACCEPT"
    } elseif { $firstw == "REJECT" } {
	set res "REJECT"
    } else {
	set res "MASQ"
    }
    
    set tmp [lindex $lst 1]
    if { $tmp != "all" } {
	set res "$res -p $tmp"
    }
    set tmp [lindex $lst 3]
    set res "$res -s $tmp"
    set tmp [lindex $lst 5]
    if { $tmp != "n/a" } {
	if { $tmp != "*" } {
	    regsub -all \, $tmp " " tmp2
	    set res "$res $tmp2"
	}
    }
    set tmp [lindex $lst 4]
    set res "$res -d $tmp"
    set tmp [lindex $lst 5]
    if { $tmp != "n/a" } {
	set tmp [lindex $lst 7]
	if { $tmp != "*" } {
	    regsub -all \, $tmp " " tmp2
	    set res "$res $tmp2"
	}
    }
    return $res
}

proc RescanRules {} {
    ResetRules
    ReadRulesFromIpUtils
}

proc VerifSystemConfig {} {
    global Extern Status Messages Mode

    set badconf 0
    if { [string compare $Mode "ipfwadm"] == 0 } {
	if { ! [file exists /proc/net/ip_input ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_input"
	}
	if { ! [file exists /proc/net/ip_output ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_output"
	}
	if { ! [file exists /proc/net/ip_forward ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_forward"
	}
	if { ! [file exists /proc/net/ip_masquerade ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_masquerade"
	}
	if { ! [file exists /proc/net/ip_masq_app ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_masq_app"
	}
	if { ! [file exists $Extern(ipfwadm) ] } {
	    incr badconf
	    puts "program missing : ipfwadm"
	}
    } else {
	if { ! [file exists /proc/net/ip_fwnames ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_fwnames"
	}
	if { ! [file exists /proc/net/ip_masquerade ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_masquerade"
	}
	if { ! [file exists /proc/net/ip_masq ] } {
	    incr badconf
	    puts "bad kernel : no /proc/net/ip_masq"
	}
	if { ! [file exists $Extern(ipchains) ] } {
	    incr badconf
	    puts "program missing : ipchains"
	}
    }
    if { ! [file exists $Extern(ifconfig) ] } {
	incr badconf
	puts "program missing : ifconfig"
    }
    if { ! [file exists $Extern(insmod) ] } {
	incr badconf
	puts "program missing : insmod"
    }
    if { ! [file exists $Extern(rmmod) ] } {
	incr badconf
	puts "program missing : rmmod"
    }
    if { ! [file exists $Extern(runlevel) ] } {
	incr badconf
	puts "program missing : runlevel"
    }
    set fid ""
    catch {set fid [open "/proc/sys/net/ipv4/ip_forward" r]} err
    if { ![ string length $fid ] } {
	return {}
    } 
    gets $fid flag
    close $fid
    if { $flag != 1 } {
	incr badconf
	puts "bad kernel config : ip_forward switch =  off "
    }

    if { $badconf } {
	tk_messageBox -icon warning -title $Messages(warning) \
		-message $Messages(sysnook)
	set Status(systemok) 0
    } else {
	set Status(systemok) 1
    }
   
}

########################################################
# On line Help 
#########################################################

proc Help {head file} {
    global easyfwlib Config

    set fhlp [file join $easyfwlib doc "$file.$Config(lng)" ]
    if [ file isfile $fhlp] {
	ShowHelp "$head :" $fhlp
    } else {
	set fhlp [file join $easyfwlib doc "$file.GB" ]
	if [ file isfile $fhlp] {
	    ShowHelp "$head :" $fhlp
	}
    }
}

proc ShowHelp {head file} {
 global Messages

 if { ! [ winfo exists .onlhelp ] } {
   toplevel .onlhelp
   label .onlhelp.head -text "head" -anchor nw -pady 4 -foreground yellow
   pack .onlhelp.head -side top -fill x
   button .onlhelp.xit -text "$Messages(ok)" -command {destroy .onlhelp}
   pack .onlhelp.xit -side bottom -pady 4
   scrolled2text .onlhelp.fh -borderwidth 0
   pack .onlhelp.fh -side top -expand 1 -fill both

   wm title .onlhelp $Messages(htitle) 
   wm geometry .onlhelp 550x500
 }

 set fid [open $file r]
 if [ string length $fid ] {
   .onlhelp.fh.txt delete 0.0 end  
   .onlhelp.head configure -text $head
   gets $fid line
   while { ! [eof $fid] } {
     .onlhelp.fh.txt insert end "$line\n"
     gets $fid line
   }
   close $fid
 }

}

#########################################################
# configuration stuff
#########################################################
proc InitDefaultConfig {} {
    global Config Extern

    set Config(linkio) 0
    set Config(lng) "GB"
    set Config(automskmod) "no"

    set tmpl {}
    foreach mod [glob -nocomplain $Extern(mmodpath)] {
	lappend tmpl [file rootname [file tail $mod]]
    }
    set Config(masqmods) $tmpl
}

proc WriteConfig {} {
    global Config Extern

    set fid [open $Extern(easyrc) w]
    puts $fid "# easyfw generated config file"
    puts $fid "#"

    set clst [array names Config]
    foreach elem $clst {
	puts $fid "set Config($elem) \{$Config($elem)\}"
    }
    close $fid
}

proc ReadConfig {} {
    global Config Extern

    source $Extern(easyrc)
}

########################################################
#
# ipfwadm/ipchain mode stuff
#
#########################################################

proc GetMode {} {
    global tcl_platform

    if { ! [regexp {2\.([0-9])\.([0-9]+)} $tcl_platform(osVersion) all n0 n1] } {
	puts "bad kernel version, aborting !"
	exit 1
    } 
    if { $n0 == 0 } {
	return "ipfwadm"
    }
    if { $n0 >= 2 } {
	return "ipchains"
    }
    if { $n0 == 1 } {
	if { $n1 >= 162 } {
	    return "ipchains"
	} else {
	    return "ipfwadm" 
	}
    }
    puts "bad kernel version, aborting !"
    exit 1
}

########################################################
#
# MAIN 
#
#########################################################

set Mode [GetMode]

InitDefaultConfig
if { ![ file exists $Extern(easyrc) ]} {
    WriteConfig
} else {
    ReadConfig
}

ReadMessagesFile

CreateWidgets

set ind 0
while {$ind < $argc} {
    switch -exact -- [lindex $argv $ind] {
	"-o" {
	    incr ind
	    .banner.banL.adr.eip insert end [lindex $argv $ind]
	    incr ind
	}
	"-i" {
	    incr ind
	    .banner.banR.adr.eip insert end [lindex $argv $ind]
	    incr ind
	}
	default {
	    Usage
	}
    }
}

VerifSystemConfig

ReadRulesFromIpUtils

