#
# topicnazi.tcl v1.16 for Eggdrop 1.3.15 and higher 
#                     Dagmar d'Surreal -- dagmar@cyberjunkie.com
#
# $Source: /home/aphasia/eggdrop/scripts/RCS/topicnazi.tcl,v $
# $Date: 1998/06/05 03:22:07 $
# $Revision: 1.17 $

# The purpose of this script is to cut down on frivolous topic changes, and
# to reduce the importance of +o as a status symbol by allowing +v users (if
# you have any) to change the topic with the help of the bot.
#
# Pragmas:
#
#  * Channel topic may be changed by anyone with a voice or ops, provided
#   they are showing at least +v in the channel.  (CPU load would be too
#   high otherwise.)
#  * Channel topic may only be changed with a frequency of once every 60
#   seconds.
#  * Only masters, owners, or other bots may change a topic before the
#   60 second topic lock has expired.  (This *might* work on more than one
#   bot per channel at a time.)
#  * To discourage people from trying to 'race' the bot, users who attempt
#   to change the topic before the timer has expired will be thwarted and
#   reminded to wait however many seconds are left.
#  * Users will only be warned once per locking period, to avoid someone
#   trying to force the bot to flood itself off.
#  * To reduce the number of annoying bug reports from illiterates, the
#   absolute latest version of eggdrop (at the time of this writing) must be
#   used.
#
# Note:  I am not a racist, nor am I a totalitarian.  I am merely an anarchist
# who understands that if limitations on behaviour are to be enforced, they
# must be done so in the most impartial and unconditional manner possible.
# Fnord.
#
# BUGS FIXED SINCE 1.14
#  - Multiple bots running this script could wind up fighting over the
#   locked topic, even if it was the SAME topic.  Not pretty.
#  - If a master or owner overrode a topic lock, if someone else changed the
#   topic before the lock expired, the bot would put the original ORIGINAL
#   topic back into place.

set topicnaziver "TopicNazi v1.16"

if {![info exists numversion] || ($numversion < 1031500)} {
  putlog "*** Can't load $topicnaziver -- At least Eggdrop v1.3.15 required"
  return 0
}

proc topicnazi:kein_mitleid {} {
  global topicnazi_chanlock topicnazi_chantopic
  foreach {chan} [channels] {
    set chan [string tolower $chan] 
    set topic [topic $chan]
    set topicnazi_chantopic($chan) $topic
    topicnazi:unlock $chan
  }
}

proc topicnazi:join_chan {nick uhost hand chan} {
  # In a perfect world, the topic would come down with the join.  Oh well.
  topicnazi:unlock $chan
}

proc topicnazi:lock chan {
  global topicnazi_chanlock
  set topicnazi_chanlock($chan) 1
  set topicnazi_warnlist($chan) ""
}
  
proc topicnazi:unlock chan {
  global topicnazi_chanlock topicnazi_warnlist
  set topicnazi_chanlock($chan) 0
  set topicnazi_warnlist($chan) ""
}

proc topicnazi:topic_change {nick uhost hand chan topic} {
  global topicnazi_chantopic topicnazi_chanlock
  set chan [string tolower $chan]

  # If they didn't really change anything, then who cares?
  if {($topic == $topicnazi_chantopic($chan))} {
    return
  }

  # This is for when the bot first joins the channel.
  if {($uhost == "*")} {
    set topicnazi_chantopic($chan) $topic
    return   
  }

  # If the channel topic isn't locked, then we will protect the
  # new topic.
  if {!($topicnazi_chanlock($chan))} {
    topicnazi:timed_lock 60 $chan $topic
    return
  }

  # Bots may possibly include ourselves, and we surely don't want a
  # self-trigger.  Store the topic variable to what the IRC server says,
  # so that bots won't argue over the same topic, either!
  if {[matchattr $hand b]} {
    set topicnazi_chantopic($chan) $topic
    return
  }

  # Global owners, global masters, as well as owners or masters of this
  # channel are quite exempt from this policy.  We want to unlock the topic
  # when these people deem it necessary to intervene.
  if {([matchattr $hand m]) || ([matchattr $hand m $chan]) || \
      ([matchattr $hand n]) || ([matchattr $hand n $chan])} {
    set topicnazi_chanlock($chan) 0
  }

  if {[botisop $chan]} {
    # No sense in even trying if we're not opped.
    puthelp "TOPIC $chan :$topicnazi_chantopic($chan)"
  }
} 

proc topicnazi:timed_lock {duration chan topic} {
  global topicnazi_chantopic
  set topicnazi_chantopic($chan) $topic
  topicnazi:lock $chan
  utimer $duration "topicnazi:unlock $chan" 
}

proc topicnazi:request {nick uhost hand chan text} {
  global topicnazi_chanlock
  set chan [string tolower $chan]
  set text [string range $text 0 80]
  if {$text != ""} {
    if {$topicnazi_chanlock($chan)} {
      topicnazi:failure $nick $hand $chan    
    } else {
      # Chance of flooding here is minimal, since for the next sixty seconds
      # everything else will be running through puthelp.
      putserv "TOPIC $chan :$text"
      topicnazi:timed_lock 60 $chan $text 
    }
  }
}

proc topicnazi:failure {nick hand chan} {
  global topicnazi_warnlist
  if {([lsearch -exact $topicnazi_warnlist($chan) $hand] == -1)} {
    set remaining [topicnazi:timeleft $chan]
    if {($remaining <= 2)} {
      puthelp "NOTICE $nick :So close!  The topic was just about to expire."
    } else {
      puthelp "NOTICE $nick :Sorry!  The topic will expire in $remaining seconds."
    }
    lappend topicnazi_warnlist($chan) $hand    
  } 
}

proc topicnazi:timeleft chan {
  foreach {thing} [utimers] {
    if {[string match "*topicnazi:unlock $chan*" $thing]} {
      set list [split $thing " "]
      set timeleft [lindex $list 0]
      return $timeleft
    }  
  } 
  return 0
}


# Here's a novel concept.  Let's not worry about building array information
# for a damn channel until we join the thing.  tee-hee!

bind join b "% $botname" topicnazi:join_chan
bind topc - * topicnazi:topic_change
bind pub ov|ov !topic topicnazi:request 

topicnazi:kein_mitleid
putlog "$topicnaziver now ready.  BOfH powers--ACTIVATE!"
