# save.tcl
# Copyright (c) 2003 Digi International Inc., All Rights Reserved
# 
# This software contains proprietary and confidential information of Digi
# International Inc.  By accepting transfer of this copy, Recipient agrees
# to retain this software in confidence, to prevent disclosure to others,
# and to make no use of this software other than that for which it was
# delivered.  This is an unpublished copyrighted work of Digi International
# Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
# prohibited.
# 
# Restricted Rights Legend
#
# Use, duplication, or disclosure by the Government is subject to
# restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
# Technical Data and Computer Software clause at DFARS 252.227-7031 or
# subparagraphs (c)(1) and (2) of the Commercial Computer Software -
# Restricted Rights at 48 CFR 52.227-19, as applicable.
#
# Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
#
# ***************************************************************************

namespace eval Save {
    variable strPassword dbps
}

proc Save::MainGuts {w} {
    variable numProgress
    variable numMax 100
    variable arrSettings
    variable strMAC
    variable strProgress
    variable Tab1st
    set numProgress 0
    set strProgress [mc save.body.saving]
    set ::Fail::strType nofail
    set strMAC $::Discover::arrSettings(MAC)
    set frmMain $w.frmsave
    if {![winfo exists $frmMain]} {
        frame $frmMain
        BuildPage $frmMain
        grid $frmMain -row 0 -column 0 -sticky news \
         -padx [expr $::numTitleBoldXPad + $::numBorderWidth] -pady 5
    }
    raise $frmMain
    set ::Tab1st $Tab1st
    bind $::Tab1st <<ShiftTab>> {focus $::btnHelp;break}
    ##If the user entered a new IP address, let's see if it's in use
    if {$::Config::arrSettings(IP) != $::Discover::arrSettings(IP)} {
        if {[::Valid::DGping $::Config::arrSettings(IP)]} {
            set msg "$::Config::arrSettings(IP) is already in use by another device.  Are you sure?"
            set ans [tk_messageBox -type yesno -icon warning -parent . -default no \
             -title "Are You Sure?" \
             -message $msg]
            if {[string equal $ans "no"]} {
                set ::Fail::strType ipinuse
                return 0
            }
        }
    }
    set ret [AddpSet]
    ##Reset the data in case user uses back button to change settings
    global arrTemp
    array set arrTemp {}
    ::MainGetSettings $strMAC ::arrTemp
    if {[info exists arrTemp(IP)]} {
        array set ::Discover::arrSettings [array get arrTemp]
    }
    return $ret
}

proc Save::BuildPage {w} {
    variable Tab1st
    set numProgHeight 20
    set lblHeading $w.lblheading
    ::LabelHeading $lblHeading [mc save.body.heading $::Discover::arrSettings(Hardware)]
    set lblProg [label $w.lblprog -text [mc save.body.saving] -textvariable ::Save::strProgress]
    set prgProg [ProgressBar $w.prgprog -maximum $::Save::numMax -variable ::Save::numProgress \
     -type normal -width [expr $::numTitleDetailWraplength] -height $numProgHeight]
    set lblContinue [label $w.lblcont -text [mc save.tocontinue] -font fontRegularBold]
    grid $lblHeading -row 0 -column 0 -sticky nw 
    grid $lblProg -row 1 -column 0 -sticky nw
    grid $prgProg -row 2 -column 0 -sticky nw 
    grid $lblContinue -row 3 -column 0 -sticky sw
    grid columnconfigure $w 0 -weight 1
    grid rowconfigure $w 3 -weight 1
    set Tab1st $::btnStart
}

proc Save::GetSettings {strMAC} {
    ::MainGetSettings $strMAC ::Save::arrSettings
}

