mod_spox 0.0.1 → 0.0.2

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/CHANGELOG CHANGED
@@ -1,2 +1,17 @@
1
+ 0.0.2 Release (Alpha status)
2
+ * New features available from the following new plugins:
3
+ * Karma
4
+ * Pinger
5
+ * Search
6
+ * Triggers
7
+ * Roulette
8
+ * Urban Dictionary
9
+ * Banner
10
+ * Fixed plugin loading problem in PluginLoader
11
+ * Fixed an issue with database creation in SQLite
12
+ * Fixed Pipeline to continue processing message when a plugin raises and exception
13
+ * Reworked authentication mechanisms. Now using group based permissions
14
+ * Added various convenience methods
15
+
1
16
  0.0.1 Release
2
17
  * Initial release. No changes to report.
data/bin/mod_spox CHANGED
@@ -12,7 +12,7 @@
12
12
  end
13
13
  }
14
14
 
15
- $BOTVERSION='0.0.1'
15
+ $BOTVERSION='0.0.2'
16
16
  $VERBOSITY = 0
17
17
 
18
18
  begin
@@ -0,0 +1,67 @@
1
+ class Karma < ModSpox::Plugin
2
+
3
+ include Messages::Outgoing
4
+
5
+ def initialize(pipeline)
6
+ super(pipeline)
7
+ KarmaDatatype::Karma.create_table unless KarmaDatatype::Karma.table_exists?
8
+ Models::Signature.find_or_create(:signature => 'karma (\S+)', :plugin => name, :method => 'score', :description => 'Returns karma for given thing').params = [:thing]
9
+ Models::Signature.find_or_create(:signature => 'karma reset (\S+)', :plugin => name, :method => 'reset',
10
+ :group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Reset a karma score').params = [:thing]
11
+ @pipeline.hook(self, :check, :Incoming_Privmsg)
12
+ @thing_maxlen = 32
13
+ @karma_regex = /(\(.{1,#@thing_maxlen}?\)|\S{1,#@thing_maxlen})([+-]{2})(?:\s|$)/
14
+ end
15
+
16
+ def check(message)
17
+ if(message.is_public?)
18
+ message.message.scan(@karma_regex) do |match|
19
+ thing, adj = match
20
+ thing.downcase!
21
+ thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..1] == ')'
22
+ adj = adj == '++' ? +1 : -1
23
+ karma = KarmaDatatype::Karma.find_or_create(:thing => thing, :channel_id => message.target.pk)
24
+ karma.set(:score => karma.score + adj)
25
+ end
26
+ end
27
+ end
28
+
29
+ def score(message, params)
30
+ params[:thing].downcase!
31
+ return unless message.is_public?
32
+ karma = KarmaDatatype::Karma.filter(:thing => params[:thing], :channel_id => message.target.pk).first
33
+ if(karma)
34
+ @pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 is #{karma.score}")
35
+ else
36
+ @pipeline << Privmsg.new(message.replyto, "\2Error:\2 #{params[:thing]} has no karma")
37
+ end
38
+ end
39
+
40
+ def reset(message, params)
41
+ params[:thing].downcase!
42
+ return unless message.is_public?
43
+ karma = KarmaDatatype::Karma.filter(:thing => params[:thing], :channel_id => message.target.pk).first
44
+ if(karma)
45
+ karma.set(:score => 0)
46
+ @pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 has been reset")
47
+ else
48
+ @pipeline << Privmsg.new(message.replyto, "\2Error:\2 #{params[:thing]} has no karma")
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ module KarmaDatatype
55
+ class Karma < Sequel::Model
56
+ set_schema do
57
+ primary_key :id
58
+ text :thing, :null => false, :unique => true
59
+ integer :score, :null => false, :default => 0
60
+ foreign_key :channel_id, :table => :channels
61
+ end
62
+
63
+ def channel
64
+ ModSpox::Models::Channel[channel_id]
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,11 @@
1
+ class Pinger < ModSpox::Plugin
2
+
3
+ def initialize(pipeline)
4
+ super(pipeline)
5
+ Models::Signature.find_or_create(:signature => 'ping', :plugin => name, :method => 'ping')
6
+ end
7
+
8
+ def ping(message, params)
9
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "#{message.source.nick}: pong")
10
+ end
11
+ end
@@ -0,0 +1,233 @@
1
+ class Roulette < ModSpox::Plugin
2
+
3
+ include Models
4
+
5
+ def initialize(pipeline)
6
+ super(pipeline)
7
+ Signature.find_or_create(:signature => 'roulette', :plugin => name, :method => 'roulette')
8
+ Signature.find_or_create(:signature => 'suicide', :plugin => name, :method => 'suicide')
9
+ Signature.find_or_create(:signature => 'shoot (\S+)', :plugin => name, :method => 'shoot').params = [:nick]
10
+ Signature.find_or_create(:signature => 'roulette topten', :plugin => name, :method => 'topten')
11
+ Signature.find_or_create(:signature => 'roulette stats ?(\S+)?', :plugin => name, :method => 'stats').params = [:nick]
12
+ Game.create_table unless Game.table_exists?
13
+ Info.create_table unless Info.table_exists?
14
+ end
15
+
16
+ # message:: ModSpox::Messages::Incoming::Privmsg
17
+ # params:: empty
18
+ # Play roulette
19
+ def roulette(message, params)
20
+ return unless message.is_public?
21
+ do_shot(message.source, message.target)
22
+ end
23
+
24
+ # message:: ModSpox::Messages::Incoming::Privmsg
25
+ # params:: empty
26
+ # Kill self
27
+ def suicide(message, params)
28
+ return unless message.is_public?
29
+ do_suicide(message.source, message.target)
30
+ end
31
+
32
+ # message:: ModSpox::Messages::Incoming::Privmsg
33
+ # params:: nick
34
+ # Shoot other person playing current game
35
+ def shoot(message, params)
36
+ return unless message.is_public?
37
+ cur_game = game(message.target)
38
+ nick = Nick.filter(:nick => params[:nick])
39
+ if(cur_game.shots == 1 && nick && Info.filter(:game_id => cur_game.pk, :nick_id => nick.pk))
40
+ do_shot(nick, message.target)
41
+ else
42
+ do_suicide(message.source, message.target)
43
+ end
44
+ end
45
+
46
+ # message:: ModSpox::Messages::Incoming::Privmsg
47
+ # params:: empty
48
+ # List topten players
49
+ def topten(message, params)
50
+ return unless message.is_public?
51
+ ds = Database.db[:infos].left_outer_join(:games, :id => :game_id)
52
+ ds.select!(:nick_id, :COUNT[:win] => :wins).where!(:channel_id => message.target.pk, :win => true).group!(:nick_id).order!(:wins.DESC).limit!(10)
53
+ Logger.log(ds.sql)
54
+ ids = ds.map(:nick_id)
55
+ top = []
56
+ ids.each do |id|
57
+ nick = Nick[id]
58
+ top << "#{nick.nick} (#{win_loss_ratio(nick, message.target)}% survival with #{games_won(nick, message.target)} wins)"
59
+ end
60
+ if(top.empty?)
61
+ reply(message.replyto, "\2Error:\2 No one has survived")
62
+ else
63
+ reply(message.replyto, "Roulette topten: #{top.join(', ')}")
64
+ end
65
+ end
66
+
67
+ # message:: ModSpox::Messages::Incoming::Privmsg
68
+ # params:: empty | nick
69
+ # List statistics on self or given nick
70
+ def stats(message, params)
71
+ return unless message.is_public?
72
+ if(params[:nick])
73
+ nick = Nick.filter(:nick => params[:nick]).first
74
+ unless(nick)
75
+ reply(message.replyto, "\2Error:\2 Failed to find record of #{params[:nick]}")
76
+ return
77
+ end
78
+ else
79
+ nick = message.source
80
+ end
81
+ reply(message.replyto, "\2Roulette stats #{nick.nick}:\2 #{win_loss_ratio(nick, message.target)}% survival rate. Has won #{games_won(nick, message.target)} games and lost #{games_lost(nick, message.target)} games, taking a total of #{total_shots(nick, message.target)} shots.")
82
+ end
83
+
84
+ private
85
+
86
+ # nick:: ModSpox::Models::Nick
87
+ # channel:: ModSpox::Models::Channel
88
+ # Report win/loss ratio for nick
89
+ def win_loss_ratio(nick, channel)
90
+ if(games_lost(nick, channel) > 0)
91
+ val = (games_won(nick, channel).to_f / games_total(nick, channel).to_f) * 100
92
+ elsif(games_lost(nick, channel) == 0 && games_won(nick, channel) == 0)
93
+ val = 0
94
+ else
95
+ val = 100
96
+ end
97
+ return sprintf("%.2f", val)
98
+ end
99
+
100
+ # nick:: ModSpox::Models::Nick
101
+ # channel:: ModSpox::Models::Channel
102
+ # Return number of games nick has won
103
+ def games_won(nick, channel)
104
+ Info.left_outer_join(:games, :id => :game_id).filter{:nick_id == nick.pk && :channel_id == channel.pk && :win == true}.size
105
+ end
106
+
107
+ # nick:: ModSpox::Models::Nick
108
+ # channel:: ModSpox::Models::Channel
109
+ # Return number of games nick has lost
110
+ def games_lost(nick, channel)
111
+ games_total(nick, channel) - games_won(nick, channel)
112
+ end
113
+
114
+ # nick:: ModSpox::Models::Nick
115
+ # channel:: ModSpox::Models::Channel
116
+ # Return number of games nick has played
117
+ def games_total(nick, channel)
118
+ Info.left_outer_join(:games, :id => :game_id).filter{:nick_id == nick.pk && :channel_id == channel.pk}.exclude(:game_id => game(channel).pk).size
119
+ end
120
+
121
+ # nick:: ModSpox::Models::Nick
122
+ # channel:: ModSpox::Models::Channel
123
+ # Return number of shots nick has taken
124
+ def total_shots(nick, channel)
125
+ v = Info.left_outer_join(:games, :id => :game_id).filter{:nick_id == nick.pk && :channel_id == channel.pk}.exclude(:game_id => game(channel).pk).sum(:infos__shots)
126
+ v = 0 unless v
127
+ return v
128
+ end
129
+
130
+ # nick:: ModSpox::Models::Nick
131
+ # channel:: ModSpox::Models::Channel
132
+ # Fire shot
133
+ def do_shot(nick, channel)
134
+ begin
135
+ shot(nick, channel)
136
+ reply(channel, "#{nick.nick}: *click*")
137
+ rescue Bullet => bang
138
+ game_over(nick, bang.game)
139
+ #TODO: add banner here
140
+ reply(channel, "#{nick.nick}: *BANG*")
141
+ end
142
+ end
143
+
144
+ # nick:: ModSpox::Models::Nick
145
+ # channel:: ModSpox::Models::Channel
146
+ # Commit suicide
147
+ def do_suicide(nick, channel)
148
+ begin
149
+ 6.times do
150
+ shot(nick, channel)
151
+ end
152
+ rescue Bullet => bang
153
+ game_over(nick, bang.game)
154
+ #TODO: add banner here
155
+ reply(channel, "#{nick.nick}: *BANG*")
156
+ end
157
+ end
158
+
159
+ # channel:: ModSpox::Models::Channel
160
+ # Return current game
161
+ def game(channel)
162
+ game = Game.filter{:shots > 0 && :channel_id == channel.pk}.first
163
+ unless(game)
164
+ chamber = rand(5) + 1
165
+ game = Game.new(:chamber => chamber, :shots => chamber, :channel_id => channel.pk)
166
+ game.save
167
+ end
168
+ return game
169
+ end
170
+
171
+ # nick:: ModSpox::Models::Nick
172
+ # channel:: ModSpox::Models::Channel
173
+ # Process shot
174
+ def shot(nick, channel)
175
+ cur_game = game(channel)
176
+ info = Info.find_or_create(:game_id => cur_game.pk, :nick_id => nick.pk)
177
+ info.set(:shots => info.shots + 1)
178
+ cur_game.set(:shots => cur_game.shots - 1)
179
+ raise Bullet.new(cur_game) if cur_game.shots < 1
180
+ end
181
+
182
+ # nick:: ModSpox::Models::Nick
183
+ # game:: Game
184
+ # Return number of games nick has won
185
+ def game_over(nick, game)
186
+ Info.filter(:game_id => game.pk).each do |info|
187
+ info.set(:win => true) unless info.nick_id == nick.pk
188
+ end
189
+ end
190
+
191
+ class Game < Sequel::Model
192
+ set_schema do
193
+ primary_key :id
194
+ timestamp :stamp, :null => false
195
+ integer :shots, :null => false, :default => 6
196
+ integer :chamber, :null => false, :default => 1
197
+ foreign_key :channel_id, :null => false, :table => :channels
198
+ end
199
+
200
+ before_create do
201
+ self.stamp = Time.now
202
+ end
203
+
204
+ def channel
205
+ Models::Channel[channel_id]
206
+ end
207
+ end
208
+
209
+ class Info < Sequel::Model
210
+ set_schema do
211
+ primary_key :id
212
+ integer :shots, :null => false, :default => 0
213
+ boolean :win, :null => false, :default => false
214
+ foreign_key :nick_id, :null => false, :table => :nicks
215
+ foreign_key :game_id, :null => false, :table => :games
216
+ end
217
+
218
+ def nick
219
+ Models::Nick[nick_id]
220
+ end
221
+
222
+ def game
223
+ Models::Game[game_id]
224
+ end
225
+ end
226
+
227
+ class Bullet < Exception
228
+ attr_reader :game
229
+ def initialize(game)
230
+ @game = game
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,33 @@
1
+ require 'net/http'
2
+ require 'cgi'
3
+ class Search < ModSpox::Plugin
4
+
5
+ include Messages::Outgoing
6
+
7
+ def initialize(pipeline)
8
+ super(pipeline)
9
+ Models::Signature.find_or_create(:signature => 'search (\d+)? ?(.+)', :plugin => name, :method => 'search', :description => 'Search the internet').params = [:number, :terms]
10
+ end
11
+
12
+ def search(message, params)
13
+ limit = params[:number] ? params[:number].to_i : 1
14
+ limit = limit > 5 || limit < 1 ? 1 : limit
15
+ begin
16
+ resp = Net::HTTP.new('www.scroogle.org', 80).request_get("/cgi-bin/nbbw.cgi?Gw=#{CGI::escape(params[:terms])}", nil)
17
+ resp.value
18
+ page = resp.body
19
+ results = []
20
+ page.scan(/<A Href="(.+?)">(.+?)<\/a>/) do |url,title|
21
+ title.gsub!(/<.*?>/, '')
22
+ title = CGI::unescapeHTML(title)
23
+ results.push [title, url]
24
+ end
25
+ @pipeline << Privmsg.new(message.replyto, "Search results for \2#{params[:terms]}:\2")
26
+ results.slice(0, limit).each do |title, url|
27
+ @pipeline << Privmsg.new(message.replyto, "#{title} -> #{Helpers.tinyurl(url)} [#{url.scan(/^http:\/\/.+?\//)[0]}]")
28
+ end
29
+ rescue Object => boom
30
+ @pipeline << Privmsg.new(message.replyto, "Failed to find any results for: #{params[:terms]} Reason: #{boom}")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ require 'soap/rpc/driver'
2
+
3
+ class UrbanDictionary < ModSpox::Plugin
4
+
5
+ include Messages::Outgoing
6
+ include Models
7
+
8
+ def initialize(pipeline)
9
+ super(pipeline)
10
+ Signature.find_or_create(:signature => 'udefine (?!key)(\d+)? ?(.+)', :plugin => name, :method => 'define',
11
+ :description => 'Find the definition of a word or phrase').params = [:number, :term]
12
+ Signature.find_or_create(:signature => 'udefine key (.+)', :plugin => name, :method => 'key',
13
+ :group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Set API key').params = [:key]
14
+ end
15
+
16
+ def define(message, params)
17
+ key = Config[:urban_key]
18
+ if(key)
19
+ site = 'http://api.urbandictionary.com/soap'
20
+ result = params[:number] ? params[:number].to_i - 1 : 0
21
+ begin
22
+ udict = SOAP::RPC::Driver.new(site, 'urn:UrbanSearch')
23
+ udict.add_method('lookup', 'key', 'term')
24
+ defs = udict.lookup(key, params[:term])
25
+ if defs.size < result + 1
26
+ @pipeline << Privmsg.new(message.replyto, "Error: Definition number #{result+1} for term: #{params[:term]} not found.")
27
+ else
28
+ defin = defs[result].definition.length > 500 ? defs[result].definition.slice(0..500) + " *[CUT]*" : defs[result].definition
29
+ exp = defs[result].example.length > 500 ? defs[result].example.slice(0..500) + " *[CUT]*" : defs[result].example
30
+ @pipeline << Privmsg.new(message.replyto, "Definition for \2#{defs[result].word}:\2")
31
+ @pipeline << Privmsg.new(message.replyto, defin)
32
+ @pipeline << Privmsg.new(message.replyto, "\2Example usage:\2 #{exp}") if exp.length > 0
33
+ end
34
+ rescue Timeout::Error
35
+ @pipeline << Privmsg.new(message.replyto, "Failed to establish connection to server.")
36
+ rescue Object => boom
37
+ @pipeline << Privmsg.new(message.replyto, "Unexpected error encountered: #{boom}")
38
+ end
39
+ else
40
+ @pipeline << Privmsg.new(message.replyto, "\2Error:\2 No valid key available for dictionary")
41
+ end
42
+ end
43
+
44
+ def key(message, params)
45
+ if(message.is_public?)
46
+ @pipeline << Privmsg.new(message.replyto, 'I don\'t set keys in public')
47
+ else
48
+ Config[:urban_key] = params[:key]
49
+ @pipeline << Privmsg.new(message.replyto, 'Urban Dictionary API key has been set.')
50
+ end
51
+ end
52
+
53
+ end
@@ -38,10 +38,11 @@ class Authenticator < ModSpox::Plugin
38
38
  # params:: Signature parameters
39
39
  # Authenticate a user by password
40
40
  def authenticate(message, params)
41
+ return unless message.is_private?
41
42
  if(message.is_private? && message.source.auth.check_password(params[:password]))
42
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, 'Authentication was successful')
43
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'Authentication was successful')
43
44
  else
44
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, 'Authentication failed')
45
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'Authentication failed')
45
46
  end
