summaryrefslogtreecommitdiff
path: root/data/rbot/plugins/seen.rb
blob: 12d0fae2584efbf511798dbee43747bb2083e0d8 (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#-- vim:sw=2:et
#++
#
# :title: Seen Plugin
#
# Keep a database of who last said/did what

define_structure :Saw, :nick, :time, :type, :where, :message

class SeenPlugin < Plugin
  Config.register Config::IntegerValue.new('seen.max_results',
    :default => 3, :validate => Proc.new{|v| v >= 0},
    :desc => "Maximum number of seen users to return in search (0 = no limit).")

  def help(plugin, topic="")
    "seen <nick> => have you seen, or when did you last see <nick>"
  end

  def privmsg(m)
    unless(m.params =~ /^(\S)+$/)
      m.reply "incorrect usage: " + help(m.plugin)
      return
    end

    m.params.gsub!(/\?$/, "")

    if @registry.has_key?(m.params)
      m.reply seen(@registry[m.params])
    else
      rx = Regexp.new(m.params, true)
      num_matched = 0
      @registry.each {|nick, saw|
        if nick.match(rx)
          m.reply seen(saw)
          num_matched += 1
          break if num_matched == @bot.config['seen.max_results']
        end
      }

      m.reply "nope!" if num_matched.zero?
    end
  end

  def listen(m)
    return unless m.source
    # keep database up to date with who last said what
    now = Time.new
    case m
    when PrivMessage
      return if m.private?
      type = m.action? ? 'ACTION' : 'PUBLIC'
      store m, Saw.new(m.sourcenick.dup, now, type,
                       m.target.to_s, m.message.dup)
    when QuitMessage
      return if m.address?
      store m, Saw.new(m.sourcenick.dup, now, "QUIT",
                       nil, m.message.dup)
    when NickMessage
      return if m.address?
      store m, Saw.new(m.oldnick, now, "NICK", nil, m.newnick)
    when PartMessage
      return if m.address?
      store m, Saw.new(m.sourcenick.dup, Time.new, "PART",
                       m.target.to_s, m.message.dup)
    when JoinMessage
      return if m.address?
      store m, Saw.new(m.sourcenick.dup, Time.new, "JOIN",
                       m.target.to_s, m.message.dup)
    when TopicMessage
      return if m.address? or m.info_or_set == :info
      store m, Saw.new(m.sourcenick.dup, Time.new, "TOPIC",
                       m.target.to_s, m.message.dup)
    end
  end

  def seen(reg)
    saw = case reg
    when Struct::Saw
      reg # for backwards compatibility
    when Array
      reg.last
    end

    ret = "#{saw.nick} was last seen "
    ago = Time.new - saw.time

    if (ago.to_i == 0)
      ret << "just now, "
    else
      ret << Utils.secs_to_string(ago) + " ago, "
    end

    case saw.type.to_sym
    when :PUBLIC
      ret << "saying #{saw.message}"
    when :ACTION
      ret << "doing #{saw.nick} #{saw.message}"
    when :NICK
      ret << "changing nick from #{saw.nick} to #{saw.message}"
    when :PART
      ret << "leaving #{saw.where}"
    when :JOIN
      ret << "joining #{saw.where}"
    when :QUIT
      ret << "quitting IRC (#{saw.message})"
    when :TOPIC
      ret << "changing the topic of #{saw.where} to #{saw.message}"
    end

    case saw.type.to_sym
    when :PART, :QUIT
      before = reg.first
      if before.type == "PUBLIC" || before.type == "ACTION"
        time_diff = saw.time - before.time
        if time_diff < 300
          time = "a moment"
        elsif time_diff < 3600
          time = "a while"
        else
          return ret
        end

        ret << ' and %{time} before' % { :time => time }

        if before.type == "PUBLIC"
          ret << ' saying "%{message}"' % {
            :message => before.message
          }
        elsif before.type == "ACTION"
          ret << ' doing *%{message}*' % {
            :nick => saw.nick,
            :message => before.message
          }
        end
      end
    end
    return ret
  end

  def store(m, saw)
    reg = @registry[saw.nick]

    if reg && reg.is_a?(Array)
      reg.shift if reg.size > 1
      reg.push(saw)
    else
      reg = [saw]
    end

    if m.is_a? NickMessage
      @registry[m.newnick] = reg
    end

    @registry[saw.nick] = reg
  end
end
plugin = SeenPlugin.new
plugin.register("seen")