proc Save::AddpSet {} {
    variable boolNeedReboot
    set strFail ""
    set boolNSuccess 0
    set boolWSuccess 0
    set boolBSuccess 0
    set boolFSuccess 0
    set boolSuccess 1
    set boolNeedReboot 0
    set strOldIP $::Discover::arrSettings(IP)
    
    if {$::boolIsWireless} {
        set boolWSuccess [AddpSetWireless]
        if {!$boolWSuccess} {
            set ::Fail::strType setwirelessfail
        }
        set boolSuccess $boolWSuccess
        ## Give a second for the device to take the data
        after 1000
    }
append ::strDebug "\n1:Fail:$::Fail::strType boolSuccess:$boolSuccess"
    
    set boolNSuccess [AddpSetNetwork]
    if {$boolSuccess} {
        set boolSuccess $boolNSuccess
    }
    
append ::strDebug "\n2:Fail:$::Fail::strType boolSuccess:$boolSuccess"    
    
    if {[string equal $::Config::arrSettings(DHCP) "On"]} {
        set boolNeedReboot 1
    }
    if {$boolSuccess && $boolNeedReboot} {
        set boolBSuccess [Reboot]
        set boolSuccess $boolBSuccess
    } elseif {$boolSuccess && $boolWSuccess} {
        ## Only Wireless changes need a reboot
        ## This situation is very unlikely
        set boolWBSuccess [Reboot]
        if {!$boolWBSuccess} {
            set ::Fail::strType wirelessrebootfail
            set ::Fail::lstArgs $::Config::arrSettings(IP)
        }
        set boolSuccess $boolWBSuccess
    } elseif {!$boolSuccess && $boolNSuccess && $boolNeedReboot && $::boolIsWireless && !$boolWSuccess} {
        ## Wireless failure won't prevent reboot if there were network changes.
        [Reboot]
        ## boolSuccess = 0 
    }

    if {$boolSuccess} {
        set boolFSuccess [Refresh]
        set boolSuccess $boolFSuccess
    }
    
    return $boolSuccess
}

proc Save::AddpSetNetwork {} {
    set ::Save::strProgress [mc save.body.savingip]; update; after 500
    variable strPassword
    variable numProgress
    variable numMax
    variable strMAC
    variable boolNeedReboot
    incr numProgress 10
    
    set cmd [list exec -- $::pathAddp -S -m $strMAC]
    if {[string equal $::Config::arrSettings(DHCP) "Off"]} {
        foreach varName {IP Submask Gateway} {
            set str$varName $::Config::arrSettings($varName)
        }
        if {"$strGateway" == "..."} {
            set strGateway "0.0.0.0"
        }
        lappend cmd -a $strIP -s $strSubmask -g $strGateway
        if {![string equal $::Discover::arrSettings(IP) "0.0.0.0"]} {
            set boolNeedReboot 1
        }
    } else {
        lappend cmd -d On
        set boolNeedReboot 1
    }
    lappend cmd -p $strPassword
append ::strDebug \n$cmd
    catch {eval $cmd} strReply
    switch -regexp -- $strReply {
        "succeeded" {
            set boolAssignSuccess 1
        }
        "Authentication" {
            set ans [GetPassword]
            if {"$ans" == "ok"} {
                set ::Fail::strType newpassword
            } else {
                set ::Fail::strType authentication
            }
            set boolAssignSuccess 0
        }
        "Failed" {
            set ::Fail::strType addpassign_failed
            set ::Fail::lstArgs [list $strReply]
            set boolAssignSuccess 0
        }
        default {
            set ::Fail::strType addpunrecognized
            set ::Fail::lstArgs [list $strReply]
            set boolAssignSuccess 0
        }
    }
append ::strDebug "\nSave::AddpSetNetwork:strReply:$strReply\nAssignSuccess:$boolAssignSuccess"
    return $boolAssignSuccess
}

proc Save::AddpSetWireless {} {
    set ::Save::strProgress [mc save.body.savingwless]; update; after 500
    variable strPassword
    variable numProgress
    variable numMax
    variable strMAC
    incr numProgress 5
    
    set cmd [list exec -- $::pathAddp -W -m $strMAC]
    if {[string equal $::Config::arrSettings(AutoSSID) "Off"]} {
        lappend cmd -i $::Config::arrSettings(DesiredSSID)
        set strTemp Off
    } else {
        set strTemp On
    }
    lappend cmd -I $strTemp
    set boolKey 0
    if {[string equal $::Config::arrSettings(EncryptionMode) "Disabled"]} {
        set strEncr "none"
    } else {
        set boolKey 1
        if {[string equal $::Config::arrSettings(WEP) "WEP40"]} {
            set strEncr 64
        } else {
            set strEncr 128
        }
    }
    if {[string equal $::Config::arrSettings(AuthMode) "Open"]} {
        set strAuth open
    } else {
        set strAuth shared
        set boolKey 1
    }
    if {$boolKey} {
        lappend cmd -e $strEncr -A $strAuth -k $::Config::arrSettings(EncryptionKey)
    } else {
        lappend cmd -e $strEncr -A $strAuth
    }
    lappend cmd -c $::Config::arrSettings(Country) -p $strPassword
append ::strDebug \n$cmd
    catch {eval $cmd} strReply
    switch -regexp -- $strReply {
        "succeeded" {
            set boolAssignSuccess 1
        }
        "Authentication" {
            set ::Fail::strType w_authentication
            set boolAssignSuccess 0
        }
        "Failed" {
            set ::Fail::strType w_addpassign_failed
            set boolAssignSuccess 0
        }
        default {
            set ::Fail::strType w_addpassign_unrecognized_response
            set boolAssignSuccess 0
        }
    }
append ::strDebug  "\nSave::AddpSetWireless:Wireless:strReply:$strReply\nAssignSuccess:$boolAssignSuccess"
    return $boolAssignSuccess
}

