summaryrefslogtreecommitdiff
path: root/nsa
diff options
context:
space:
mode:
authorPeter Palfrader <peter@palfrader.org>2007-05-23 21:25:21 +0000
committerweasel <weasel@bc3d92e2-beff-0310-a7cd-cc87d7ac0ede>2007-05-23 21:25:21 +0000
commitc0e8f01a25ed8f81daa4f6a56fee81c2053477bd (patch)
tree36f3d39b4422cd3efce56401116b4f5ac0b18fe7 /nsa
Add nsa
git-svn-id: svn+ssh://asteria.noreply.org/svn/weaselutils/trunk@270 bc3d92e2-beff-0310-a7cd-cc87d7ac0ede
Diffstat (limited to 'nsa')
-rwxr-xr-xnsa388
1 files changed, 388 insertions, 0 deletions
diff --git a/nsa b/nsa
new file mode 100755
index 0000000..47c484e
--- /dev/null
+++ b/nsa
@@ -0,0 +1,388 @@
+#!/usr/bin/ruby
+
+# (c) 2005 Peter Palfrader <weasel@debian.org>
+
+require 'socket'
+require 'yaml'
+require 'monitor'
+
+default_irc = {
+ 'server' => 'irc.oftc.net',
+ 'port' => 6667,
+ 'username' => 'unknown_nsa',
+ 'nick' => 'unknown_nsa',
+ 'realname' => 'Unknown NSA instance'
+}
+
+CONFIG = YAML::load( File.open( 'config' ) )
+default_irc.each_pair do |k,v|
+ CONFIG['irc'][k] = v unless CONFIG['irc'][k]
+end
+CONFIG['mailin'] = '/home/commit/Maildir' unless CONFIG['mailin'];
+
+Log = Object.new
+class << Log
+ def init
+ @ignore_list = []
+ @ignore_list << "dispatch thread"
+ @ignore_list << "connection"
+ @ignore_list << "waituntilonline - waiter"
+ @ignore_list << "waituntilonline - runthread"
+ end
+
+ def log section, message
+ puts message unless @ignore_list.include?(section)
+ end
+end
+
+
+class Connection
+ def initialize
+ @inQueue = []
+ @inQueue.extend(MonitorMixin)
+ @inEmpty = @inQueue.new_cond
+
+ @outQueue = []
+ @outQueue.extend(MonitorMixin)
+ @outEmpty = @outQueue.new_cond
+
+ @sock = TCPSocket.new(CONFIG['irc']['server'], CONFIG['irc']['port']);
+ puts "Connected!"
+
+ createInThread
+ createOutThread
+ end
+
+ def print line
+ @outQueue.synchronize do
+ @outQueue << line
+ @outEmpty.signal
+ end
+ end
+
+ def getline
+ line = ""
+ @inQueue.synchronize do
+ @inEmpty.wait_while { @inQueue.empty? }
+ line = @inQueue.shift
+ end
+ return line
+ end
+
+ private
+
+ def createInThread
+ @inThread = Thread.new {
+ begin
+ while true
+ line = @sock.readline
+ Log.log "connection", "[connection] <<< " + line
+ line.chop!
+
+ @inQueue.synchronize do
+ @inQueue << line
+ @inEmpty.signal
+ end
+ end
+ rescue => e
+ puts e.class.to_s+": "+e.message
+ puts e.backtrace
+ end
+ Thread.main.exit
+ }
+ end
+
+ def createOutThread
+ @outThread = Thread.new {
+ begin
+ while true
+ @outQueue.synchronize do
+ @outEmpty.wait_while { @outQueue.empty? }
+ line = @outQueue.shift
+ @sock.puts line
+ Log.log "connection", "[connection] >>> " + line
+ end
+ end
+ rescue => e
+ puts e.class.to_s+": "+e.message
+ puts e.backtrace
+ end
+ Thread.main.exit
+ }
+ end
+end
+
+IrcHandleDevNull = Object.new
+class << IrcHandleDevNull
+ def handle(irc, parsed)
+ end
+end
+
+IrcHandlePing = Object.new
+class << IrcHandlePing
+ def handle(irc, parsed)
+ irc.print "PONG "+irc.getNick
+ end
+end
+
+IrcHandle001 = Object.new
+class << IrcHandle001
+ def handle(irc, parsed)
+ irc.weAreOnline
+ end
+end
+
+IrcHandlePickAnotherNick = Object.new
+class << IrcHandlePickAnotherNick
+ def handle(irc, parsed)
+ irc.useADifferentNick
+ end
+end
+
+IrcHandleMode = Object.new
+class << IrcHandleMode
+ def handle(irc, parsed)
+ irc.modeUpdate(parsed)
+ end
+end
+
+class Irc
+ IRC_NOT_CONNECTED = 0
+ IRC_CONNECTED = 1
+ IRC_SENT_NICK = 2
+ IRC_PICK_NEW_NICK = 3
+ IRC_ONLINE = 4
+
+ def initialize
+ @handler = {}
+ @nick = "#{CONFIG['irc']['nick']}"
+ @onlineMonitor = Monitor.new;
+ @onlineCond = @onlineMonitor.new_cond
+
+
+ @handler['PING'] = IrcHandlePing # PING
+ @handler['NOTICE'] = IrcHandleDevNull # NOTICE
+ @handler['MODE'] = IrcHandleMode # NOTICE
+ @handler['001'] = IrcHandle001 # w :Welcome to the OFTC Internet
+ @handler['002'] = IrcHandleDevNull # w :Your host is neutron.oftc.net..
+ @handler['003'] = IrcHandleDevNull # w :This server was created Fri ....
+ @handler['004'] = IrcHandleDevNull # w neutron.oftc.net hybrid-7.1+oftc1....
+ @handler['005'] = IrcHandleDevNull # w WALLCHOPS KNOCK EXCEPTS INVEX....
+ @handler['375'] = IrcHandleDevNull # RPL_MOTDSTART
+ @handler['372'] = IrcHandleDevNull # RPL_MOTD
+ @handler['376'] = IrcHandleDevNull # RPL_ENDOFMOTD
+ @handler['250'] = IrcHandleDevNull # Highest connection count: 2 (2 clients) (7 connections received)
+ @handler['251'] = IrcHandleDevNull # RPL_LUSERCLIENT
+ @handler['252'] = IrcHandleDevNull # RPL_LUSEROP
+ @handler['253'] = IrcHandleDevNull # 1 :unknown connection(s)
+ @handler['254'] = IrcHandleDevNull # 575 :channels formed
+ @handler['255'] = IrcHandleDevNull # RPL_LUSERME
+ @handler['265'] = IrcHandleDevNull # Current local users: 2 Max: 2
+ @handler['266'] = IrcHandleDevNull # Current global users: 2 Max: 2
+ @handler['353'] = IrcHandleDevNull # RAB = #rab :RAB @weasel·
+ @handler['366'] = IrcHandleDevNull # RAB #rab :End of /NAMES list.
+ @handler['433'] = IrcHandlePickAnotherNick # * oftc-bot :Nickname is already in use.
+
+ dispatchToHandlers
+ run
+ end
+
+ def print line
+ @connection.print line
+ end
+
+ def getNick
+ @nick
+ end
+
+ def weAreOnline
+ throw "Current run_state is @{run_state}. that's unexpected" unless @run_state == IRC_SENT_NICK
+ @run_state = IRC_ONLINE
+ @run_thread.wakeup
+ end
+
+ def useADifferentNick
+ throw "Current run_state is @{run_state}. that's unexpected" unless @run_state == IRC_SENT_NICK
+ @run_state = IRC_PICK_NEW_NICK
+ @run_thread.wakeup
+ end
+
+ def modeUpdate(message)
+ puts "[irc] Received mode update: " + message.to_yaml.gsub("\n","\n ")
+ end
+
+
+ def waitUntilOnline
+ Log.log "waituntilonline - waiter", "[waituntilonline] entering monitor"
+ @onlineMonitor.synchronize do
+ Log.log "waituntilonline - waiter", "[waituntilonline] entered monitor"
+ @onlineCond.wait_while { @run_state != IRC_ONLINE }
+ Log.log "waituntilonline - waiter", "[waituntilonline] waiting done"
+ @onlineCond.signal
+ Log.log "waituntilonline - waiter", "[waituntilonline] woke up the rest"
+ end
+ Log.log "waituntilonline - waiter", "[waituntilonline] left monitor"
+ end
+
+ private
+
+ def run
+ @run_thread = Thread.new {
+ @run_state = IRC_NOT_CONNECTED
+ while true
+ puts "[run thread] state '#{@run_state}'"
+ case @run_state
+ when IRC_NOT_CONNECTED
+ @connection = Connection.new
+ @dispatch_thread.wakeup
+ @run_state = IRC_CONNECTED
+ when IRC_CONNECTED
+ @connection.print "USER #{CONFIG['irc']['username']} . . :#{CONFIG['irc']['realname']}"
+ issueNick
+ @run_state = IRC_SENT_NICK
+ when IRC_SENT_NICK
+ sleep
+ when IRC_PICK_NEW_NICK
+ @nick.succ!
+ issueNick
+ @run_state = IRC_SENT_NICK
+ when IRC_ONLINE
+ @connection.print "MODE #{@nick} +w"
+
+ Log.log "waituntilonline - runthread", "[run thread] entering monitor onlineMonitor"
+ @onlineMonitor.synchronize do
+ Log.log "waituntilonline - runthread", "[run thread] entered monitor onlineMonitor"
+ @onlineCond.signal
+ Log.log "waituntilonline - runthread", "[run thread] sent signal on onlineCond"
+ end
+ Log.log "waituntilonline - runthread", "[run thread] left monitor onlineMonitor"
+ sleep
+ end
+ end
+ }
+ end
+
+ def dispatchToHandlers
+ @dispatch_thread = Thread.new {
+ while true
+ while not @connection
+ Log.log "dispatch thread", "[dispatch thread] waiting for connection"
+ sleep
+ Log.log "dispatch thread", "[dispatch thread] waiting for connection done"
+ end
+
+ Log.log "dispatch thread", "[dispatch thread] waiting for line"
+ line = @connection.getline
+ Log.log "dispatch thread", "[dispatch thread] waiting for line done"
+
+ parsed = parseLine line
+
+ if @handler.has_key?(parsed['command'])
+ Log.log "dispatch thread", "[dispatch thread] dispatching #{parsed['command']}: " + parsed['params'].join(' ')
+ @handler[parsed['command']].handle( self, parsed )
+ else
+ Log.log "dispatch thread - unhandled", "[dispatch thread] Unhandled: #{line}"
+ end
+ end
+ }
+ end
+
+ def issueNick
+ @connection.print "NICK #{@nick}"
+ end
+
+ def parseLine line
+ source = nil
+ (source, line) = line.split(' ', 2) if line[0,1] == ':'
+ source = source[1,source.length-1] if source
+ (command, line) = line.split(' ', 2)
+ params = []
+ while line and line[0,1] != ':'
+ (middle, line) = line.split(' ', 2)
+ params << middle
+ end
+ params << line[1,line.length-1] if line and line[0,1] == ':'
+ throw "hmmmm. line is '#{line}'." if line and line[0,1] != ':'
+
+ return {
+ 'source' => source,
+ 'command' => command,
+ 'params' => params
+ }
+ end
+end
+
+Thread.abort_on_exception = true
+
+Dir.chdir( CONFIG['mailin'] + "/new" )
+
+Log.init
+bot = Irc.new
+bot.waitUntilOnline
+sleep 1
+if CONFIG['irc']['nickserv_is_smart']
+ bot.print "NICKSERV :identify #{CONFIG['irc']['nickservpassword']} #{CONFIG['irc']['nick']}"
+else
+ bot.print "NICKSERV :identify #{CONFIG['irc']['nickservpassword']}"
+end
+sleep 5
+
+channels = {}
+CONFIG['projects'].each_value do |cl|
+ cl.each do |c|
+ channels[c] = true
+ end
+end
+channels.each_key do |c|
+ bot.print "JOIN #{c}"
+end
+
+while (1) do
+ oldcommitmsg = nil
+ Dir.foreach('.') { |filename|
+ next if filename == "."
+ next if filename == ".."
+
+ in_headers = true
+ fh = File.open(filename, "r")
+ project = nil
+ lines = []
+ commitmsg = ""
+ fh.readlines.each { |line|
+ line.chomp!
+ in_headers = false if line == ""
+ if (in_headers and not line =~ /^\s/)
+ (header, content) = line.split(':', 2);
+ content.strip!
+ if header.upcase == "SUBJECT"
+ project = /Announce\s+([A-Za-z0-9_-]+)/.match(content)[1];
+ end
+ elsif (not in_headers)
+ lines.push line
+ commitmsg = commitmsg + line
+ end
+ }
+ fh.close
+ File.unlink(filename)
+
+ puts "Project "+project
+ puts "commitmsg "+commitmsg
+
+ if project and commitmsg != oldcommitmsg
+ pr = "%c"%(002) + project + "%c: "%(002)
+ lines.each{ |line|
+ if (line != '')
+ line = pr + line
+ channellist = CONFIG['projects'].has_key?(project) ? CONFIG['projects'][project] : CONFIG['*']
+ channellist.each do |c|
+ bot.print "PRIVMSG #{c} :#{line}"
+ end
+ end
+ }
+ end
+ oldcommitmsg = commitmsg
+ }
+ sleep 5
+end
+
+Thread.stop