46
47
  end
47
48
 
@@ -55,9 +56,9 @@ class Authenticator < ModSpox::Plugin
55
56
  a = Models::Auth.find_or_create(:mask => Regexp.new(params[:mask]).source)
56
57
  a.group = group
57
58
  a.save
58
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, 'Mask has been successfully added to authentication table')
59
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'Mask has been successfully added to authentication table')
59
60
  rescue Object => boom
60
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Authentication failed to add mask. Reason: #{boom}")
61
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Authentication failed to add mask. Reason: #{boom}")
61
62
  end
62
63
  end
63
64
 
@@ -71,9 +72,9 @@ class Authenticator < ModSpox::Plugin
71
72
  group = Models::Group.filter(:name => g).first
72
73
  auth.group = group if group
73
74
  end
74
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Mask groups have been updated")
75
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Mask groups have been updated")
75
76
  else
76
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Failed to find mask with ID: #{params[:id]}")
77
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Failed to find mask with ID: #{params[:id]}")
77
78
  end
78
79
  end
79
80
 
@@ -87,9 +88,9 @@ class Authenticator < ModSpox::Plugin
87
88
  group = Models::Group.filter(:name => g).first
88
89
  auth.remove_group(group) if group
89
90
  end
90
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Mask groups have been updated")
91
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Mask groups have been updated")
91
92
  else
