Skip to content

Instantly share code, notes, and snippets.

@smiler
Created June 13, 2012 14:34
Show Gist options
  • Save smiler/2924436 to your computer and use it in GitHub Desktop.
Save smiler/2924436 to your computer and use it in GitHub Desktop.
require "socket"
require "net/http"
require "plugin"
require "channel"
# The irc class, which talks to the server and holds the main event loop
class IRC
attr_reader :channels, :nick
def initialize(server, port, nick, user, realname, channels)
@server = server
@port = port
@nick = nick
@user = user
@realname = realname
@plugin_handler = Plugin_Handler.new
@channels = []
channels.each { |channel|
@channels << Channel.new(channel)
}
# Used to store names while joining a channel
@names = Hash.new
end
# Sends message to the nick specified by target
def putnick(target, message)
putserv "PRIVMSG #{target} :#{message}"
end
# Sends message to the channel specified by target
def putchan(target, message)
putserv "PRIVMSG #{target} :#{message}"
end
# Sets mode on channel with optional args
def putmode(channel, mode, args)
putserv "MODE #{channel} #{mode} #{args}"
end
# Sends a string in its raw form to the server
def putserv(s)
# Send a message to the irc server and print it to the screen
puts "--> #{s}"
@irc.send "#{s}\n", 0
end
# Tires to kick a user from a channel
def putkick(nick, channel, message)
putserv "KICK #{channel} #{user} :#{message}"
end
# Connects, registers and join channels
def connect()
@irc = TCPSocket.open(@server, @port)
putserv "NICK #{@nick}"
putserv "USER #{@user} 8 * :#{@realname}"
@channels.each { |chan|
putserv "JOIN #{chan.name}"
}
end
# Matches server input and delegates control to the plugin event handler
# server PING PONG is handled locally here.
def handle_server_input(s)
case s.strip
# Server PING
when /^PING :(.+)$/i
puts "[ Server ping ]"
putserv "PONG :#{$1}"
# CTCP PING
when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[\001]PING (.+)[\001]$/i
@plugin_handler.event(:on_ctcp_ping, :nick => $1, :user => $2,
:host => $3, :message => $4)
# CTCP VERSION
when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[\001]VERSION[\001]$/i
@plugin_handler.event(:on_ctcp_version, :nick => $1, :user => $2,
:host => $3)
# PRIVMSG
when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s(.+?)\s:(.+)$/i
if $1 == $4
@plugin_handler.event(:on_privmsg, :nick => $1, :user => $2,
:host => $3, :message => $5)
else
@plugin_handler.event(:on_msg, :nick => $1, :user => $2,
:host => $3, :channel => $4, :message => $5)
end
# NOTICE
when /^:(.+?)!(.+?)@(.+?)\sNOTICE\s(.+?)\s:(.+)$/i
@plugin_handler.event(:on_notice, :nick => $1, :user => $2,
:host => $3, :target => $4, :message => $5)
# JOIN
when /^:(.+?)!(.+?)@(.+?)\sJOIN\s:(.+)/i
channel = $4
nick = $1
if nick == @nick
@channels << Channel.new(channel)
end
# Create channel if it dosen't exist
chan = @channels.select { |c| c.name == channel.downcase }[0]
if chan == nil
chan = Channel.new(channel)
@channels << chan
end
# Add user to our channel db
chan.adduser(nick, "")
# Handle plugins
@plugin_handler.event(:on_join, :nick => $1, :user => $2, :host => $3,
:channel => $4)
# PART
when /^:(.+?)!(.+?)@(.+?)\sPART\s(\S+)(\s:(.+))?/
channel = $4
nick = $1
# Remove channel if it's us that are leaving otherwise remove
# user from channel db
chan = @channels.select { |c| c.name == channel.downcase }[0]
if nick == @nick
@channels.delete(chan)
else
chan.deluser(nick)
end
# Handle plugins
@plugin_handler.event(:on_part, :nick => $1, :user => $2, :host => $3,
:channel => $4, :message => $6)
# KICK
when /^:(.+?)!(.+?)@(.+?)\sKICK\s(\S+)\s(\S+)(\s:(.+))?/
channel = $4
knick = $5
# Remove channel if it's us that are being kicked otherwise remove
# user from channel db
chan = @channels.select { |c| c.name == channel.downcase }[0]
if knick == @nick
@channels.delete(chan)
else
chan.deluser(knick)
end
# Handle plugins
@plugin_handler.event(:on_kick, :nick => $1, :user => $2, :host => $3,
:knick => $4,
:channel => $5, :message => $7)
# QUIT
when /^:(.+?)!(.+?)@(.+?)\sQUIT\s:(.+)$/
nick = $1
return if nick == @nick # TODO: Shall we do this?
# Remove user from all channels
@channels.each { |c| c.deluser(nick) }
# Handle plugins
@plugin_handler.event(:on_quit, :nick => $1, :user => $2, :host => $3,
:message => $4)
# MODE
when /^:(.+?)!(.+?)@(.+?)\sMODE\s(\S*)\s(\S*)(\s(.*))?/
# Set mode in our channel db
chan = @channels.select { |c| c.name == $4.downcase }[0]
chan.setmode($5, $7)
# Handle plugins
@plugin_handler.event(:on_mode, :nick => $1, :user => $2, :host => $3,
:channel => $4, :mode => $5, :args => $7)
# SMODE
when /^:(.+)\sMODE\s(.+)\s(.+)(\s(.+))?/
server = $1
channel = $2
mode = $3
args = $4
# Set mode in our channel db
chan = @channels.select { |c| c.name == channel.downcase }[0]
chan.setmode(mode, args)
# Handle plugins
@plugin_handler.event(:on_smode, :server => server, :channel =>
channel, :mode => mode, :args => args)
# NAMES reply
when /^:(.+)\s353\s(.+)\s([\*=@])\s(.+)\s:(.+)/
channel = $4.downcase
users = $5.split
puts "[ NAMES #{channel}: #{users.join(', ')} ]"
# Store users for later usage in NAMES end event
if @names[channel] == nil
@names[channel] = Array.new users
else
@names[channel].concat users
end
# NAMES end
when /^:(.+)366\s(.+)\s(.*)\s:(.+)/
channel = $3.downcase
message = $4
puts "[ NAMES #{channel}: #{message} ]"
# Add all stored users to our channel db
@names[channel].each { |user|
modes = user.chars.take_while { |c| "@%+".chars.to_a.include? c }.join
user = user.chars.drop_while { |c| "@%+".chars.to_a.include? c }.join
chan = @channels.select { |c| c.name == channel }[0]
chan.adduser(user, modes)
}
@names[channel] = nil
# Name already in use
when /^:(.+)\s433\s(.*)\s(.*)\s(.*)/
nick = $4
# TODO: handle this in a better way
putserv "NICK #{$altnick}"
putserv "USER #{@user} 8 * :#{@realname}"
@channels.each { |chan|
putserv "JOIN #{chan.name}"
}
else
@plugin_handler.event(:unknown, s)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment