]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/seen.rb
markov: refactor triplet learning
[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       ret << " (#{saw.message})" unless saw.message.empty?
103     when :JOIN
104       ret << "joining #{saw.where}"
105     when :QUIT
106       ret << "quitting IRC (#{saw.message})"
107     when :TOPIC
108       ret << "changing the topic of #{saw.where} to \"#{saw.message}\""
109     end
110
111     case saw.type.to_sym
112     when :PART, :QUIT
113       before = reg.first
114       if before.type == "PUBLIC" || before.type == "ACTION"
115         time_diff = saw.time - before.time
116         if time_diff < 300
117           time = "a moment"
118         elsif time_diff < 3600
119           time = "a while"
120         else
121           return ret
122         end
123
124         ret << ' and %{time} before' % { :time => time }
125
126         if before.type == "PUBLIC"
127           ret << ' saying "%{message}"' % {
128             :message => before.message
129           }
130         elsif before.type == "ACTION"
131           ret << ' doing *%{message}*' % {
132             :nick => saw.nick,
133             :message => before.message
134           }
135         end
136       end
137     end
138     return ret
139   end
140
141   def store(m, saw)
142     reg = @registry[saw.nick]
143
144     if reg && reg.is_a?(Array)
145       reg.shift if reg.size > 1
146       reg.push(saw)
147     else
148       reg = [saw]
149     end
150
151     if m.is_a? NickMessage
152       @registry[m.newnick] = reg
153     end
154
155     @registry[saw.nick] = reg
156   end
157 end
158 plugin = SeenPlugin.new
159 plugin.register("seen")