aboutsummaryrefslogtreecommitdiff
path: root/dinobot.rb
blob: 866396ea77658785a31d54da67fedbc9f094a018 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
require 'socket'

module Dinobot
  class Bot
    def initialize(server, port, nick, pass=nil, &block)
      @server = server
      @port = port
      @nick = nick
      @pass = pass

      @trigger = '!'

      @socket = nil
      @modules = Hash.new
      @channels = Array.new

      instance_eval(&block) if block_given?
    end

    def connect
      @socket = TCPSocket.new(@server, @port)

      out "PASS #{@pass}" if @pass
      out "NICK #{@nick}"
      out "USER #{@nick} 0 * :#{@nick}"

      @channels.each do |channel|
        join channel
      end
    end

    def connected?
      !(@socket.nil? || @socket.closed?)
    end

    def run
      while true
        puts "== Connecting to #{@server}:#{@port}."
        connect

        while str = @socket.gets
          str.chomp!
          puts "<< " + str.inspect

          begin
            parse_line(str)
          rescue
          end
        end

        puts "== Disconnected."
        @socket.close
      end
    end

    def parse_line(str)
      out str.sub('PING', 'PONG') if str =~ /^PING /

      if str =~ /(\S+) PRIVMSG (\S+) :(.*)/
        user, channel, message = str.scan(/(\S+) PRIVMSG (\S+) :(.*)/).first

        if message =~ /^#{Regexp.escape(@trigger)}/
          message.sub!(@trigger, '')

          mod = message.split.first.downcase.intern

          if @modules.has_key?(mod)
            exec_commands(@modules[mod].call(user, channel, message))
          end
        end
      end
    end

    def exec_commands(commands)
      commands.each do |command|
        case command.first
        when :say
          send(*command) if command.length == 3
        when :join, :part
          send(*command) if command.length == 2
        end
      end
    end

    def out(str)
      return unless connected?

      puts ">> " + str.inspect

      @socket.puts str
    end

    def say(channel, message)
      out "PRIVMSG #{channel} :#{message}"
    end

    def join(channel)
      @channels << channel unless @channels.include?(channel)

      out "JOIN #{channel}"
    end

    def part(channel)
      @channels.delete(channel)

      out "PART #{channel}"
    end

    def load_module(mod)
      mod = mod.downcase.intern
      puts "== Loading module: #{mod}"

      file = "#{mod}.rb"

      begin
        load file

        m = Dinobot.const_get(Dinobot.constants.find { |x| x.downcase == mod })
        @modules[mod] = m.new

        puts "== Loaded module: #{mod} (#{m})"
      rescue LoadError, StandardError => e
        puts "== Failed to load module: #{mod} (#{e.message})"
      end
    end
  end
end