]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/seen.rb
seen: show what user said or did before leaving
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / seen.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: Seen Plugin
5 #
6 # Keep a database of who last said/did what
7
8 define_structure :Saw, :nick, :time, :type, :where, :message
9
10 class SeenPlugin < Plugin
11   Config.register Config::IntegerValue.new('seen.max_results',
12     :default => 3, :validate => Proc.new{|v| v >= 0},
13     :desc => "Maximum number of seen users to return in search (0 = no limit).")
14
15   def help(plugin, topic="")
16     "seen <nick> => have you seen, or when did you last see <nick>"
17   end
18
19   def privmsg(m)
20     unless(m.params =~ /^(\S)+$/)
21       m.reply "incorrect usage: " + help(m.plugin)
22       return
23     end
24
25     m.params.gsub!(/\?$/, "")
26
27     if @registry.has_key?(m.params)
28       m.reply seen(@registry[m.params])
29     else
30       rx = Regexp.new(m.params, true)
31       num_matched = 0
32       @registry.each {|nick, saw|
33         if nick.match(rx)
34           m.reply seen(saw)
35           num_matched += 1
36           break if num_matched == @bot.config['seen.max_results']
37         end
38       }
39
40       m.reply "nope!" if num_matched.zero?
41     end
42   end
43
44   def listen(m)
45     return unless m.source
46     # keep database up to date with who last said what
47     now = Time.new
48     case m
49     when PrivMessage
50       return if m.private?
51       type = m.action? ? 'ACTION' : 'PUBLIC'
52       store m, Saw.new(m.sourcenick.dup, now, type,
53                        m.target.to_s, m.message.dup)
54     when QuitMessage
55       return if m.address?
56       store m, Saw.new(m.sourcenick.dup, now, "QUIT",
57                        nil, m.message.dup)
58     when NickMessage
59       return if m.address?
60       store m, Saw.new(m.oldnick, now, "NICK", nil, m.newnick)
61     when PartMessage
62       return if m.address?
63       store m, Saw.new(m.sourcenick.dup, Time.new, "PART",
64                        m.target.to_s, m.message.dup)
65     when JoinMessage
66       return if m.address?
67       store m, Saw.new(m.sourcenick.dup, Time.new, "JOIN",
68                        m.target.to_s, m.message.dup)
69     when TopicMessage
70       return if m.address? or m.info_or_set == :info
71       store m, Saw.new(m.sourcenick.dup, Time.new, "TOPIC",
72                        m.target.to_s, m.message.dup)
73     end
74   end
75
76   def seen(reg)
77     saw = case reg
78     when Struct::Saw
79       reg # for backwards compatibility
80     when Array
81       reg.last
82     end
83
84     ret = "#{saw.nick} was last seen "
85     ago = Time.new - saw.time
86
87     if (ago.to_i == 0)
88       ret << "just now, "
89     else
90       ret << Utils.secs_to_string(ago) + " ago, "
91     end
92
93     case saw.type.to_sym
94     when :PUBLIC
95       ret << "saying #{saw.message}"
96     when :ACTION
97       ret << "doing #{saw.nick} #{saw.message}"
98     when :NICK
99       ret << "changing nick from #{saw.nick} to #{saw.message}"
100     when :PART
101       ret << "leaving #{saw.where}"
102     when :JOIN
103       ret << "joining #{saw.where}"
104     when :QUIT
105       ret << "quitting IRC (#{saw.message})"
106     when :TOPIC
107       ret << "changing the topic of #{saw.where} to #{saw.message}"
108     end
109
110     case saw.type.to_sym
111     when :PART, :QUIT
112       before = reg.first
113       if before.type == "PUBLIC" || before.type == "ACTION"
114         time_diff = saw.time - before.time
115         if time_diff < 300
116           time = "a moment"
117         elsif time_diff < 3600
118           time = "a while"
119         else
120           return ret
121         end
122
123         ret << ' and %{time} before' % { :time => time }
124
125         if before.type == "PUBLIC"
126           ret << ' saying "%{message}"' % {
127             :message => before.message
128           }
129         elsif before.type == "ACTION"
130           ret << ' doing *%{message}*' % {
131             :nick => saw.nick,
132             :message => before.message
133           }
134         end
135       end
136     end
137     return ret
138   end
139
140   def store(m, saw)
141     reg = @registry[saw.nick]
142
143     if reg && reg.is_a?(Array)
144       reg.shift if reg.size > 1
145       reg.push(saw)
146     else
147       reg = [saw]
148     end
149
150     if m.is_a? NickMessage
151       @registry[m.newnick] = reg
152     end
153
154     @registry[saw.nick] = reg
155   end
156 end
157 plugin = SeenPlugin.new
158 plugin.register("seen")