92
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Failed to find mask with ID: #{params[:id]}")
93
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Failed to find mask with ID: #{params[:id]}")
93
94
  end
94
95
  end
95
96
 
@@ -97,13 +98,13 @@ class Authenticator < ModSpox::Plugin
97
98
  # params:: Signature parameters
98
99
  # List all authentication masks
99
100
  def list_mask(message, params)
100
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, 'Authentication Mask Listing:')
101
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'Authentication Mask Listing:')
101
102
  auths = []
102
103
  Models::Auth.where('mask is not null').each{|a| auths << a}
103
104
  auths.each do |a|
104
105
  groups = []
105
106
  a.groups.each{|g| groups << g.name}
106
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "\2ID:\2 #{a.pk}: \2mask:\2 #{a.mask} \2groups:\2 #{groups.join(', ')}")
107
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "\2ID:\2 #{a.pk}: \2mask:\2 #{a.mask} \2groups:\2 #{groups.join(', ')}")
107
108
  end
108
109
  end
109
110
 
@@ -114,9 +115,9 @@ class Authenticator < ModSpox::Plugin
114
115
  auth = Models::Auth[params[:id].to_i]
115
116
  if(auth)
116
117
  auth.destroy
117
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Authentication mask with ID #{params[:id]} was deleted")
118
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Authentication mask with ID #{params[:id]} was deleted")
118
119
  else
