# innadmin.tcl
#
# Handle Inn control messages and such from within exmh
#
# Gareth Owen (oweng@aston.ac.uk) v970414 
#


#
# Initialise diverse variables
#
proc Init_InnAdmin {} {

    global INN env NNTP

    set INN(host) $NNTP(host)
    set INN(port) $NNTP(port)
    set INN(user) news

# Where the control executables reside on the news server
    set INN(ctlpath) /usr/local/news/bin/control
# Where other executables reside
    set INN(binpath) /usr/local/news/bin
# Inn config file directory
    set INN(cfgpath) /usr/local/news/etc
# If set , run this  after a rmgroup with command line argument the group name
# This one deletes directories and files as necessary
#    set INN(rmtidy)  /usr/local/news/local/getrid
#  file prefix to use for local files (currently just $INN(prefix).newsgroups)
    set INN(prefix) $env(HOME)/inn/inn
# Address to use for creator when creating groups from unwanted list or control messages
    set INN(creator) $NNTP(moderator)
# directory where user created control messages are saved - fully qualified path
    set INN(ctrlf) $env(HOME)/inn

}


# InnExecMsg
#
# exec Inn control messages
#
proc InnExecMsg {} {

    global INN

    if {[info exists INN(host)]==0}  Init_InnAdmin

    set msg [.msg.t get 0.0 end]

    if {[string first "Subject: newgroup" $msg] > -1} {
## Newgroup
	if [regexp \
"To do this, type the following:\n\[\t \]*(\[^\t \]+)\[\t \]+(\[^\t \]+)\[\t \]+(\[^\t\n \]+)\[\t \]+(\[^\t \])\[\t \]+(\[^\n\]+)"\
		$msg match binary cmd group mod email] {
	    set result [busy exec rsh -l $INN(user) -n $INN(host) \
			    $binary $cmd $group $mod $email]
	    if [regexp \
		    "\nFor your newsgroups file:\n*($group\[\t ]+\[^\n\]+)\n" \
		    $msg match newgroup] {
		set ngf [open "$INN(prefix).newsgroups" a+]
		puts $ngf "+$newgroup"
		close $ngf
	    }
	    set result "Newgroup $group : $INN(host) says $result"
	} else {
	    set result "Can't find newgroup command to execute"
	}
   } elseif {[string first "Subject: rmgroup" $msg] > -1} {
## Rmgroup
	if [regexp \
		"To do this, type the following:\n\[\t \]*(\[^\t \]+)\[\t \]+(\[^\t \]+)\[\t \]+(\[^\t\n \]+)"\
		$msg match binary cmd group] {
	    set result [busy exec rsh -l $INN(user) -n $INN(host) \
			    $binary $cmd $group]
	    set result \
		"RmGroup $group : $INN(host) says $result"
	    if [info exists $INN(rmtidy)] {
		set result [busy exec rsh -l $INN(user) -n $INN(host) \
				$rmtidy $group]
		# should I do anything with this result ?
	    }
	    set group [string trim $group "\""]
	    set ngf [open $INN(prefix).newsgroups a+]
	    
	    puts $ngf "-$group"
	    close $ngf
	} else {
	    set result "Can't find rmgroup command to execute"
	}
    } elseif {[string first "Subject: checkgroups" $msg] > -1} {
## Checkgroup
	Exmh_Status "Executing Checkgroups control message - please wait ..."
	regexp "userid:\n\n(\[^\<\]+)\<\<-EOF-\n(.*)" $msg match cmd text
	# strip off -EOF-'here' tags  so don't have to worry about what shell it's going to be executed by
	set gorffan [string last "-EOF-" $text]
	incr gorffan -1
	set text [string range $text 0 $gorffan]
	set result [busy exec rsh -l $INN(user) $INN(host) $cmd << $text ]
	set result [InnChkGrp $result]
    } elseif {[regexp "\[Dd\]aily \[Uu\]senet \[Rr\]eport" $msg]} {
# option of creating groups in the unwanted list of the daily report
	set s [string first "Top 20 unwanted newsgroups:\n " $msg]
	if {$s > -1} {
	    incr s 28
	    set result [InnMakeUnwanted "[string range $msg $s end]"]
	} else {
	    set result "No unwanted groups"
	}
    } else {
	set result "Can't find anything Innish to chew on"
    }
    Exmh_Status $result
    return 
}

