#!/usr/bin/wish -f
#
# tcl/tk script to aid with administrative overview of
# log files and such things.
#
# Written by Allin Cottrell (cottrell@wfu.edu), February 1998.

set syslog "/var/log/syslog"
set messages "/var/log/messages"
set debug "/var/log/debug"
set maillog "/var/log/maillog"
set xferlog "/var/log/xferlog"
set httperr "/usr/local/etc/httpd/logs/error_log"
set smblog "/usr/local/samba/var/log.smb"
set nmblog "/usr/local/samba/var/log.nmb"
set tmpfile "/tmp/tkadmin_tmp"

set login_cmd { exec echo "Last 10 logins:" >$tmpfile ;
                exec last -10 >>$tmpfile ;
		exec echo >>$tmpfile;
		exec echo "Last 5 bad login attempts:" >>$tmpfile ;
                exec lastb -5 >>$tmpfile }
set smb_list_cmd { exec smbclient -L localhost -N >$tmpfile }
set ps_cmd { exec ps aux >$tmpfile }
set misc_cmd { exec echo "w:" >$tmpfile 
               exec w >>$tmpfile
	       exec echo -n "\ndf:\n" >>$tmpfile 
               exec df >>$tmpfile 
	       exec echo -n "\nfree:\n" >>$tmpfile
	       exec free >>$tmpfile }

catch { exec uname -a } hostinfo

global tmpfile login_cmd smb_list_cmd


wm title . "tkAdmin"

# Main section of program

   # Set up frames, buttons

   frame .f1 -relief flat -borderwidth 2
   frame .f2 -relief flat -borderwidth 2
   frame .f3 -relief flat -borderwidth 2
   frame .f4 -relief flat -borderwidth 2
   frame .f5 -relief flat -borderwidth 2
   
   message .msg0 -text $hostinfo -width 250
   message .msg1 -text "Basics:" -width 100 -font fixed
   message .msg2 -text "Internet:" -width 100 -font fixed
   message .msg3 -text "Samba:" -width 100 -font fixed
   message .msg4 -text "Other:" -width 100 -font fixed
   
   button .f1.syslog -text "syslog" -width 10 \
       -command "display .syslog $syslog null" -relief groove 
   button .f1.messages -text "messages" -width 10 \
       -command "display .messages $messages null" -relief groove 
   button .f1.debug -text "debug" -width 10 \
       -command "display .debug $debug null" -relief groove 
   
   button .f2.maillog -text "maillog" -width 10 \
       -command "display .maillog $maillog null" -relief groove 
   button .f2.xferlog -text "xferlog" -width 10 \
       -command "display .xferlog $xferlog null" -relief groove
   button .f2.httperr -text "http errors" -width 10 \
       -command "display .httperr $httperr null" -relief groove
         
   button .f3.smblog -text "log.smb" -width 10 \
       -command "display .smblog $smblog null" -relief groove 
   button .f3.nmblog -text "log.nmb" -width 10 \
       -command "display .nmblog $nmblog null" -relief groove 
   button .f3.listing -text "smb listing" -relief groove -width 10 \
       -command "display .smbclient_listing $tmpfile \$smb_list_cmd"             

   button .f4.logins -text "logins" -width 10 -relief groove \
       -command "display .logins $tmpfile \$login_cmd"
   button .f4.ps -text "processes" -width 10 -relief groove \
        -command psaux
#       -command "display .ps $tmpfile \$ps_cmd"
   button .f4.finger -text "w, etc" -width 10 -relief groove \
       -command "display .finger $tmpfile \$misc_cmd"

   button .f5.dismiss -text " Dismiss " \
       -command "exec rm -f $tmpfile ; destroy ." -relief groove

   # Pack stuff into place

   pack .msg0 -side top 
   pack .msg1 -side top -anchor w -pady 5
   pack .f1 -side top -padx 10 -expand 1 -fill both
   pack .msg2 -side top -anchor w -pady 5
   pack .f2 -side top -padx 10 -expand 1 -fill both 
   pack .msg3 -side top -anchor w -pady 5
   pack .f3 -side top -padx 10 -expand 1 -fill both
   pack .msg4 -side top -anchor w -pady 5
   pack .f4 -side top -padx 10 -expand 1 -fill both
   pack .f5 -side top -padx 10 -expand 1 -fill both
   
   pack .f1.syslog -side left 
   pack .f1.messages -side left 
   pack .f1.debug -side left 
   pack .f2.maillog -side left 
   pack .f2.xferlog -side left 
   pack .f2.httperr -side left
   pack .f3.smblog -side left 
   pack .f3.nmblog -side left 
   pack .f3.listing -side left
   pack .f4.logins -side left
   pack .f4.ps -side left
   pack .f4.finger -side left

   pack .f5.dismiss -side left -pady 15 -expand yes
   
   set blue "-foreground blue"
   set red "-foreground red"
   set cyan "-background cyan"
   set normal "-background {}"
  