119
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "\2Failed\2: Could not find an authentication mask with ID: #{params[:id]}")
120
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "\2Failed\2: Could not find an authentication mask with ID: #{params[:id]}")
120
121
  end
121
122
  end
122
123
 
@@ -130,7 +131,7 @@ class Authenticator < ModSpox::Plugin
130
131
  else
131
132
  nick.auth.set(:services => false)
132
133
  end
133
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Nick #{params[:nick]} has been updated. Services for authentication has been set to #{params[:ident]}")
134
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Nick #{params[:nick]} has been updated. Services for authentication has been set to #{params[:ident]}")
134
135
  end
135
136
 
136
137
 
@@ -140,7 +141,7 @@ class Authenticator < ModSpox::Plugin
140
141
  def nick_pass(message, params)
141
142
  nick = Models::Nick.find_or_create(:nick => params[:nick])
142
143
  nick.auth.password = params[:password]
143
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Nick #{params[:nick]} has been updated. Password has been set.")
144
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Nick #{params[:nick]} has been updated. Password has been set.")
144
145
  end
145
146
 
146
147
  # message:: ModSpox::Messages::Incoming::Privmsg
@@ -149,7 +150,7 @@ class Authenticator < ModSpox::Plugin
149
150
  def nick_clear(message, params)
