]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/core/irclog.rb
c4e9f590c2a093f0ceff62c6f41bf4e464ac22df
[user/henk/code/ruby/rbot.git] / lib / rbot / core / irclog.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: rbot IRC logging facilities
5 #
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7 # Copyright:: (C) 2008 Giuseppe Bilotta
8 # License:: GPL v2
9
10 class IrcLogModule < CoreBotModule
11
12   Config.register Config::IntegerValue.new('irclog.max_open_files',
13     :default => 20, :validate => Proc.new { |v| v > 0 },
14     :desc => "Maximum number of irclog files to keep open at any one time.")
15   
16   def initialize
17     super
18     @logs = Hash.new
19     Dir.mkdir("#{@bot.botclass}/logs") unless File.exist?("#{@bot.botclass}/logs")
20   end
21
22   def logfile_close(where_str, reason = 'unknown reason')
23     f = @logs.delete(where_str) or return
24     stamp = Time.now.strftime '%Y/%m/%d %H:%M:%S'
25     f[1].puts "[#{stamp}] @ Log closed by #{@bot.myself.nick} (#{reason})"
26     f[1].close
27   end
28
29   # log IRC-related message +message+ to a file determined by +where+.
30   # +where+ can be a channel name, or a nick for private message logging
31   def irclog(message, where="server")
32     message = message.chomp
33     now = Time.now
34     stamp = now.strftime("%Y/%m/%d %H:%M:%S")
35     if where.class <= Server
36       where_str = "server"
37     else
38       where_str = where.downcase.gsub(/[:!?$*()\/\\<>|"']/, "_")
39     end
40     unless @logs.has_key? where_str
41       if @logs.size > @bot.config['irclog.max_open_files']
42         @logs.keys.sort do |a, b|
43           @logs[a][0] <=> @logs[b][0]
44         end.slice(0, @logs.size - @bot.config['irclog.max_open_files']).each do |w|
45           logfile_close w, "idle since #{@logs[w][0]}"
46         end
47       end
48       f = File.new("#{@bot.botclass}/logs/#{where_str}", "a")
49       f.sync = true
50       f.puts "[#{stamp}] @ Log started by #{@bot.myself.nick}"
51       @logs[where_str] = [now, f]
52     end
53     @logs[where_str][1].puts "[#{stamp}] #{message}"
54     @logs[where_str][0] = now
55     #debug "[#{stamp}] <#{where}> #{message}"
56   end
57
58   def cleanup
59     @logs.keys.each { |w| logfile_close(w, 'rescan or shutdown') }
60   end
61
62   def sent(m)
63     case m
64     when NoticeMessage
65       irclog "-#{m.source}- #{m.message}", m.target
66     when PrivMessage
67       irclog "<#{m.source}> #{m.message}", m.target
68     when QuitMessage
69       m.was_on.each { |ch|
70         irclog "@ quit (#{m.message})", ch
71       }
72     end
73   end
74
75   def welcome(m)
76     irclog "joined server #{m.server} as #{m.target}", "server"
77   end
78
79   def listen(m)
80     case m
81     when PrivMessage
82       method = 'log_message'
83     else
84       method = 'log_' + m.class.name.downcase.match(/^irc::(\w+)message$/).captures.first
85     end
86     if self.respond_to?(method)
87       self.__send__(method, m)
88     else
89       warning "unhandled logging for #{m.pretty_inspect} (no such method #{method})"
90       unknown_message(m)
91     end
92   end
93
94   def log_message(m)
95     if m.ctcp
96       who = m.private? ? "me" : m.target
97       logtarget = m.private? ? m.source : m.target
98       case m.ctcp.intern
99       when :ACTION
100         if m.public?
101           irclog "* #{m.source} #{m.logmessage}", m.target
102         else
103           irclog "* #{m.source}(#{m.sourceaddress}) #{m.logmessage}", m.source
104         end
105       when :VERSION
106         irclog "@ #{m.source} asked #{who} about version info", logtarget
107       when :SOURCE
108         irclog "@ #{m.source} asked #{who} about source info", logtarget
109       when :PING
110         irclog "@ #{m.source} pinged #{who}", logtarget
111       when :TIME
112         irclog "@ #{m.source} asked #{who} what time it is", logtarget
113       else
114         irclog "@ #{m.source} asked #{who} about #{[m.ctcp, m.message].join(' ')}", logtarget
115       end
116     else
117       if m.public? 
118         irclog "<#{m.source}> #{m.logmessage}", m.target
119       else
120         irclog "<#{m.source}(#{m.sourceaddress})> #{m.logmessage}", m.source
121       end
122     end
123   end
124
125   def log_notice(m)
126     if m.private?
127       irclog "-#{m.source}(#{m.sourceaddress})- #{m.logmessage}", m.source
128     else
129       irclog "-#{m.source}- #{m.logmessage}", m.target
130     end
131   end
132
133   def motd(m)
134     m.message.each_line { |line|
135       irclog "MOTD: #{line}", "server"
136     }
137   end
138
139   def log_nick(m)
140     m.is_on.each { |ch|
141       irclog "@ #{m.oldnick} is now known as #{m.newnick}", ch
142     }
143   end
144
145   def log_quit(m)
146     m.was_on.each { |ch|
147       irclog "@ Quit: #{m.source}: #{m.logmessage}", ch
148     }
149   end
150
151   def modechange(m)
152     irclog "@ Mode #{m.logmessage} by #{m.source}", m.target
153   end
154
155   def log_join(m)
156     if m.address?
157       debug "joined channel #{m.channel}"
158       irclog "@ Joined channel #{m.channel}", m.channel
159     else
160       irclog "@ #{m.source} joined channel #{m.channel}", m.channel
161     end
162   end
163
164   def log_part(m)
165     if(m.address?)
166       debug "left channel #{m.channel}"
167       irclog "@ Left channel #{m.channel} (#{m.logmessage})", m.channel
168     else
169       irclog "@ #{m.source} left channel #{m.channel} (#{m.logmessage})", m.channel
170     end
171   end
172
173   def log_kick(m)
174     if(m.address?)
175       debug "kicked from channel #{m.channel}"
176       irclog "@ You have been kicked from #{m.channel} by #{m.source} (#{m.logmessage})", m.channel
177     else
178       irclog "@ #{m.target} has been kicked from #{m.channel} by #{m.source} (#{m.logmessage})", m.channel
179     end
180   end
181
182   # def log_invite(m)
183   #   # TODO
184   # end
185
186   def log_topic(m)
187     case m.info_or_set
188     when :set
189       if m.source == @bot.myself
190         irclog "@ I set topic \"#{m.topic}\"", m.channel
191       else
192         irclog "@ #{m.source} set topic \"#{m.topic}\"", m.channel
193       end
194     when :info
195       topic = m.channel.topic
196       irclog "@ Topic is \"#{m.topic}\"", m.channel
197       irclog "@ Topic set by #{topic.set_by} on #{topic.set_on}", m.channel
198     end
199   end
200
201   # def names(m)
202   #   # TODO
203   # end
204
205   def unknown_message(m)
206     irclog m.logmessage, ".unknown"
207   end
208 end
209
210 ilm = IrcLogModule.new
211 ilm.priority = -1
212