rbot 0.9.12 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/bin/rbot +1 -1
- data/data/rbot/plugins/geoip.rb +161 -0
- data/data/rbot/plugins/iplookup.rb +4 -3
- data/data/rbot/plugins/nickrecover.rb +13 -5
- data/data/rbot/plugins/quakeauth.rb +3 -2
- data/lib/rbot/core/irclog.rb +33 -4
- data/lib/rbot/irc.rb +12 -1
- data/lib/rbot/ircbot.rb +12 -9
- data/lib/rbot/ircsocket.rb +19 -44
- data/lib/rbot/message.rb +18 -7
- data/lib/rbot/rfc2812.rb +91 -15
- metadata +3 -2
data/Rakefile
CHANGED
data/bin/rbot
CHANGED
@@ -0,0 +1,161 @@
|
|
1
|
+
#-- vim:sw=2:et
|
2
|
+
#++
|
3
|
+
#
|
4
|
+
# :title: Geo IP Plugin
|
5
|
+
#
|
6
|
+
# Author:: Raine Virta <rane@kapsi.fi>
|
7
|
+
# Copyright:: (C) 2008 Raine Virta
|
8
|
+
# License:: GPL v2
|
9
|
+
#
|
10
|
+
# Resolves the geographic locations of users (network-wide) and IP addresses
|
11
|
+
|
12
|
+
module GeoIP
|
13
|
+
class InvalidHostError < RuntimeError; end
|
14
|
+
|
15
|
+
GEO_IP_PRIMARY = "http://lakka.kapsi.fi:40086/lookup.yaml?host="
|
16
|
+
GEO_IP_SECONDARY = "http://www.geoiptool.com/en/?IP="
|
17
|
+
HOST_NAME_REGEX = /^[a-z0-9\-]+(?:\.[a-z0-9\-]+)*\.[a-z]{2,4}/i
|
18
|
+
|
19
|
+
REGEX = {
|
20
|
+
:country => %r{Country:.*?<a href=".*?" target="_blank"> (.*?)</a>}m,
|
21
|
+
:region => %r{Region:.*?<a href=".*?" target="_blank">(.*?)</a>}m,
|
22
|
+
:city => %r{City:.*?<td align="left" class="arial_bold">(.*?)</td>}m
|
23
|
+
}
|
24
|
+
|
25
|
+
def self.valid_host?(hostname)
|
26
|
+
hostname =~ HOST_NAME_REGEX ||
|
27
|
+
hostname =~ Resolv::IPv4::Regex && (hostname.split(".").map { |e| e.to_i }.max <= 255)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.resolve(hostname)
|
31
|
+
raise InvalidHostError unless valid_host?(hostname)
|
32
|
+
|
33
|
+
yaml = Irc::Utils.bot.httputil.get(GEO_IP_PRIMARY+hostname)
|
34
|
+
|
35
|
+
if yaml
|
36
|
+
return YAML::load(yaml)
|
37
|
+
else
|
38
|
+
res = {}
|
39
|
+
raw = Irc::Utils.bot.httputil.get_response(GEO_IP_SECONDARY+hostname)
|
40
|
+
raw = raw.decompress_body(raw.raw_body)
|
41
|
+
|
42
|
+
REGEX.each { |key, regex| res[key] = Iconv.conv('utf-8', 'ISO-8859-1', raw.scan(regex).to_s) }
|
43
|
+
|
44
|
+
return res
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Stack
|
50
|
+
def initialize
|
51
|
+
@hash = {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def [](nick)
|
55
|
+
@hash[nick] = [] unless @hash[nick]
|
56
|
+
@hash[nick]
|
57
|
+
end
|
58
|
+
|
59
|
+
def has_nick?(nick)
|
60
|
+
@hash.has_key?(nick)
|
61
|
+
end
|
62
|
+
|
63
|
+
def clear(nick)
|
64
|
+
@hash.delete(nick)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class GeoIpPlugin < Plugin
|
69
|
+
def help(plugin, topic="")
|
70
|
+
"geoip [<user|hostname|ip>] => returns the geographic location of whichever has been given -- note: user can be anyone on the network"
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
super
|
75
|
+
|
76
|
+
@stack = Stack.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def whois(m)
|
80
|
+
nick = m.whois[:nick].downcase
|
81
|
+
|
82
|
+
# need to see if the whois reply was invoked by this plugin
|
83
|
+
return unless @stack.has_nick?(nick)
|
84
|
+
|
85
|
+
if m.target
|
86
|
+
msg = host2output(m.target.host, m.target.nick)
|
87
|
+
else
|
88
|
+
msg = "no such user on "+@bot.server.hostname.split(".")[-2]
|
89
|
+
end
|
90
|
+
@stack[nick].each do |source|
|
91
|
+
@bot.say source, msg
|
92
|
+
end
|
93
|
+
|
94
|
+
@stack.clear(nick)
|
95
|
+
end
|
96
|
+
|
97
|
+
def geoip(m, params)
|
98
|
+
if params.empty?
|
99
|
+
m.reply host2output(m.source.host, m.source.nick)
|
100
|
+
else
|
101
|
+
if m.replyto.class == Channel
|
102
|
+
|
103
|
+
# check if there is an user on the channel with nick same as input given
|
104
|
+
user = m.replyto.users.find { |user| user.nick == params[:input] }
|
105
|
+
|
106
|
+
if user
|
107
|
+
m.reply host2output(user.host, user.nick)
|
108
|
+
return
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# input is a host name or an IP
|
113
|
+
if GeoIP::valid_host?(params[:input])
|
114
|
+
m.reply host2output(params[:input])
|
115
|
+
|
116
|
+
# assume input is a nick
|
117
|
+
elsif params[:input] !~ /\./
|
118
|
+
nick = params[:input].downcase
|
119
|
+
|
120
|
+
@stack[nick] << m.replyto
|
121
|
+
@bot.whois(nick)
|
122
|
+
else
|
123
|
+
m.reply "invalid input"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def host2output(host, nick=nil)
|
129
|
+
return "127.0.0.1 could not be res.. wait, what?" if host == "127.0.0.1"
|
130
|
+
|
131
|
+
begin
|
132
|
+
geo = GeoIP::resolve(host)
|
133
|
+
|
134
|
+
raise if geo[:country].empty?
|
135
|
+
rescue GeoIP::InvalidHostError, RuntimeError
|
136
|
+
return _("#{nick ? "#{nick}'s location" : host} could not be resolved")
|
137
|
+
end
|
138
|
+
|
139
|
+
res = _("%{thing} is #{nick ? "from" : "located in"}") % {
|
140
|
+
:thing => (nick ? nick : Resolv::getaddress(host)),
|
141
|
+
:country => geo[:country]
|
142
|
+
}
|
143
|
+
|
144
|
+
res << " %{city}," % {
|
145
|
+
:city => geo[:city]
|
146
|
+
} unless geo[:city].to_s.empty?
|
147
|
+
|
148
|
+
res << " %{country}" % {
|
149
|
+
:country => geo[:country]
|
150
|
+
}
|
151
|
+
|
152
|
+
res << " (%{region})" % {
|
153
|
+
:region => geo[:region]
|
154
|
+
} unless geo[:region].to_s.empty? || geo[:region] == geo[:city]
|
155
|
+
|
156
|
+
return res
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
plugin = GeoIpPlugin.new
|
161
|
+
plugin.map "geoip [:input]", :action => 'geoip', :thread => true
|
@@ -188,20 +188,21 @@ class IPLookupPlugin < Plugin
|
|
188
188
|
end
|
189
189
|
|
190
190
|
def iplookup(m, params)
|
191
|
-
|
191
|
+
reply = ""
|
192
192
|
if params[:domain].match(/^#{Regexp::Irc::HOSTADDR}$/)
|
193
193
|
ip = params[:domain]
|
194
194
|
else
|
195
195
|
begin
|
196
196
|
ip = Resolv.getaddress(params[:domain])
|
197
|
-
reply
|
197
|
+
reply << "#{params[:domain]} | "
|
198
198
|
rescue => e
|
199
199
|
m.reply "#{e.message}"
|
200
200
|
return
|
201
201
|
end
|
202
202
|
end
|
203
203
|
|
204
|
-
reply
|
204
|
+
reply << ArinWhois.lookup_info(ip)
|
205
|
+
|
205
206
|
m.reply reply
|
206
207
|
end
|
207
208
|
|
@@ -52,17 +52,25 @@ class NickRecoverPlugin < Plugin
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def stop_recovery
|
55
|
-
|
55
|
+
begin
|
56
|
+
@bot.timer.remove(@recovery) if @recovery
|
57
|
+
ensure
|
58
|
+
@recovery = nil
|
59
|
+
end
|
56
60
|
end
|
57
61
|
|
58
62
|
def start_recovery(time=self.poll_time)
|
59
63
|
if @recovery
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
+
begin
|
65
|
+
@bot.timer.reschedule(@recovery, poll_time)
|
66
|
+
return
|
67
|
+
rescue
|
68
|
+
@recovery=nil
|
64
69
|
end
|
65
70
|
end
|
71
|
+
@recovery = @bot.timer.add(time) do
|
72
|
+
has_nick? ? stop_recovery : recover
|
73
|
+
end
|
66
74
|
end
|
67
75
|
|
68
76
|
def initialize
|
@@ -35,6 +35,7 @@ class QPlugin < Plugin
|
|
35
35
|
val
|
36
36
|
end
|
37
37
|
end
|
38
|
+
@source = nil
|
38
39
|
end
|
39
40
|
|
40
41
|
def set(m, params)
|
@@ -44,11 +45,11 @@ class QPlugin < Plugin
|
|
44
45
|
end
|
45
46
|
|
46
47
|
def connect
|
47
|
-
identify(nil, nil)
|
48
|
+
identify(nil, nil) if on_quakenet?
|
48
49
|
end
|
49
50
|
|
50
51
|
def identify(m, params)
|
51
|
-
@source = m.replyto
|
52
|
+
@source = m.replyto if m
|
52
53
|
@registry['quakenet.auth'] = params[:password] if params[:password]
|
53
54
|
|
54
55
|
if @registry.has_key?('quakenet.user') && @registry.has_key?('quakenet.auth')
|
data/lib/rbot/core/irclog.rb
CHANGED
@@ -272,10 +272,39 @@ class IrcLogModule < CoreBotModule
|
|
272
272
|
end
|
273
273
|
end
|
274
274
|
fp = logfilepath(where_str, now)
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
275
|
+
begin
|
276
|
+
dir = File.dirname(fp)
|
277
|
+
# first of all, we check we're not trying to build a directory structure
|
278
|
+
# where one of the components exists already as a file, so we
|
279
|
+
# backtrack along dir until we come across the topmost existing name.
|
280
|
+
# If it's a file, we rename to filename.old.filedate
|
281
|
+
up = dir.dup
|
282
|
+
until File.exist? up
|
283
|
+
up.replace File.dirname up
|
284
|
+
end
|
285
|
+
unless File.directory? up
|
286
|
+
backup = up.dup
|
287
|
+
backup << ".old." << File.atime(up).strftime('%Y%m%d%H%M%S')
|
288
|
+
debug "#{up} is not a directory! renaming to #{backup}"
|
289
|
+
File.rename(up, backup)
|
290
|
+
end
|
291
|
+
FileUtils.mkdir_p(dir)
|
292
|
+
# conversely, it may happen that fp exists and is a directory, in
|
293
|
+
# which case we rename the directory instead
|
294
|
+
if File.directory? fp
|
295
|
+
backup = fp.dup
|
296
|
+
backup << ".old." << File.atime(fp).strftime('%Y%m%d%H%M%S')
|
297
|
+
debug "#{fp} is not a file! renaming to #{backup}"
|
298
|
+
File.rename(fp, backup)
|
299
|
+
end
|
300
|
+
# it should be fine to create the file now
|
301
|
+
f = File.new(fp, "a")
|
302
|
+
f.sync = true
|
303
|
+
f.puts "[#{stamp}] @ Log started by #{@bot.myself.nick}"
|
304
|
+
rescue Exception => e
|
305
|
+
error e
|
306
|
+
next
|
307
|
+
end
|
279
308
|
@logs[where_str] = [now, f]
|
280
309
|
end
|
281
310
|
@logs[where_str][1].puts "[#{stamp}] #{message}"
|
data/lib/rbot/irc.rb
CHANGED
@@ -922,7 +922,7 @@ module Irc
|
|
922
922
|
class User < Netmask
|
923
923
|
alias :to_s :nick
|
924
924
|
|
925
|
-
attr_accessor :real_name
|
925
|
+
attr_accessor :real_name, :idle_since, :signon
|
926
926
|
|
927
927
|
# Create a new IRC User from a given Netmask (or anything that can be converted
|
928
928
|
# into a Netmask) provided that the given Netmask does not have globs.
|
@@ -934,6 +934,8 @@ module Irc
|
|
934
934
|
raise ArgumentError, "#{str.inspect} must not have globs (unescaped * or ?)" if host.has_irc_glob? && host != "*"
|
935
935
|
@away = false
|
936
936
|
@real_name = String.new
|
937
|
+
@idle_since = nil
|
938
|
+
@signon = nil
|
937
939
|
end
|
938
940
|
|
939
941
|
# The nick of a User may be changed freely, but it must not contain glob patterns.
|
@@ -1299,12 +1301,15 @@ module Irc
|
|
1299
1301
|
include ServerOrCasemap
|
1300
1302
|
attr_reader :name, :topic, :mode, :users
|
1301
1303
|
alias :to_s :name
|
1304
|
+
attr_accessor :creation_time, :url
|
1302
1305
|
|
1303
1306
|
def inspect
|
1304
1307
|
str = self.__to_s__[0..-2]
|
1305
1308
|
str << " on server #{server}" if server
|
1306
1309
|
str << " @name=#{@name.inspect} @topic=#{@topic.text.inspect}"
|
1307
1310
|
str << " @users=[#{user_nicks.sort.join(', ')}]"
|
1311
|
+
str << " (created on #{creation_time})" if creation_time
|
1312
|
+
str << " (URL #{url})" if url
|
1308
1313
|
str << ">"
|
1309
1314
|
end
|
1310
1315
|
|
@@ -1368,6 +1373,12 @@ module Irc
|
|
1368
1373
|
|
1369
1374
|
# Flags
|
1370
1375
|
@mode = ModeHash.new
|
1376
|
+
|
1377
|
+
# creation time, only on some networks
|
1378
|
+
@creation_time = nil
|
1379
|
+
|
1380
|
+
# URL, only on some networks
|
1381
|
+
@url = nil
|
1371
1382
|
end
|
1372
1383
|
|
1373
1384
|
# Removes a user from the channel
|
data/lib/rbot/ircbot.rb
CHANGED
@@ -277,14 +277,6 @@ class Bot
|
|
277
277
|
Config.register Config::IntegerValue.new('server.reconnect_wait',
|
278
278
|
:default => 5, :validate => Proc.new{|v| v >= 0},
|
279
279
|
:desc => "Seconds to wait before attempting to reconnect, on disconnect")
|
280
|
-
Config.register Config::FloatValue.new('server.sendq_delay',
|
281
|
-
:default => 2.0, :validate => Proc.new{|v| v >= 0},
|
282
|
-
:desc => "(flood prevention) the delay between sending messages to the server (in seconds)",
|
283
|
-
:on_change => Proc.new {|bot, v| bot.socket.sendq_delay = v })
|
284
|
-
Config.register Config::IntegerValue.new('server.sendq_burst',
|
285
|
-
:default => 4, :validate => Proc.new{|v| v >= 0},
|
286
|
-
:desc => "(flood prevention) max lines to burst to the server before throttling. Most ircd's allow bursts of up 5 lines",
|
287
|
-
:on_change => Proc.new {|bot, v| bot.socket.sendq_burst = v })
|
288
280
|
Config.register Config::IntegerValue.new('server.ping_timeout',
|
289
281
|
:default => 30, :validate => Proc.new{|v| v >= 0},
|
290
282
|
:desc => "reconnect if server doesn't respond to PING within this many seconds (set to 0 to disable)")
|
@@ -589,7 +581,7 @@ class Bot
|
|
589
581
|
debug "server.list is now #{@config['server.list'].inspect}"
|
590
582
|
end
|
591
583
|
|
592
|
-
@socket = Irc::Socket.new(@config['server.list'], @config['server.bindhost'],
|
584
|
+
@socket = Irc::Socket.new(@config['server.list'], @config['server.bindhost'], :ssl => @config['server.ssl'])
|
593
585
|
@client = Client.new
|
594
586
|
|
595
587
|
@plugins.scan
|
@@ -698,6 +690,12 @@ class Bot
|
|
698
690
|
m.modes = data[:modes]
|
699
691
|
@plugins.delegate "modechange", m
|
700
692
|
}
|
693
|
+
@client[:whois] = proc {|data|
|
694
|
+
source = data[:source]
|
695
|
+
target = server.get_user(data[:whois][:nick])
|
696
|
+
m = WhoisMessage.new(self, server, source, target, data[:whois])
|
697
|
+
@plugins.delegate "whois", m
|
698
|
+
}
|
701
699
|
@client[:join] = proc {|data|
|
702
700
|
m = JoinMessage.new(self, server, data[:source], data[:channel], data[:message])
|
703
701
|
sendq("MODE #{data[:channel]}", nil, 0) if m.address?
|
@@ -1209,6 +1207,11 @@ class Bot
|
|
1209
1207
|
sendq "MODE #{channel} #{mode} #{target}", channel, 2
|
1210
1208
|
end
|
1211
1209
|
|
1210
|
+
# asking whois
|
1211
|
+
def whois(nick, target=nil)
|
1212
|
+
sendq "WHOIS #{target} #{nick}", nil, 0
|
1213
|
+
end
|
1214
|
+
|
1212
1215
|
# kicking a user
|
1213
1216
|
def kick(channel, user, msg)
|
1214
1217
|
sendq "KICK #{channel} #{user} :#{msg}", channel, 2
|
data/lib/rbot/ircsocket.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
|
+
#-- vim:sw=2:et
|
2
|
+
#++
|
3
|
+
#
|
4
|
+
# :title: IRC Socket
|
5
|
+
#
|
6
|
+
# This module implements the IRC socket interface, including IRC message
|
7
|
+
# penalty computation and the message queue system
|
8
|
+
|
1
9
|
require 'monitor'
|
2
10
|
|
3
11
|
class ::String
|
4
12
|
# Calculate the penalty which will be assigned to this message
|
5
13
|
# by the IRCd
|
6
14
|
def irc_send_penalty
|
7
|
-
# According to
|
15
|
+
# According to eggdrop, the initial penalty is
|
8
16
|
penalty = 1 + self.size/100
|
9
17
|
# on everything but UnderNET where it's
|
10
18
|
# penalty = 2 + self.size/120
|
@@ -231,12 +239,6 @@ module Irc
|
|
231
239
|
# accumulator for the throttle
|
232
240
|
attr_reader :throttle_bytes
|
233
241
|
|
234
|
-
# delay between lines sent
|
235
|
-
attr_accessor :sendq_delay
|
236
|
-
|
237
|
-
# max lines to burst
|
238
|
-
attr_accessor :sendq_burst
|
239
|
-
|
240
242
|
# an optional filter object. we call @filter.in(data) for
|
241
243
|
# all incoming data and @filter.out(data) for all outgoing data
|
242
244
|
attr_reader :filter
|
@@ -263,7 +265,7 @@ module Irc
|
|
263
265
|
# server_list:: list of servers to connect to
|
264
266
|
# host:: optional local host to bind to (ruby 1.7+ required)
|
265
267
|
# create a new Irc::Socket
|
266
|
-
def initialize(server_list, host,
|
268
|
+
def initialize(server_list, host, opts={})
|
267
269
|
@server_list = server_list.dup
|
268
270
|
@server_uri = nil
|
269
271
|
@conn_count = 0
|
@@ -278,17 +280,6 @@ module Irc
|
|
278
280
|
else
|
279
281
|
@ssl = false
|
280
282
|
end
|
281
|
-
|
282
|
-
if sendq_delay
|
283
|
-
@sendq_delay = sendq_delay.to_f
|
284
|
-
else
|
285
|
-
@sendq_delay = 2
|
286
|
-
end
|
287
|
-
if sendq_burst
|
288
|
-
@sendq_burst = sendq_burst.to_i
|
289
|
-
else
|
290
|
-
@sendq_burst = 4
|
291
|
-
end
|
292
283
|
end
|
293
284
|
|
294
285
|
def connected?
|
@@ -330,9 +321,8 @@ module Irc
|
|
330
321
|
sock.connect
|
331
322
|
end
|
332
323
|
@sock = sock
|
333
|
-
@last_send = Time.new
|
324
|
+
@last_send = Time.new
|
334
325
|
@flood_send = Time.new
|
335
|
-
@last_throttle = Time.new
|
336
326
|
@burst = 0
|
337
327
|
@sock.extend(MonitorMixin)
|
338
328
|
@sendq = MessageQueue.new
|
@@ -405,7 +395,6 @@ module Irc
|
|
405
395
|
error "error while shutting down: #{e.pretty_inspect}"
|
406
396
|
end
|
407
397
|
@sock = nil
|
408
|
-
@burst = 0
|
409
398
|
@sendq.clear
|
410
399
|
end
|
411
400
|
|
@@ -413,30 +402,15 @@ module Irc
|
|
413
402
|
|
414
403
|
def writer_loop
|
415
404
|
loop do
|
416
|
-
# we could wait for the message, then calculate the delay and sleep
|
417
|
-
# if necessary. however, if high-priority message is enqueued while
|
418
|
-
# we sleep, it won't be the first to go out when the sleep is over.
|
419
|
-
# thus, we have to call Time.now() twice, once to calculate the delay
|
420
|
-
# and once to adjust @burst / @flood_send.
|
421
405
|
begin
|
422
406
|
now = Time.now
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
flood_delay = @flood_send - MAX_IRC_SEND_PENALTY - now
|
430
|
-
delay = [burst_delay, flood_delay, 0].max
|
431
|
-
if delay > 0
|
432
|
-
debug "sleep(#{delay}) # (f: #{flood_delay}, b: #{burst_delay})"
|
433
|
-
sleep(delay)
|
434
|
-
end
|
407
|
+
flood_delay = @flood_send - MAX_IRC_SEND_PENALTY - now
|
408
|
+
delay = [flood_delay, 0].max
|
409
|
+
if delay > 0
|
410
|
+
debug "sleep(#{delay}) # (f: #{flood_delay})"
|
411
|
+
sleep(delay)
|
435
412
|
end
|
436
413
|
msg = @sendq.shift
|
437
|
-
now = Time.now
|
438
|
-
@flood_send = now if @flood_send < now
|
439
|
-
@burst = 0 if @last_send + @sendq_delay < now
|
440
414
|
debug "got #{msg.inspect} from queue, sending"
|
441
415
|
emergency_puts(msg, true)
|
442
416
|
rescue Exception => e
|
@@ -459,11 +433,12 @@ module Irc
|
|
459
433
|
# the latter is racy and can cause double message output in
|
460
434
|
# some circumstances
|
461
435
|
actual = @filter.out(message) + "\n"
|
436
|
+
now = Time.new
|
462
437
|
@sock.syswrite actual
|
463
|
-
@last_send =
|
438
|
+
@last_send = now
|
439
|
+
@flood_send = now if @flood_send < now
|
464
440
|
@flood_send += message.irc_send_penalty if penalty
|
465
441
|
@lines_sent += 1
|
466
|
-
@burst += 1
|
467
442
|
end
|
468
443
|
rescue Exception => e
|
469
444
|
handle_socket_error(:SEND, e)
|
data/lib/rbot/message.rb
CHANGED
@@ -195,9 +195,7 @@ module Irc
|
|
195
195
|
@plainmessage = BasicUserMessage.strip_formatting(@message)
|
196
196
|
@message = BasicUserMessage.strip_initial_formatting(@message)
|
197
197
|
|
198
|
-
|
199
|
-
@address = true
|
200
|
-
end
|
198
|
+
@address = true if source == @bot.myself
|
201
199
|
|
202
200
|
end
|
203
201
|
|
@@ -323,9 +321,8 @@ module Irc
|
|
323
321
|
@ctcp = false
|
324
322
|
@action = false
|
325
323
|
|
326
|
-
if target == @bot.myself
|
324
|
+
if @address = (target == @bot.myself)
|
327
325
|
@private = true
|
328
|
-
@address = true
|
329
326
|
@channel = nil
|
330
327
|
@replyto = source
|
331
328
|
else
|
@@ -357,6 +354,8 @@ module Irc
|
|
357
354
|
@action = @ctcp == 'ACTION'
|
358
355
|
debug "Received CTCP command #{@ctcp} with options #{@message} (action? #{@action})"
|
359
356
|
@logmessage = @message.dup
|
357
|
+
@plainmessage = BasicUserMessage.strip_formatting(@message)
|
358
|
+
@message = BasicUserMessage.strip_initial_formatting(@message)
|
360
359
|
end
|
361
360
|
|
362
361
|
# free splitting for plugins
|
@@ -541,7 +540,6 @@ module Irc
|
|
541
540
|
attr_accessor :modes
|
542
541
|
def initialize(bot, server, source, target, message="")
|
543
542
|
super(bot, server, source, target, message)
|
544
|
-
@address = (source == @bot.myself)
|
545
543
|
@modes = []
|
546
544
|
end
|
547
545
|
|
@@ -551,6 +549,20 @@ module Irc
|
|
551
549
|
end
|
552
550
|
end
|
553
551
|
|
552
|
+
# class to manage WHOIS replies
|
553
|
+
class WhoisMessage < BasicUserMessage
|
554
|
+
attr_reader :whois
|
555
|
+
def initialize(bot, server, source, target, whois)
|
556
|
+
super(bot, server, source, target, "")
|
557
|
+
@whois = whois
|
558
|
+
end
|
559
|
+
|
560
|
+
def inspect
|
561
|
+
fields = ' whois=' << whois.inspect
|
562
|
+
super(fields)
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
554
566
|
# class to manage NAME replies
|
555
567
|
class NamesMessage < BasicUserMessage
|
556
568
|
attr_accessor :users
|
@@ -612,7 +624,6 @@ module Irc
|
|
612
624
|
super(bot, server, source, channel, message)
|
613
625
|
@channel = channel
|
614
626
|
# in this case sourcenick is the nick that could be the bot
|
615
|
-
@address = (source == @bot.myself)
|
616
627
|
end
|
617
628
|
end
|
618
629
|
|
data/lib/rbot/rfc2812.rb
CHANGED
@@ -144,6 +144,12 @@ module Irc
|
|
144
144
|
# "<channel> <mode> <mode params>"
|
145
145
|
RPL_CHANNELMODEIS=324
|
146
146
|
|
147
|
+
# "<channel> <unixtime>"
|
148
|
+
RPL_CREATIONTIME=329
|
149
|
+
|
150
|
+
# "<channel> <url>"
|
151
|
+
RPL_CHANNEL_URL=328
|
152
|
+
|
147
153
|
# "<channel> :No topic is set"
|
148
154
|
RPL_NOTOPIC=331
|
149
155
|
|
@@ -975,7 +981,6 @@ module Irc
|
|
975
981
|
#
|
976
982
|
# ==server events currently supported:
|
977
983
|
#
|
978
|
-
# TODO handle errors ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL
|
979
984
|
# TODO handle errors ERR_CHANOPRIVSNEEDED, ERR_CANNOTSENDTOCHAN
|
980
985
|
#
|
981
986
|
# welcome:: server welcome message on connect
|
@@ -1147,13 +1152,7 @@ module Irc
|
|
1147
1152
|
# - "@" is used for secret channels, "*" for private
|
1148
1153
|
# channels, and "=" for others (public channels).
|
1149
1154
|
data[:channeltype] = argv[1]
|
1150
|
-
data[:channel] = argv[2]
|
1151
|
-
|
1152
|
-
chan = @server.get_channel(data[:channel])
|
1153
|
-
unless chan
|
1154
|
-
warning "Received names #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
|
1155
|
-
return
|
1156
|
-
end
|
1155
|
+
data[:channel] = chan = @server.channel(argv[2])
|
1157
1156
|
|
1158
1157
|
users = []
|
1159
1158
|
argv[3].scan(/\S+/).each { |u|
|
@@ -1177,7 +1176,7 @@ module Irc
|
|
1177
1176
|
}
|
1178
1177
|
@tmpusers += users
|
1179
1178
|
when RPL_ENDOFNAMES
|
1180
|
-
data[:channel] = argv[1]
|
1179
|
+
data[:channel] = @server.channel(argv[1])
|
1181
1180
|
data[:users] = @tmpusers
|
1182
1181
|
handle(:names, data)
|
1183
1182
|
@tmpusers = Array.new
|
@@ -1238,12 +1237,17 @@ module Irc
|
|
1238
1237
|
when RPL_DATASTR
|
1239
1238
|
data[:text] = argv[1]
|
1240
1239
|
handle(:datastr, data)
|
1240
|
+
when RPL_AWAY
|
1241
|
+
data[:nick] = user = @server.user(argv[1])
|
1242
|
+
data[:message] = argv[-1]
|
1243
|
+
user.away = data[:message]
|
1244
|
+
handle(:away, data)
|
1241
1245
|
when RPL_WHOREPLY
|
1242
|
-
data[:channel] = argv[1]
|
1246
|
+
data[:channel] = channel = @server.channel(argv[1])
|
1243
1247
|
data[:user] = argv[2]
|
1244
1248
|
data[:host] = argv[3]
|
1245
1249
|
data[:userserver] = argv[4]
|
1246
|
-
data[:nick] = argv[5]
|
1250
|
+
data[:nick] = user = @server.user(argv[5])
|
1247
1251
|
if argv[6] =~ /^(H|G)(\*)?(.*)?$/
|
1248
1252
|
data[:away] = ($1 == 'G')
|
1249
1253
|
data[:ircop] = $2
|
@@ -1256,8 +1260,6 @@ module Irc
|
|
1256
1260
|
end
|
1257
1261
|
data[:hopcount], data[:real_name] = argv[7].split(" ", 2)
|
1258
1262
|
|
1259
|
-
user = @server.get_user(data[:nick])
|
1260
|
-
|
1261
1263
|
user.user = data[:user]
|
1262
1264
|
user.host = data[:host]
|
1263
1265
|
user.away = data[:away] # FIXME doesn't provide the actual message
|
@@ -1266,8 +1268,6 @@ module Irc
|
|
1266
1268
|
# TODO hopcount
|
1267
1269
|
user.real_name = data[:real_name]
|
1268
1270
|
|
1269
|
-
channel = @server.get_channel(data[:channel])
|
1270
|
-
|
1271
1271
|
channel.add_user(user, :silent=>true)
|
1272
1272
|
data[:modes].map { |mode|
|
1273
1273
|
channel.mode[mode].set(user)
|
@@ -1276,9 +1276,85 @@ module Irc
|
|
1276
1276
|
handle(:who, data)
|
1277
1277
|
when RPL_ENDOFWHO
|
1278
1278
|
handle(:eowho, data)
|
1279
|
+
when RPL_WHOISUSER
|
1280
|
+
@whois ||= Hash.new
|
1281
|
+
@whois[:nick] = argv[1]
|
1282
|
+
@whois[:user] = argv[2]
|
1283
|
+
@whois[:host] = argv[3]
|
1284
|
+
@whois[:real_name] = argv[-1]
|
1285
|
+
|
1286
|
+
user = @server.user(@whois[:nick])
|
1287
|
+
user.user = @whois[:user]
|
1288
|
+
user.host = @whois[:host]
|
1289
|
+
user.real_name = @whois[:real_name]
|
1290
|
+
when RPL_WHOISSERVER
|
1291
|
+
@whois ||= Hash.new
|
1292
|
+
@whois[:nick] = argv[1]
|
1293
|
+
@whois[:server] = argv[2]
|
1294
|
+
@whois[:server_info] = argv[-1]
|
1295
|
+
# TODO update user info
|
1296
|
+
when RPL_WHOISOPERATOR
|
1297
|
+
@whois ||= Hash.new
|
1298
|
+
@whois[:nick] = argv[1]
|
1299
|
+
@whois[:operator] = argv[-1]
|
1300
|
+
# TODO update user info
|
1301
|
+
when RPL_WHOISIDLE
|
1302
|
+
@whois ||= Hash.new
|
1303
|
+
@whois[:nick] = argv[1]
|
1304
|
+
user = @server.user(@whois[:nick])
|
1305
|
+
@whois[:idle] = argv[2].to_i
|
1306
|
+
user.idle_since = Time.now - @whois[:idle]
|
1307
|
+
if argv[-1] == 'seconds idle, signon time'
|
1308
|
+
@whois[:signon] = Time.at(argv[3].to_i)
|
1309
|
+
user.signon = @whois[:signon]
|
1310
|
+
end
|
1311
|
+
when RPL_ENDOFWHOIS
|
1312
|
+
@whois ||= Hash.new
|
1313
|
+
@whois[:nick] = argv[1]
|
1314
|
+
data[:whois] = @whois.dup
|
1315
|
+
@whois.clear
|
1316
|
+
handle(:whois, data)
|
1317
|
+
when RPL_WHOISCHANNELS
|
1318
|
+
@whois ||= Hash.new
|
1319
|
+
@whois[:nick] = argv[1]
|
1320
|
+
@whois[:channels] = []
|
1321
|
+
user = @server.user(@whois[:nick])
|
1322
|
+
argv[-1].split.each do |prechan|
|
1323
|
+
pfx = prechan.scan(/[#{@server.supports[:prefix][:prefixes].join}]/)
|
1324
|
+
modes = pfx.map { |p| @server.mode_for_prefix p }
|
1325
|
+
chan = prechan[pfx.length..prechan.length]
|
1326
|
+
|
1327
|
+
channel = @server.channel(chan)
|
1328
|
+
channel.add_user(user, :silent => true)
|
1329
|
+
modes.map { |mode| channel.mode[mode].set(user) }
|
1330
|
+
|
1331
|
+
@whois[:channels] << [chan, modes]
|
1332
|
+
end
|
1279
1333
|
when RPL_CHANNELMODEIS
|
1280
1334
|
parse_mode(serverstring, argv[1..-1], data)
|
1281
1335
|
handle(:mode, data)
|
1336
|
+
when RPL_CREATIONTIME
|
1337
|
+
data[:channel] = @server.channel(argv[1])
|
1338
|
+
data[:time] = Time.at(argv[2].to_i)
|
1339
|
+
data[:channel].creation_time=data[:time]
|
1340
|
+
handle(:creationtime, data)
|
1341
|
+
when RPL_CHANNEL_URL
|
1342
|
+
data[:channel] = @server.channel(argv[1])
|
1343
|
+
data[:url] = argv[2]
|
1344
|
+
data[:channel].url=data[:url].dup
|
1345
|
+
handle(:channel_url, data)
|
1346
|
+
when ERR_NOSUCHNICK
|
1347
|
+
data[:nick] = argv[1]
|
1348
|
+
if user = @server.get_user(data[:nick])
|
1349
|
+
@server.delete_user(user)
|
1350
|
+
end
|
1351
|
+
handle(:nosuchnick, data)
|
1352
|
+
when ERR_NOSUCHCHANNEL
|
1353
|
+
data[:channel] = argv[1]
|
1354
|
+
if channel = @server.get_channel(data[:channel])
|
1355
|
+
@server.delete_channel(channel)
|
1356
|
+
end
|
1357
|
+
handle(:nosuchchannel, data)
|
1282
1358
|
else
|
1283
1359
|
warning "Unknown message #{serverstring.inspect}"
|
1284
1360
|
handle(:unknown, data)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Gilbert
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-09-02 00:00:00 +02:00
|
13
13
|
default_executable: rbot
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- data/rbot/plugins/nslookup.rb
|
86
86
|
- data/rbot/plugins/imdb.rb
|
87
87
|
- data/rbot/plugins/seen.rb
|
88
|
+
- data/rbot/plugins/geoip.rb
|
88
89
|
- data/rbot/plugins/twitter.rb
|
89
90
|
- data/rbot/plugins/spell.rb
|
90
91
|
- data/rbot/plugins/ri.rb
|