quotefiles are now only saved only if they were changed
[rbot] / data / rbot / plugins / nickserv.rb
1 # Automatically lookup nicks in @registry and identify when asked
2 # Takes over proper nick if required and nick is registered
3 # TODO allow custom IDENTIFY and GHOST names
4 # TODO instead of nickserv.wait it would be ideal if we could just
5 # set up "don't send further commands until you receive this particular message"
6
7 class NickServPlugin < Plugin
8   
9   BotConfig.register BotConfigStringValue.new('nickserv.name',
10     :default => "nickserv", :requires_restart => false,
11     :desc => "Name of the nick server (all lowercase)")
12   BotConfig.register BotConfigStringValue.new('nickserv.ident_request',
13     :default => "IDENTIFY", :requires_restart => false,
14     :on_change => Proc.new { |bot, v| bot.plugins.delegate "set_ident_request", v },
15     :desc => "String to look for to see if the nick server is asking us to identify")
16   BotConfig.register BotConfigBooleanValue.new('nickserv.wants_nick',
17     :default => false, :requires_restart => false,
18     :desc => "Set to false if the nick server doesn't expect the nick as a parameter in the identify command")
19   BotConfig.register BotConfigIntegerValue.new('nickserv.wait',
20     :default => 30, :validate => Proc.new { |v| v > 0 }, :requires_restart => false,
21     :desc => "Seconds to wait after sending a message to nickserv, e.g. after ghosting")
22
23   def help(plugin, topic="")
24     case topic
25     when ""
26       return "nickserv plugin: handles nickserv protected IRC nicks. topics password, register, identify, listnicks"
27     when "password"
28       return "nickserv password [<nick>] <passwd>: remember the password for nick <nick> and use it to identify in future"
29     when "register"
30       return "nickserv register [<password> [<email>]]: register the current nick, choosing a random password unless <password> is supplied - current nick must not already be registered for this to work. Also specify email if required by your services"
31     when "identify"
32       return "nickserv identify: identify with nickserv - shouldn't be needed - bot should identify with nickserv immediately on request - however this could be useful after splits or service disruptions, or when you just set the password for the current nick"
33     when "listnicks"
34       return "nickserv listnicks: lists nicknames and associated password the bot knows about - you will need config level auth access to do this one and it will reply by privmsg only"
35     end
36   end
37   
38   def genpasswd
39     # generate a random password
40     passwd = ""
41     8.times do
42       passwd += (rand(26) + (rand(2) == 0 ? 65 : 97) ).chr
43     end
44     return passwd
45   end
46
47   def set_ident_request(val)
48     @ident_request = Regexp.new(val)
49   end
50
51   def initialize
52     super
53     # this plugin only wants to store strings!
54     class << @registry
55       def store(val)
56         val
57       end
58       def restore(val)
59         val
60       end
61     end
62     set_ident_request(@bot.config['nickserv.ident_request'])
63   end
64
65   # Returns the nickserv name
66   def ns_nick
67     @bot.config['nickserv.name']
68   end
69
70   # say something to nickserv
71   def ns_say(msg)
72     @bot.say ns_nick, msg
73   end
74
75   def password(m, params)
76     nick = params[:nick] || @bot.nick
77     passwd = params[:passwd]
78     if nick == @bot.nick
79       ns_say "SET PASSWORD #{passwd}"
80     else
81       m.reply "I'm only changing this in my database, I won't inform #{ns_nick} of the change"
82     end
83     @registry[nick] = passwd
84     m.okay
85   end
86
87   def nick_register(m, params)
88     passwd = params[:passwd] ? params[:passwd] : genpasswd
89     message = "REGISTER #{passwd}"
90     message += " #{params[:email]}" if params[:email]
91     ns_say message
92     @registry[@bot.nick] = passwd
93     m.okay
94   end
95
96   def listnicks(m, params)
97     if @registry.length > 0
98       @registry.each {|k,v|
99         @bot.say m.sourcenick, "#{k} => #{v}"
100       }
101     else
102       m.reply "none known"
103     end
104   end
105
106   def do_identify(nick=@bot.nick)
107     if @registry.has_key?(nick)
108       if @bot.config['nickserv.wants_nick']
109         ns_say "IDENTIFY #{nick} #{@registry[nick]}"
110       else
111         if nick == @bot.nick
112           ns_say "IDENTIFY #{@registry[nick]}"
113         else
114           # We cannot identify for different nicks if we can't use the nickname ...
115           return false
116         end
117       end
118       return true
119     end
120     return nil
121   end
122
123   def identify(m, params)
124     ided = do_identify
125     case ided
126     when true
127       m.okay
128     when false
129       m.reply "I cannot identify for a this nick"
130     when nil
131       m.reply "I dunno the nickserv password for the nickname #{@bot.nick} :("
132     else
133       m.reply "uh ... something went wrong ..."
134     end
135   end
136   
137   def connect
138     do_identify
139   end
140   
141   def nicktaken(nick)
142     if @registry.has_key?(nick)
143       ns_say "GHOST #{nick} #{@registry[nick]}"
144       if do_identify nick
145         sleep @bot.config['nickserv.wait']
146         @bot.nickchg nick
147         # We need to wait after changing nick, otherwise the server
148         # might refuse to execute further commangs, e.g. subsequent JOIN
149         # commands until the nick has changed.
150         sleep @bot.config['nickserv.wait']
151       else
152         debug "Failed to identify for nick #{nick}, cannot take over"
153       end
154     end
155   end
156
157   def listen(m)
158     return unless(m.kind_of? NoticeMessage)
159
160     if (m.sourcenick.downcase == ns_nick.downcase && m.message =~ @ident_request)
161       debug "nickserv asked us to identify for nick #{@bot.nick}"
162       do_identify
163     end
164   end
165
166 end
167 plugin = NickServPlugin.new
168 plugin.map 'nickserv password [:nick] :passwd', :action => "password"
169 plugin.map 'nickserv register :passwd :email', :action => 'nick_register',
170            :defaults => {:passwd => false, :email => false}
171 plugin.map 'nickserv listnicks', :action => "listnicks"
172 plugin.map 'nickserv identify', :action => "identify"
173
174 plugin.default_auth('*', false)
175