# Procedure to display contents of a file -- last parameter gives
# an action to be performed before the file is displayed.
 
proc display { w file action } {
    global contents numLines myfile mywindow
    global tmpfile readfile myaction abort
    set myfile $file
    set myaction $action
    set mywindow $w
    toplevel $w
    dpos $w
    wm title $w $file
    set abort 0
    
    set readfile { if { "$myaction" != "null" } { eval $myaction }
                   set abort 0
                   if ![file exists $myfile] then { 
		      set abort 1 
		   } else {
                     set contents [ open $myfile r ]
   		     $mywindow.t.text configure -state normal
		     $mywindow.t.text delete 0.0 end
                     $mywindow.t.text insert 0.0 [ read $contents ] 
                     close $contents 
                     $mywindow.t.text configure -state disabled 
		     # $mywindow.t.text configure -wrap none
                     $mywindow.t.text yview moveto 1   
                     $mywindow.t.text tag configure search -background cyan }
		  }

    frame $w.string
    label $w.string.label -text " Search string:" -width 13 -anchor w
    entry $w.string.entry -width 40 -relief sunken -bd 2 \
	    -textvariable searchString
    button $w.string.hi -text "Highlight" -width 10 -relief groove \
	    -command "TextSearch $w.t.text \$searchString search"
    button $w.string.next -text "Go to next" -width 10 -relief groove \
            -command "\
            set pos \[ lindex \[ $w.t.text yview \] 0 \]
            set pos \[ expr int(\$pos * \$numLines) + 20 \]
            set nextfind \[ $w.t.text search \$searchString \$pos.0 \]
            $w.t.text yview \$nextfind"
    pack $w.string.label $w.string.entry -side left
    pack $w.string.hi -side left -pady 5 -padx 10
    pack $w.string.next -side left -pady 5 
    bind $w.string.entry <Return> "TextSearch $w.t.text \$searchString search"
    pack $w.string -side top -fill x -padx 5 -pady 5

    frame $w.t -relief groove -borderwidth 2
    pack [scrollbar $w.t.scroll -width 4m -command "$w.t.text yview" \
        -relief sunken -borderwidth 2] -side right -fill y

    pack [text $w.t.text -relief flat \
        -setgrid 1 -yscroll "$w.t.scroll set"] \
        -side top -fill both -expand 1 -padx 5 -pady 5
    pack $w.t -side top -padx 10  -expand 1 -fill both
    frame $w.c -relief flat -borderwidth 2
    pack [button $w.c.dismiss -text Dismiss -width 12 -relief groove \
        -command "destroy $w"] \
        -side left -anchor c -expand 1 -pady 5
    pack [button $w.c.refresh -text Refresh -width 12 -relief groove \
        -command { eval $readfile }] \
        -side left -anchor c -expand 1 -pady 5    
    pack $w.c -side top -fill x -padx 10 -pady 5
    eval $readfile
    if { $abort != "0" } then { no_file $w $myfile }

}


proc TextSearch {w string tag} {
    global numLines
    $w tag remove search 0.0 end
    scan [$w index end] %d numLines
    set l [string length $string]
    for {set i 1} {$i <= $numLines} {incr i} {
        if {[string first $string [$w get $i.0 $i.1000]] == -1} {
            continue
        }
        set line [$w get $i.0 $i.1000]
        set offset 0
        while 1 {
            set index [string first $string $line]
            if {$index < 0} {
                break
            }
            incr offset $index
            $w tag add $tag $i.[expr $offset] $i.[expr $offset+$l]
            incr offset $l
            set line [string range $line [expr $index+$l] 1000]
        }
    }
    $w yview search.first
}



proc psaux {} {

   set w ".psaux"
   toplevel $w
   dpos $w
   
   frame $w.f1 -relief groove -borderwidth 2
  
   message $w.msg -text "Button 2 to kill, button 3 to kill -9" \
       -justify center -aspect 2000
   pack $w.msg -side top -fill x -pady 5

    frame $w.string
    label $w.string.label -text " Search string:" -width 13 -anchor w
    entry $w.string.entry -width 40 -relief sunken -bd 2 \
	    -textvariable searchString
    button $w.string.hi -text "Highlight" -width 10 -relief groove \
	    -command "TextSearch $w.f1.t \$searchString search"
    button $w.string.next -text "Go to next" -width 10 -relief groove \
            -command "\
            set pos \[ lindex \[ $w.f1.t yview \] 0 \]
            set pos \[ expr int(\$pos * \$numLines) + 20 \]
            set nextfind \[ $w.f1.t search \$searchString \$pos.0 \]
            $w.f1.t yview \$nextfind"
    pack $w.string.label $w.string.entry -side left
    pack $w.string.hi -side left -pady 5 -padx 10
    pack $w.string.next -side left -pady 5 
    bind $w.string.entry <Return> "TextSearch $w.f1.t \$searchString search"
    pack $w.string -side top -fill x -padx 5 -pady 5
    
   text $w.f1.t  -yscrollcommand "$w.f1.s set" -relief flat \
      -setgrid true 
   scrollbar $w.f1.s -width 4m -relief sunken -command "$w.f1.t yview"

   pack $w.f1 -side top -padx 10 -expand 1 -fill both

   # commands frame
   frame $w.c -relief flat -borderwidth 2
   pack [button $w.c.dismiss -text Dismiss -width 12 -relief groove \
        -command "exec rm -r /tmp/psaux ; destroy $w"] \
        -side left -anchor c -expand 1 -pady 5
   pack [button $w.c.refresh -text Refresh -width 12 -relief groove \
        -command { fill_psaux .psaux }] \
        -side left -anchor c -expand 1 -pady 5    
   pack $w.c -side top -fill x -padx 10 -pady 5

   pack $w.f1.s -side right -fill y
   pack $w.f1.t -fill both -expand 1 -padx 5 -pady 5
    
   set numLines 0
   $w.f1.t tag configure search -background cyan
   
   fill_psaux .psaux
   
}

proc fill_psaux { w } {

   exec ps aux >/tmp/psaux
   set info [ open /tmp/psaux r ]

   set blue "-foreground blue"
   set red "-foreground red"
   set cyan "-background cyan"
   set normal "-background {}"

   $w.f1.t configure -state normal
   $w.f1.t delete 0.0 end
   gets $info line
   $w.f1.t insert insert "$line\n"
   while { [ gets $info line ] >= 0 } {
         scan $line "%s %s %s" own pid rest
         lappend pidlist $pid
	 lappend linelist $line
   }

   set n [ llength $pidlist ]

   for {set i 0} {$i < $n} {incr i} {
        lappend taglist1 "$i"
        set start [ $w.f1.t index insert ]
        $w.f1.t insert insert "[ lindex $linelist $i ] "
	$w.f1.t insert insert "\n"
        foreach tag [ $w.f1.t tag names $start ] {
	   $w.f1.t tag remove $tag $start insert
         }
        $w.f1.t tag add [ lindex $taglist1 $i ] $start insert 
         set start [ $w.f1.t index insert ]  
        foreach tag [ $w.f1.t tag names $start ] {
	   $w.f1.t tag remove $tag $start insert
         }           
        $w.f1.t tag bind [ lindex $taglist1 $i ] <Any-Enter> \
            "$w.f1.t tag configure [lindex $taglist1 $i] $cyan"  
        $w.f1.t tag bind [ lindex $taglist1 $i ] <Any-Leave> \
            "$w.f1.t tag configure [ lindex $taglist1 $i ] $normal" 
        $w.f1.t tag bind [ lindex $taglist1 $i ] <2> \
            "$w.f1.t tag configure [ lindex $taglist1 $i ] $red
             exec kill [ lindex $pidlist $i ]"
        $w.f1.t tag bind [ lindex $taglist1 $i ] <3> \
            "$w.f1.t tag configure [ lindex $taglist1 $i ] $red
             exec kill -9 [ lindex $pidlist $i ]"
    } 
    $w.f1.t configure -state disabled
}

proc no_file { parent file } {
       destroy $parent
       set w ".no_file"
       toplevel $w
       pack [ label $w.b -bitmap error ]
       pack [ label $w.err -text "Sorry, can't find $file" ]
       button $w.dismiss -text "Dismiss" \
         -command "set abort 1 ; destroy $w" -relief groove
       pack $w.dismiss -side top
       tkwait variable abort
       return
}

proc dpos w {
    wm geometry $w +150+120
}