150
151
  nick = Models::Nick.find_or_create(:nick => params[:nick])
151
152
  nick.auth.password = nil
152
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Nick #{params[:nick]} has been updated. Password has been set.")
153
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Nick #{params[:nick]} has been updated. Password has been set.")
153
154
  end
154
155
 
155
156
  # message:: ModSpox::Messages::Incoming::Privmsg
@@ -162,12 +163,12 @@ class Authenticator < ModSpox::Plugin
162
163
  info << "\2INFO [#{nick.nick}]:\2"
163
164
  groups = []
164
165
  nick.auth_groups.each{|g| groups << g.name}
165
- info << "Groups: #{groups.join(', ')}."
166
+ info << "Groups: #{groups.uniq.sort.join(', ')}."
166
167
  nick.auth.password.nil? ? info << 'Password has not been set.' : info << 'Password has been set.'
167
168
  nick.auth.services ? info << 'Nickserv ident is enabled.' : info << 'Nickserv ident is disabled.'
168
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "#{info.join(' ')}")
169
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "#{info.join(' ')}")
169
170
  else
170
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "I have no record of nick: #{params[:nick]}")
171
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "I have no record of nick: #{params[:nick]}")
171
172
  end
172
173
  end
173
174
 
@@ -179,9 +180,9 @@ class Authenticator < ModSpox::Plugin
179
180
  nick = Models::Nick.find_or_create(:nick => params[:nick])
