7 attr_accessor :config, :socket, :last_nick, :authorized
11 self.config.merge! Hash[*options.map { |k,v| [k.intern, v] }.flatten]
18 log "Connecting to #{config[:server]}:#{config[:port]}..."
19 self.socket = TCPSocket.new(config[:server], config[:port])
21 socket.puts "USER #{config[:user]} #{config[:nick]} #{config[:name]} :#{config[:name]} \r\n"
22 socket.puts "NICK #{config[:nick]} \r\n"
24 socket.puts "PRIVMSG NickServ :IDENTIFY #{config[:password]}" if config[:password]
26 # channel might not have a # in front of it, so add it
27 config[:channel] = config[:channel][/^#/] ? config[:channel] : '#' + config[:channel]
39 if IO.select([socket])
43 #socket.each do |line|
44 # react_to line # its own method so we can change it on the fly, without hurting the loop
51 rescue Exception => bang
52 say "Class load error #{bang.class} (#{caller[1]}), #{bang}."
55 self.authorized = false # not authorized
57 info = grab_info(line) # grabs the info from an PRIVMSG
58 puts line # puts to the console
60 pong(line) if line[0..3] == "PING" # keep-alive
62 if info && info.last # only called if grabbing the info was successful
63 log_message info # logs in a friendly format, in chat.txt
64 execute(info.last, info.first) if info
65 elsif has_error?(line)
71 log "Error from server: #{line}" and return true if line[/^ERROR/]
74 def execute(cmd, nick)
76 return false unless data && data.first && authorize?(data)
80 data.join(' ').split(' then ').each do |command|
82 filters(:listen).each do |filter|
83 filter.call(command) if command
84 end if filters(:listen).size.nonzero?
86 command = command.split(' ')
87 command.shift if command.first =~ /^#{config[:nick]}/i
89 if Commands.methods.include? command.first and !(EmptyModule.methods.include? command.first)
90 Commands.send(command.first, command[1..-1])
92 # say "no command #{command}"
95 rescue Exception => bang
96 say "Command error #{bang.class}, #{bang}."
97 say " #{bang.backtrace.first}"
105 Commands.send(:filters, type)
110 socket.puts "#{line}"
112 Commands.poll(line) if Commands.methods.include? 'poll'
116 # The following is the format of what the bot recieves:
117 # :kyle!~kyle@X-24735511.lmdaca.adelphia.net PRIVMSG #youngcoders :for the most part
118 # :nick!~ident@host PRIVMSG #channel :message
119 text =~ /^\:(.+)\!\~?(.+)\@(.+) PRIVMSG \#?(\w+) \:(.+)/ ? [$1, $2, $3, $4, $5] : false
123 if self.config[:only_when_addressed] and data.first != "#{self.config[:nick]}:"
127 command, password = data.first, data[1]
128 if Commands.protected_instance_methods(false).include? command
129 self.authorized = config[:password] && password == config[:password]
136 def join(channel, quit_prev = true)
137 socket.puts "PART #{config[:channel]}" if quit_prev
138 socket.puts "JOIN #{channel} \r\n"
139 config[:channel] = channel
142 def log_message(array)
143 log "<#{array[0]}> : #{array[4]}"
147 File.open("chat.txt", "a") do |f|
148 f.puts "[#{Time.new.strftime "%m/%d/%Y %I:%M %p PST"}] #{string} \n"