#
# display results of checkgroup message
#
proc InnChkGrp {msg} {

    global INN

    if [Exwin_Toplevel .chkgrp "Checkgroups Result" CheckGroup] {
	
	.chkgrp.but.quit config -command InnChkGrp_dismiss
	
	wm protocol .chkgrp -command InnChkGrp_dismiss
	
	frame .chkgrp.res -borderwidth 2
	pack .chkgrp.res -expand yes -fill both
        text .chkgrp.res.t -yscrollcommand {.chkgrp.res.sb set} \
	    -height 30 -wrap word -width 80 
	pack .chkgrp.res.t -expand yes -fill both -side left
	scrollbar .chkgrp.res.sb -command {.chkgrp.res.t yview}
	pack .chkgrp.res.sb -side right -fill y
    }
    set count 0
    set addflag 0
    set changeflag 0
    set removeflag 0

    foreach i [split $msg \n] {
	if {[string first ctlinnd $i] > -1 } {
	    set i "$INN(binpath)/[string trim $i]"
	    button .chkgrp.res.t.but$count -text "$i" -command \
		  "InnExecNewGroup $count \"$i\"" \
		  -cursor top_left_arrow
	    .chkgrp.res.t window create end \
		  -window .chkgrp.res.t.but$count
	    .chkgrp.res.t insert end "\n"
	    incr count
	} elseif {[string first "\# Add these lines:" $i]==0} {
	    set addflag 1
	    .chkgrp.res.t insert end "$i\n"
	} elseif {[string first "\# Change these lines:" $i]==0} {
	    .chkgrp.res.t insert end "$i\n"
	    set changeflag 1
	} elseif {[string first "\#  Remove these lines:" $i]==0} {
	    .chkgrp.res.t insert end "$i\n"
	    set removeflag 1
	} elseif {$addflag} {
	    if [string length $i] {
		regexp "\#\[\t \]+(.+)" $i match line
		button .chkgrp.res.t.but$count -text "$i" -command \
		    "InnAddtoNewsgroups $count \"$line\"" \
		  -cursor top_left_arrow
	    .chkgrp.res.t window create end \
		  -window .chkgrp.res.t.but$count
	    .chkgrp.res.t insert end "\n"
	    incr count		
	    } else {
		set addflag 0
	    }
	} elseif {$changeflag} {
	    if [string length $i] {
		regexp "\#\[\t \]+(.+)" $i match line
		button .chkgrp.res.t.but$count -text "$i" -command \
		  "InnChangeNewsgroups $count \"$line\"" \
		  -cursor top_left_arrow
	    .chkgrp.res.t window create end \
		  -window .chkgrp.res.t.but$count
	    .chkgrp.res.t insert end "\n"
	    incr count		
	    } else {
		set changeflag 0
	    }
	} elseif {$removeflag} {
	    if [string length $i] {
		regexp "\#\[\t \]+(\[^\t \]+)" $i match group
		button .chkgrp.res.t.but$count -text "$i" -command \
		  "InnRemoveNewsgroups $count \"$line\"" \
		  -cursor top_left_arrow
	    .chkgrp.res.t window create end \
		  -window .chkgrp.res.t.but$count
	    .chkgrp.res.t insert end "\n"
	    incr count		
	    } else {
		set removeflag 0
	    }


	} else {
	    .chkgrp.res.t insert end "$i\n"
	}
    }
	
    return
}


#
# Write checkgroup additions to the newsgroup file to $INN(prefix).newsgroups
# and then disable button which invoked this
#
proc InnAddtoNewsgroups {count line} {

    global INN

    set ngf [open $INN(prefix).newsgroups a+]
    puts $ngf "+ $line"
    close $ngf
    .chkgrp.res.t.but$count configure -state disabled
    
}

#
# Write checkgroup chamges to the newsgroup file to $INN(prefix).newsgroups
# and then disable button which invoked this
#
proc InnChangeNewsgroups {count line} {

    global INN

    regexp "\#\[\t \]+(\[^\t \]+)" $line match group
    set ngf [open $INN(prefix).newsgroups a+]
    puts $ngf "+$line"
    close $ngf
   .chkgrp.res.t.but$count configure -state disabled
  
}

#
# Write checkgroup removals to the newsgroup file to $INN(prefix).newsgroups
# and then disable button which invoked this
#
proc InnRemoveNewsgroups {count line} {

    global INN

    set ngf [open $INN(prefix).newsgroups a+]
    puts $ngf "-$line"
    close $ngf
   .chkgrp.res.t.but$count configure -state disabled
  
}



#
# Execute newgroup commands in checkgroup results 
#  and then disable button which invoked this
#
proc InnExecNewGroup {count line} {

    global INN

    set result [busy exec rsh -l $INN(user) -n $INN(host) $line]
    Exmh_Status "Newgroup : $INN(host) says $result"
    .chkgrp.res.t.but$count configure -state disabled
}

#
# Checkgroup messages are few and far between so might as well destroy it as keep it
# hanging around
#
proc InnChkGrp_dismiss {} {

    destroy .chkgrp

}