180
181
  if(group)
181
182
  nick.group = group
182
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Nick #{params[:nick]} has been added to the group: #{params[:group]}")
183
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Nick #{params[:nick]} has been added to the group: #{params[:group]}")
183
184
  else
184
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Failed to find authentication group: #{params[:group]}")
185
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Failed to find authentication group: #{params[:group]}")
185
186
 
186
187
  end
187
188
  end
@@ -194,10 +195,10 @@ class Authenticator < ModSpox::Plugin
194
195
  nick = Models::Nick.filter(:nick => params[:nick]).first
195
196
  if(group && nick)
196
197
  nick.remove_group(group)
197
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Removed #{params[:nick]} from the #{params[:group]} authentication group.")
198
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Removed #{params[:nick]} from the #{params[:group]} authentication group.")
198
199
  else
199
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Failed to find nick: #{params[:nick]}") unless nick
200
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Failed to find group: #{params[:group]}") unless group
200
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Failed to find nick: #{params[:nick]}") unless nick
201
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Failed to find group: #{params[:group]}") unless group
201
202
  end
202
203
  end
203
204
 
@@ -214,7 +215,7 @@ class Authenticator < ModSpox::Plugin
214
215
  def list_groups(message, params)
215
216
  groups = []
216
217
  Models::Group.all.each{|g| groups << g.name}
217
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "\2Groups:\2 #{groups.join(', ')}")
218
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "\2Groups:\2 #{groups.join(', ')}")
218
219
  end
219
220
 
220
221
  # message:: ModSpox::Messages::Incoming::Privmsg
@@ -236,9 +237,9 @@ class Authenticator < ModSpox::Plugin
236
237
  output = []
237
238
  output << "\2Nicks:\2 #{nicks.join(', ')}" if nicks.size > 0
238
239
  output << "\2Masks:\2 #{masks.join(' | ')}" if masks.size > 0
239
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "\2Group #{params[:group]}:\2 #{output.join('. ')}")
240
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "\2Group #{params[:group]}:\2 #{output.join('. ')}")
240
241
  else
241
- @pipeline << Messages::Outgoing::Privmsg.new(message.source.nick, "Failed to find group named: #{params[:group]}")
242
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Failed to find group named: #{params[:group]}")
242
243
  end
243
244
  end
244
245