proc Save::Reboot {} {
    set ::Save::strProgress [mc save.body.reboot]
    variable strMAC
    variable strPassword
    variable numMax
    variable numProgress
    set numBootTime 10
    set numRebootIncr [expr $numMax/40]
    catch {exec -- $::pathAddp -R \
     -m $strMAC \
     -p $strPassword} strBootReply
append ::strDebug "\nBootReply:$strBootReply"
    # Some devices do not reply to reboot commands, but they do reboot.
    if {![string match *Failed* $strBootReply]} {
        ##Give the device time to cycle
        for {set i 0} {$i < $numBootTime} {incr i} {
            after 1000
            incr numProgress $numRebootIncr
        }
        set ret 1
    } else {
        set ret 0
    }
    return $ret
}

proc Save::Refresh {} {
    set ::Save::strProgress [mc save.body.wait]
    variable strMAC
    variable strPassword
    variable numMax
    variable numProgress
    set timeout 60
    set boolRefreshed 0
    set boolSuccess 0
    set numPingTO 10
    ## These vars control the speed of the progres bar
    set numRefreshIncr [expr $numMax/70]
    set numPingIncr [expr $numMax/50]

    ## Lets try ADDP before trying to ping
    after 1000; incr numProgress $numPingIncr
    set count 0
    set numOldTime [clock seconds]
    while {$count <= $timeout} {
        GetSettings $strMAC
        if {[info exists ::Save::arrSettings(IP)]} {
            if {[string equal $::Config::arrSettings(DHCP) "On"]} {
                ## Wait for DHCP server to assign IP address
                if {[string equal $::Save::arrSettings(IP) "0.0.0.0"]} {
                    after 1000
                } else {
                    ## The device is reporting it's new settings
                    set boolRefreshed 1
                    break
                }
            } else {
                ## The device is reporting it's new settings
                set boolRefreshed 1
                break
            }
        }
        set numCurTime [clock seconds]
        set numElapsedTime [expr $numCurTime - $numOldTime]
        set numIncr [expr $numRefreshIncr * $numElapsedTime]

        incr numProgress $numIncr
        incr count $numElapsedTime
        set numOldTime $numCurTime
    }
append ::strDebug "\nboolRefreshed:$boolRefreshed count:$count timeout:$timeout"
    ## Ping the device
    if {$boolRefreshed} {
        if {[Valid::DGping $::Save::arrSettings(IP) $numPingTO]} {
            set boolSuccess 1
        } else {
            set boolSuccess 0
            set ::Fail::strType unpingable
        }
    } else {
        set boolSuccess 0
        if {[info exists ::Save::arrSettings(IP)] && \
         [string equal $::Config::arrSettings(DHCP) "On"]} {
            set ::Fail::strType dhcptimeout
        } else {
            set ::Fail::strType unrefreshed
        }
    }
    return $boolSuccess
}

proc Save::GetPassword {} {
    variable strPassword
    set strReply ""
    set d [toplevel .dialog -borderwidth 8]
    wm transient $d .   
    wm resizable $d 0 0
    wm title $d [mc getpassword.title]
    set lblMsg [label $d.lblmsg -wraplength 300 \
        -text [mc getpassword.msg]]
    set entPass [entry $d.entpass -show * -textvariable ::Save::strPassword \
     -validate key -validatecommand {::Save::ValidPWChar %S %W %v}]
    set btnOK [button $d.btnok -text [mc OK] \
        -width 8 -relief raised -default active \
        -command "set ::strReply ok;destroy $d"]
    set btnCancel [button $d.btncancel -text [mc Cancel] \
        -width 8 -relief raised -command "set ::strReply cancel;destroy $d"]
    grid $lblMsg -padx 5 -pady 5 -columnspan 2
    grid $entPass -padx 5 -pady 5 -columnspan 2
    grid $btnOK $btnCancel -padx 5 -pady 5
    
    bind $d <Return> [list tkButtonInvoke $btnOK]
    focus $entPass
    tkwait visibility $d
    ::window::center $d
    grab set $d
    tkwait window $d
    grab release $d
    return $::strReply
}

proc Save::ValidPWChar {char W v} {
    ##From the Tcl/Tk entry man page
    after idle [list $W config -validate $v]

    set ret [regexp -- {[A-Za-z0-9_]} $char]
    return $ret
}