#
# Display top 20 unwanted groups so a newgroup can be executed if wanted
#
proc InnMakeUnwanted {msg} {

    global INN

    if {[info exists INN(host)]==0} {
	Init_InnAdmin
    }
    if [Exwin_Toplevel .unwanted "\"Unwanted\" Groups" Unwanted] {
	
	.unwanted.but.quit config -command {destroy .unwanted}
	
	wm protocol .unwanted -command {destroy .unwanted}
	
	frame .unwanted.res -borderwidth 2
	pack .unwanted.res -expand yes -fill both
        text .unwanted.res.t -yscrollcommand {.unwanted.res.sb set} \
	    -height 30 -wrap word -width 80 
	pack .unwanted.res.t -expand yes -fill both -side left
	scrollbar .unwanted.res.sb -command {.unwanted.res.t yview}
	pack .unwanted.res.sb -side right -fill y
    }
  
    set s [string first "\n\n" $msg]
    incr s -1
    set unwanted [split [string range $msg 0 $s] \n]
    set count 0
    foreach u $unwanted {
	regexp "\[\t \]+\[0-9\]+\[ \t\]+(.*)" $u match group
	button .unwanted.res.t.but$count -text "$u" -command \
	    "InnWanted $count  $group" -cursor top_left_arrow
	.unwanted.res.t window create end \
		  -window .unwanted.res.t.but$count
	.unwanted.res.t insert end "\n"
	incr count		
    }
	
}

#
# newgroup a group from the Daily report's unwanted list
#
proc InnWanted {count group} {

    global INN

    set result [busy exec rsh -l $INN(user) -n $INN(host) \
		    $INN(binpath)/ctlinnd newgroup $group y $INN(creator)]
    Exmh_Status "Newgroup $group : $INN(host) says $result"
    .unwanted.res.t.but$count configure -state disabled
  
}


proc InnHelp {} {

# To come (maybe)

}


#
# Prompt for newsgroup to which control message applies
#
proc CtrlMsg {arg} {

    global INN

    set INN(ctrlmsg) $arg

    if [Exwin_Toplevel .ctrlmsg "$arg Control Message" CtrlMessage] {
	if {[info exists INN(ctrlf)]==0} Init_InnAdmin
	.ctrlmsg.but.quit config -command {Exwin_Dismiss .ctrlmsg}
	wm protocol .ctrlmsg WM_DELETE_WINDOW \
	    {Exwin_Dismiss .ctrlmsg}
	Widget_AddBut .ctrlmsg.but ok Ok "EditCtrlMsg {}"
	frame .ctrlmsg.res -borderwidth 2
	pack .ctrlmsg.res -expand yes -fill both
	label .ctrlmsg.res.l -text Newsgroup:
	entry .ctrlmsg.res.e -textvariable INN(group)
	pack .ctrlmsg.res.l .ctrlmsg.res.e -side left -anchor w
    }

    wm title .ctrlmsg "$arg Control Message"

}

#
# Create control message template and invoke sedit to edit it
#
proc EditCtrlMsg {filename} {

  global INN

  Exwin_Dismiss .ctrlmsg

  if [string length $filename] {
     Sedit_Start $filename
  } else {

    switch -exact $INN(ctrlmsg) {
	newgroup { set ngf "$INN(ctrlf)/newgroup[clock seconds]"
	           set outf [open $ngf w]
	           puts $outf "From: $INN(creator)"
	           puts $outf "Newsgroups: $INN(group).ctl"
	           puts $outf "Subject: cmsg newgroup $INN(group)"
	           puts $outf "Control: newgroup $INN(group)"
	           puts $outf "Approved: $INN(creator)\n"
	           puts $outf "For your newsgroups file:\n$INN(group)\t\n"
	           close $outf
	           Sedit_Start $ngf
	          .sedit$ngf.but.send configure -command "PostCtrlMsg $ngf" \
		       -text Post
	}
	rmgroup { set rgf "$INN(ctrlf)/rmgroup[clock seconds]"
	           set outf [open $rgf w]
	           puts $outf "From: $INN(creator)"
	           puts $outf "Newsgroups: $INN(group)"
	           puts $outf "Subject: cmsg rmgroup $INN(group)"
	           puts $outf "Control: rmgroup $INN(group)"
	           puts $outf "Approved: $INN(creator)\n"
	           close $outf
	           Sedit_Start $rgf
	          .sedit$rgf.but.send configure -command "PostCtrlMsg $rgf" \
		      -text Post
	}
	default {Exmh_Status "Only newgroup and rmgroup currently supported"}
    }
  } 
}


#
# Pass article to PostIt, If posting failed return to edit stage
#
proc PostCtrlMsg {filename} {

    global INN    

    SeditSave $filename .sedit$filename.f.t

    set artfile [open $filename r]
    set article [read $artfile]
    set result [PostIt "$article"]
    Exmh_Status $result
    if [string compare $result "Posted Successfully"] {
	EditCtrlMsg $filename
    } else {
	destroy .sedit$filename
    }
}


