mod_spox 0.1.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/CHANGELOG +36 -0
  2. data/INSTALL +2 -2
  3. data/README +0 -1
  4. data/bin/mod_spox +51 -12
  5. data/data/mod_spox/extras/AOLSpeak.rb +5 -18
  6. data/data/mod_spox/extras/AutoKick.rb +44 -23
  7. data/data/mod_spox/extras/AutoMode.rb +2 -5
  8. data/data/mod_spox/extras/AutoRejoin.rb +21 -0
  9. data/data/mod_spox/extras/Bouncer.rb +10 -10
  10. data/data/mod_spox/extras/Bytes.rb +12 -0
  11. data/data/mod_spox/extras/Confess.rb +131 -52
  12. data/data/mod_spox/extras/DCC.rb +189 -0
  13. data/data/mod_spox/extras/DevWatch.rb +32 -33
  14. data/data/mod_spox/extras/FloodKicker.rb +129 -0
  15. data/data/mod_spox/extras/GoogleIt.rb +13 -0
  16. data/data/mod_spox/extras/Headers.rb +31 -4
  17. data/data/mod_spox/extras/Karma.rb +103 -49
  18. data/data/mod_spox/extras/Logger.rb +45 -30
  19. data/data/mod_spox/extras/LolSpeak.rb +1 -1
  20. data/data/mod_spox/extras/NickServ.rb +83 -0
  21. data/data/mod_spox/extras/PhpCli.rb +12 -15
  22. data/data/mod_spox/extras/PhpFuncLookup.rb +57 -25
  23. data/data/mod_spox/extras/Quotes.rb +5 -4
  24. data/data/mod_spox/extras/RegexTracker.rb +160 -0
  25. data/data/mod_spox/extras/Roulette.rb +22 -23
  26. data/data/mod_spox/extras/Search.rb +3 -2
  27. data/data/mod_spox/extras/Slashdot.rb +35 -0
  28. data/data/mod_spox/extras/Topten.rb +5 -5
  29. data/data/mod_spox/extras/TracTicket.rb +68 -0
  30. data/data/mod_spox/extras/Translate.rb +69 -30
  31. data/data/mod_spox/extras/Twitter.rb +372 -0
  32. data/data/mod_spox/extras/UrbanDictionary.rb +21 -12
  33. data/data/mod_spox/extras/Weather.rb +1 -1
  34. data/data/mod_spox/plugins/Authenticator.rb +63 -30
  35. data/data/mod_spox/plugins/Banner.rb +164 -151
  36. data/data/mod_spox/plugins/Helper.rb +18 -7
  37. data/data/mod_spox/plugins/PluginLoader.rb +46 -22
  38. data/data/mod_spox/plugins/PoolConfig.rb +52 -0
  39. data/data/mod_spox/plugins/Quitter.rb +1 -1
  40. data/data/mod_spox/plugins/Status.rb +28 -0
  41. data/lib/mod_spox/Action.rb +20 -3
  42. data/lib/mod_spox/BaseConfig.rb +1 -0
  43. data/lib/mod_spox/Bot.rb +98 -75
  44. data/lib/mod_spox/BotConfig.rb +14 -6
  45. data/lib/mod_spox/ConfigurationWizard.rb +94 -105
  46. data/lib/mod_spox/Database.rb +33 -13
  47. data/lib/mod_spox/Helpers.rb +67 -38
  48. data/lib/mod_spox/Loader.rb +25 -5
  49. data/lib/mod_spox/Logger.rb +20 -62
  50. data/lib/mod_spox/MessageFactory.rb +34 -25
  51. data/lib/mod_spox/Monitors.rb +5 -0
  52. data/lib/mod_spox/Pipeline.rb +40 -51
  53. data/lib/mod_spox/Plugin.rb +40 -9
  54. data/lib/mod_spox/PluginManager.rb +46 -38
  55. data/lib/mod_spox/Pool.rb +129 -143
  56. data/lib/mod_spox/Socket.rb +41 -50
  57. data/lib/mod_spox/Sockets.rb +211 -0
  58. data/lib/mod_spox/Timer.rb +86 -69
  59. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  60. data/lib/mod_spox/handlers/Created.rb +1 -1
  61. data/lib/mod_spox/handlers/Handler.rb +9 -0
  62. data/lib/mod_spox/handlers/Invite.rb +1 -1
  63. data/lib/mod_spox/handlers/Join.rb +2 -2
  64. data/lib/mod_spox/handlers/Kick.rb +1 -1
  65. data/lib/mod_spox/handlers/LuserChannels.rb +1 -1
  66. data/lib/mod_spox/handlers/LuserOp.rb +1 -1
  67. data/lib/mod_spox/handlers/LuserUnknown.rb +1 -1
  68. data/lib/mod_spox/handlers/Mode.rb +2 -2
  69. data/lib/mod_spox/handlers/MyInfo.rb +1 -1
  70. data/lib/mod_spox/handlers/Names.rb +1 -1
  71. data/lib/mod_spox/handlers/Nick.rb +20 -3
  72. data/lib/mod_spox/handlers/NickInUse.rb +3 -3
  73. data/lib/mod_spox/handlers/Notice.rb +5 -15
  74. data/lib/mod_spox/handlers/Part.rb +1 -1
  75. data/lib/mod_spox/handlers/Ping.rb +1 -1
  76. data/lib/mod_spox/handlers/Pong.rb +1 -1
  77. data/lib/mod_spox/handlers/Privmsg.rb +2 -2
  78. data/lib/mod_spox/handlers/Quit.rb +1 -1
  79. data/lib/mod_spox/handlers/Topic.rb +2 -1
  80. data/lib/mod_spox/handlers/Welcome.rb +3 -3
  81. data/lib/mod_spox/handlers/Who.rb +9 -7
  82. data/lib/mod_spox/handlers/Whois.rb +29 -16
  83. data/lib/mod_spox/handlers/YourHost.rb +1 -1
  84. data/lib/mod_spox/messages/incoming/Privmsg.rb +38 -19
  85. data/lib/mod_spox/messages/internal/DCCListener.rb +12 -0
  86. data/lib/mod_spox/messages/internal/DCCRequest.rb +12 -0
  87. data/lib/mod_spox/messages/internal/DCCSocket.rb +19 -0
  88. data/lib/mod_spox/messages/internal/StatusRequest.rb +2 -1
  89. data/lib/mod_spox/messages/outgoing/Privmsg.rb +21 -5
  90. data/lib/mod_spox/migrations/001_initialize_models.rb +115 -0
  91. data/lib/mod_spox/models/Auth.rb +24 -16
  92. data/lib/mod_spox/models/AuthGroup.rb +4 -3
  93. data/lib/mod_spox/models/Channel.rb +20 -12
  94. data/lib/mod_spox/models/ChannelMode.rb +2 -2
  95. data/lib/mod_spox/models/Config.rb +11 -3
  96. data/lib/mod_spox/models/Group.rb +6 -1
  97. data/lib/mod_spox/models/Nick.rb +93 -33
  98. data/lib/mod_spox/models/NickChannel.rb +8 -6
  99. data/lib/mod_spox/models/NickGroup.rb +16 -0
  100. data/lib/mod_spox/models/NickMode.rb +3 -3
  101. data/lib/mod_spox/models/Server.rb +6 -2
  102. data/lib/mod_spox/models/Setting.rb +12 -6
  103. data/lib/mod_spox/models/Signature.rb +7 -13
  104. data/lib/mod_spox/models/Trigger.rb +1 -1
  105. metadata +125 -100
@@ -13,11 +13,19 @@ class Confess < ModSpox::Plugin
13
13
  begin
14
14
  require 'htmlentities'
15
15
  rescue Object => boom
16
- Logger.log('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
16
+ Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
17
17
  raise Exceptions::BotException.new("Missing required HTMLEntities library")
18
18
  end
19
- Confession.create_table unless Confession.table_exists?
20
- Signature.find_or_create(:signature => 'confess ?(.+)?', :plugin => name, :method => 'confess',
19
+ begin
20
+ Confession.db = Sequel.sqlite(BotConfig[:userpath] + '/confessions.db')
21
+ rescue Object => boom
22
+ Logger.warn("Error: Unable to initialize this plugin: #{boom}")
23
+ raise Exceptions::BotException.new("Failed to create database: #{boom}")
24
+ end
25
+ Confession.build_confession && Confession.create_table unless Confession.table_exists?
26
+ Signature.find_or_create(:signature => 'confess', :plugin => name, :method => 'confess',
27
+ :description => 'Print a confession')
28
+ Signature.find_or_create(:signature => 'confess (?!score|count|fetcher|\+\+|\-\-)(.+)?', :plugin => name, :method => 'confess',
21
29
  :description => 'Print a confession').params = [:term]
22
30
  Signature.find_or_create(:signature => 'confess(\+\+|\-\-) ?(\d+)?', :plugin => name, :method => 'score',
23
31
  :description => 'Score a confession').params = [:score, :id]
@@ -30,62 +38,100 @@ class Confess < ModSpox::Plugin
30
38
  Config[:confess] = 'nofetch' if Config[:confess].nil?
31
39
  @last_confession = {}
32
40
  @fetch = false
33
- @mutex = Mutex.new
34
41
  @coder = HTMLEntities.new
42
+ @timer = {:action => nil, :id => nil}
43
+ @lock = Mutex.new
35
44
  start_fetcher if Config[:confess] == 'fetch'
36
45
  end
37
46
 
47
+ def destroy
48
+ Confession.db.disconnect
49
+ end
50
+
38
51
  def confess(message, params)
39
- c = nil
40
- reg = false
41
- if(params[:term])
42
- if(params[:term] =~ /^\d+$/)
43
- c = Confession[params[:term].to_i]
52
+ begin
53
+ c = nil
54
+ pk = nil
55
+ @lock.synchronize do
56
+ if(params[:term])
57
+ return if params[:term] == 'count'
58
+ if(params[:term] =~ /^\d+$/)
59
+ c = Confession[params[:term].to_i]
60
+ else
61
+ cs = Confession.search(params[:term])
62
+ Logger.info("Size of confession results: #{cs.size}")
63
+ rand_idx = rand(cs.size - 1)
64
+ rand_id = cs[rand_idx].to_i
65
+ Logger.info("Random index to be used: #{rand_idx}")
66
+ Logger.info("Random ID to be used for confession: #{rand_id}")
67
+ c = Confession[rand_id]
68
+ end
69
+ else
70
+ c = Confession[rand(Confession.count) - 1]
71
+ end
72
+ unless c.nil?
73
+ pk = c.pk
74
+ c = c.confession
75
+ end
76
+ end
77
+ if(c)
78
+ reply message.replyto, "\2[#{pk}]\2: #{c}"
79
+ @last_confession[message.target.pk] = pk
44
80
  else
45
- c = Confession.filter(:confession => Regexp.new(params[:term])).first
46
- reg = true
81
+ reply message.replyto, "\2Error:\2 Failed to find confession"
47
82
  end
48
- else
49
- ids = Confession.select(:id).map(:id)
50
- c = Confession[ids[rand(ids.size - 1)].to_i]
51
- end
52
- if(c)
53
- reply message.replyto, "\2[#{c.pk}]\2: #{reg ? c.confession.gsub(/(#{params[:term]})/, "\2\\1\2") : c.confession}"
54
- @last_confession[message.target.pk] = c.pk
55
- else
56
- reply message.replyto, "\2Error:\2 Failed to find confession"
83
+ rescue Object => boom
84
+ reply message.replyto, "Failed to locate a match. Error encountered: #{boom}"
57
85
  end
58
86
  end
59
87
 
60
88
  def show_score(message, params)
61
- c = Confession[params[:id].to_i]
62
- if(c)
63
- reply message.replyto, "\2[#{c.pk}]:\2 #{c.score.to_i}% of raters gave this confession a positive score"
89
+ pk = nil
90
+ score = nil
91
+ c = nil
92
+ @lock.synchronize do
93
+ c = Confession[params[:id].to_i]
94
+ if(c)
95
+ pk = c.pk
96
+ score = c.score.to_i
97
+ end
98
+ end
99
+ if(pk)
100
+ reply message.replyto, "\2[#{pk}]:\2 #{score}% of raters gave this confession a positive score"
64
101
  else
65
102
  reply message.replyto, "\2Error:\2 Failed to find confession with ID: #{params[:id]}"
66
103
  end
67
104
  end
68
105
 
69
106
  def score(message, params)
70
- if(params[:id])
71
- c = Confession[params[:id].to_i]
72
- else
73
- c = Confession[@last_confession[message.target.pk]] if @last_confession.has_key?(message.target.pk)
107
+ c = nil
108
+ @lock.synchronize do
109
+ if(params[:id])
110
+ c = Confession[params[:id].to_i]
111
+ else
112
+ c = Confession[@last_confession[message.target.pk]] if @last_confession.has_key?(message.target.pk)
113
+ end
74
114
  end
75
115
  if(c)
76
- if(params[:score] == '++')
77
- c.update_with_params(:positive => c.positive.to_i + 1)
78
- else
79
- c.update_with_params(:negative => c.negative.to_i + 1)
116
+ @lock.synchronize do
117
+ if(params[:score] == '++')
118
+ c.update_with_params(:positive => c.positive.to_i + 1)
119
+ else
120
+ c.update_with_params(:negative => c.negative.to_i + 1)
121
+ end
122
+ c.update_with_params(:score => ((c.positive.to_f) / (c.positive.to_f + c.negative.to_f)) * 100.0)
80
123
  end
81
- c.update_with_params(:score => ((c.positive.to_f) / (c.positive.to_f + c.negative.to_f)) * 100.0)
82
124
  else
83
125
  reply message.replyto, "\2Error:\2 Failed to find confession to score"
84
126
  end
85
127
  end
86
128
 
87
129
  def count(message, params)
88
- reply message.replyto, "Current number of stored confessions: #{Confession.all.size}"
130
+ c = 0
131
+ @lock.synchronize do
132
+ c = Confession.count
133
+ end
134
+ reply message.replyto, "Current number of stored confessions: #{c}"
89
135
  end
90
136
 
91
137
  def fetcher(message, params)
@@ -100,6 +146,7 @@ class Confess < ModSpox::Plugin
100
146
  else
101
147
  if(Config[:confess] == 'fetch')
102
148
  Config[:confess] = 'nofetch'
149
+ stop_fetcher
103
150
  reply message.replyto, 'Confession fetcher has been stopped'
104
151
  else
105
152
  reply message.replyto, 'Confession fetcher is not currently running'
@@ -109,58 +156,90 @@ class Confess < ModSpox::Plugin
109
156
 
110
157
  def grab_page
111
158
  begin
112
- connection = Net::HTTP.new('beta.grouphug.us', 80)
113
- response = connection.request_get('/random', nil)
159
+ connection = Net::HTTP.new('www.grouphug.us', 80)
160
+ response = connection.request_get("/frontpage?page=#{rand(17349)+1}", nil)
114
161
  response.value
115
162
  page = response.body.gsub(/[\r\n]/, ' ')
116
- Logger.log("Processing matches")
163
+ Logger.info("Processing matches")
117
164
  page.scan(/<div class="content">\s*<p>\s*(.+?)\s*<\/p>\s*<\/div>/).each{|match|
118
- Logger.log("Match found: #{match[0]}")
165
+ Logger.info("Match found: #{match[0]}")
119
166
  conf = CGI::unescapeHTML(match[0])
120
167
  conf = conf.gsub(/<.+?>/, ' ').gsub(/[\r\n]/, '').gsub(/\s+/, ' ')
121
168
  conf = @coder.decode(conf)
122
- Logger.log("Match turned into: #{conf}")
169
+ Logger.info("Match turned into: #{conf}")
123
170
  if conf.length < 300
124
171
  begin
125
- Confession.new(:confession => conf, :hash => Digest::MD5.hexdigest(conf)).save
172
+ @lock.synchronize do
173
+ c = Confession.new(:hash => Digest::MD5.hexdigest(conf)).save
174
+ c.confession = conf
175
+ end
126
176
  rescue Object => boom
127
- Logger.log 'Warning: Fetched confession already found in database'
177
+ Logger.warn('Warning: Fetched confession already found in database')
128
178
  end
129
179
  end
130
180
  }
131
181
  rescue Object => boom
132
- Logger.log "Error fetching data: #{boom}"
133
- end
134
- if(Config[:confess] == 'fetch')
135
- @pipeline << Messages::Internal::TimerAdd.new(self, rand(500), nil, true){ grab_page }
136
- else
137
- stop_fetcher
182
+ Logger.warn("Error fetching data: #{boom}")
183
+ ensure
184
+ @timer[:action].reset_period(rand(1000)+1) unless @timer[:action].nil?
138
185
  end
139
186
  end
140
187
 
141
188
  private
142
189
 
143
190
  def start_fetcher
144
- @mutex.synchronize do
145
- grab_page unless @fetch
191
+ if(@timer[:action].nil?)
192
+ m = Messages::Internal::TimerAdd.new(self, rand(1000)+1){ grab_page }
193
+ @timer[:id] = m.id
194
+ @pipeline << m
195
+ end
196
+ end
197
+
198
+ def get_timer(m)
199
+ if(m.id == @timer[:id])
200
+ if(m.action_added?)
201
+ @timer[:action] = m.action
202
+ else
203
+ @timer = {:action => nil, :id => nil}
204
+ end
146
205
  end
147
206
  end
148
207
 
149
208
  def stop_fetcher
150
- @mutex.synchronize do
151
- @fetch = false
209
+ unless(@timer[:action].nil?)
210
+ @pipeline << Messages::Internal::TimerRemove(@timer[:action])
152
211
  end
153
212
  end
154
213
 
155
- class Confession < Sequel::Model
214
+ class Confession < Sequel::Model
215
+ def Confession.build_confession
216
+ db << 'CREATE VIRTUAL TABLE `confessions_confession` USING FTS3(`confession` TEXT NOT NULL)'
217
+ end
218
+
156
219
  set_schema do
157
- text :confession, :null => false
158
220
  text :hash, :null => false, :unique => true
159
221
  integer :positive, :null => false, :default => 0
160
222
  integer :negative, :null => false, :default => 0
161
223
  float :score, :null => false, :default => 0
162
224
  primary_key :id
163
225
  end
226
+
227
+ def confession=(c)
228
+ if(confession)
229
+ db[:confessions_confession].filter('docid = ?', pk).update(:confession => c)
230
+ else
231
+ db[:confessions_confession] << {:docid => pk, :confession => c}
232
+ end
233
+ end
234
+
235
+ def confession
236
+ c = db[:confessions_confession].select(:confession).where('docid = ?', pk).first
237
+ return c.nil? ? nil : c[:confession]
238
+ end
239
+
240
+ def Confession.search(terms)
241
+ results = db['select docid from confessions_confession where confession match ?', terms].map(:docid)
242
+ end
164
243
  end
165
244
 
166
245
  end
@@ -0,0 +1,189 @@
1
+ ['ipaddr', 'socket', 'timeout'].each{|f| require f}
2
+
3
+ class DCC < ModSpox::Plugin
4
+
5
+ include Models
6
+
7
+ def initialize(pipeline)
8
+ super
9
+ group = Group.find_or_create(:name => 'dcc')
10
+ admin = Group.find_or_create(:name => 'admin')
11
+ Signature.find_or_create(:signature => 'file list(\s(.+))?', :plugin => name, :method => 'file_list',
12
+ :description => 'List available DCC files', :group_id => group.pk).params = [:pattern]
13
+ Signature.find_or_create(:signature => 'file get (.+)', :plugin => name, :method => 'file_get',
14
+ :description => 'Download file', :group_id => group.pk).params = [:filename]
15
+ Signature.find_or_create(:signature => 'file ports (\d+)-(\d+)', :plugin => name, :method => 'set_ports',
16
+ :description => 'Set allowed DCC ports', :group_id => admin.pk).params = [:start, :end]
17
+ Signature.find_or_create(:signature => 'file adddir (.+)', :plugin => name, :method => 'add_dir',
18
+ :description => 'Add directory to file list', :group_id => admin.pk).params = [:dir]
19
+ Signature.find_or_create(:signature => 'file rmdir (\d+)', :plugin => name, :method => 'rm_dir',
20
+ :description => 'Remove directory from file list', :group_id => admin.pk).params = [:dir]
21
+ Signature.find_or_create(:signature => 'file show dir', :plugin => name, :method => 'show_dirs',
22
+ :description => 'Show directories available to file list', :group_id => admin.pk)
23
+ Signature.find_or_create(:signature => 'file show ports', :plugin => name, :method => 'show_ports',
24
+ :description => 'Show allowed ports', :group_id => admin.pk)
25
+ Signature.find_or_create(:signature => 'file max wait(\s(\d+))?', :plugin => name, :method => 'max_wait',
26
+ :description => 'Show/set timeout for accepting files', :group_id => admin.pk).params = [:wait]
27
+ Signature.find_or_create(:signature => 'dcc chat', :plugin => name, :method => 'dcc_chat',
28
+ :description => 'Start a DCC chat with the bot (useful if behind firewall', :group_id => group.pk)
29
+ @servers = {}
30
+ @ports = Setting[:dcc_ports]
31
+ @ports = {:start => 49152, :end => 65535} if @ports.nil?
32
+ @dirs = Setting.find_or_create(:name => 'dcc_dirs').value
33
+ @dirs = [] unless @dirs.is_a?(Array)
34
+ @max_wait = Setting[:dcc_max_wait]
35
+ @max_wait = @max_wait.nil? ? 60 : @max_wait.to_i
36
+ end
37
+
38
+ def file_list(message, params)
39
+ matches = []
40
+ pattern = params[:pattern] ? Regexp.new(params[:pattern].strip!) : nil
41
+ @dirs.each do |path|
42
+ dir = Dir.new(path)
43
+ dir.each do |file|
44
+ next if File.directory?("#{dir.path}/#{file}") || (file[0] == 46 || file[0] == '.') || !File.readable?("#{dir.path}/#{file}")
45
+ unless(pattern.nil?)
46
+ if(pattern.match(file))
47
+ matches << dir.path + '/' + file + " - #{Helpers.format_size(File.size(dir.path + '/' + file))}"
48
+ end
49
+ else
50
+ matches << dir.path + '/' + file + " - #{Helpers.format_size(File.size(dir.path + '/' + file))}"
51
+ end
52
+ end
53
+ end
54
+ output = ["\2Files in available list:\2 (matching: #{params[:pattern] ? params[:pattern] : ''})"]
55
+ output = output + matches
56
+ reply message.replyto, output
57
+ end
58
+
59
+ def file_get(message, params)
60
+ @try = 0
61
+ socket = nil
62
+ port = 0
63
+ unless(@dirs.include?(File.dirname(params[:filename])))
64
+ reply message.replyto, "\2Error:\2 #{params[:filename]} is not within the allowed directories"
65
+ else
66
+ while(socket.nil? && @try < 3) do
67
+ begin
68
+ port = rand(@ports[:end] - @ports[:start]) + @ports[:start]
69
+ socket = Object::Socket.new(Object::Socket::AF_INET, Object::Socket::SOCK_STREAM, 0)
70
+ addr = Object::Socket.pack_sockaddr_in(port, me.address)
71
+ socket.bind(addr)
72
+ initialize_getter(socket, params[:filename])
73
+ rescue Object => boom
74
+ Logger.warn("Failed to initialize DCC TCPServer. Reason: #{boom}")
75
+ @try += 1
76
+ socket = nil
77
+ port = nil
78
+ end
79
+ end
80
+ if(socket.nil?)
81
+ reply message.replyto, "\2Error:\2 Failed to initialize file getter process."
82
+ else
83
+ ip = IPAddr.new(me.address).to_i
84
+ @pipeline << Messages::Outgoing::Privmsg.new(message.source, "SEND #{File.basename(params[:filename])} #{ip} #{port} #{File.size(params[:filename])}", false, true, 'DCC')
85
+ end
86
+ end
87
+ end
88
+
89
+ def max_wait(message, params)
90
+ wait = params[:wait].nil? ? nil : params[:wait].strip
91
+ unless(wait.nil?)
92
+ @max_wait = wait.to_i
93
+ record = Setting.find_or_create(:name => 'dcc_max_wait')
94
+ record.value = wait
95
+ record.save
96
+ reply message.replyto, "Timeout for file download changed to: #{@max_wait} seconds"
97
+ else
98
+ reply message.replyto, "Timeout for file download is: #{@max_wait} seconds"
99
+ end
100
+ end
101
+
102
+ def set_ports(message, params)
103
+ if(params[:start].to_i > 1024 && params[:end].to_i < 65536)
104
+ @ports = {:start => params[:start].to_i, :end => params[:end].to_i}
105
+ record = Setting.find_or_create(:name => 'dcc_ports')
106
+ record.value = @ports
107
+ record.save
108
+ reply message.replyto, "File ports have been updated to: #{@ports[:start]} - #{@ports[:end]}"
109
+ else
110
+ reply message.replyto, "\2Error:\2 Ports given are out of acceptable range (1025 - 65535)"
111
+ end
112
+ end
113
+
114
+ def add_dir(message, params)
115
+ if(File.readable?(params[:dir]))
116
+ if(@dirs.include?(dir))
117
+ reply message.replyto, "\2Error:\2 Given directory is already in available list. (#{params[:dir]})"
118
+ else
119
+ @dirs << dir
120
+ record = Setting.find_or_create(:name => 'dcc_dirs')
121
+ record.value = @dirs
122
+ record.save
123
+ reply message.replyto, "New directory added to DCC directory list: #{params[:dir]}"
124
+ end
125
+ else
126
+ reply message.replyto, "\2Error:\2 Given directory is not readable. (#{params[:dir]})"
127
+ end
128
+ end
129
+
130
+ def rm_dir(message, params)
131
+ if(@dirs.include?(params[:dir]))
132
+ @dirs.delete(params[:dir])
133
+ record = Setting.find_or_create(:name => 'dcc_dirs')
134
+ record.value = @dirs
135
+ record.save
136
+ reply message.replyto, "DCC directory successfully updated"
137
+ else
138
+ reply message.replyto, "\2Error:\2 Failed to find directory: #{params[:dir]} in available directory list"
139
+ end
140
+ end
141
+
142
+ def show_dirs(message, params)
143
+ output = []
144
+ output << "\2Directories available for DCC file list:\2"
145
+ output += @dirs
146
+ reply message.replyto, output
147
+ end
148
+
149
+ def show_ports(message, params)
150
+ reply message.replyto, "\2Allowed Ports:\2 #{@ports[:start]} - #{@ports[:end]}"
151
+ end
152
+
153
+ def dcc_chat(message, params)
154
+ @pipeline << Messages::Internal::DCCListener.new(message.source)
155
+ end
156
+
157
+ private
158
+
159
+ def initialize_getter(socket, filename)
160
+ @servers[socket.object_id] = Thread.new do
161
+ client = nil
162
+ addrinfo = nil
163
+ cport = nil
164
+ cip = nil
165
+ begin
166
+ Timeout::timeout(@max_wait) do
167
+ socket.listen(5)
168
+ client, addrinfo = socket.accept
169
+ cport, cip = Object::Socket.unpack_sockaddr_in(addrinfo)
170
+ end
171
+ Logger.info("Sending file: #{filename} to IP: #{cip}:#{cport}")
172
+ file = File.new(filename)
173
+ until((line = file.gets).nil?) do
174
+ client << line
175
+ end
176
+ Logger.info("Sending of file: #{filename} to IP: #{addrinfo} is now complete")
177
+ rescue Timeout::Error => boom
178
+ Logger.warn("Error sending file: #{filename}. Timeout exceeded (#{@max_wait} seconds)")
179
+ rescue Object => boom
180
+ Logger.warn("Error sending file: #{filename}. Unknown reason: #{boom}")
181
+ ensure
182
+ socket.close
183
+ client.close
184
+ @servers.delete(socket.object_id)
185
+ end
186
+ end
187
+ end
188
+
189
+ end
@@ -19,12 +19,10 @@ class DevWatch < ModSpox::Plugin
19
19
  if(Setting[:devwatch].nil?)
20
20
  Setting.find_or_create(:name => 'devwatch').value = {:channels => [], :interval => 300}
21
21
  end
22
- @pipeline.hook(self, :timer_response, :Internal_TimerResponse)
23
22
  @original = nil
24
23
  @new = nil
25
- @timer = nil
26
- @lock = Mutex.new
27
- run
24
+ @timer = {:action => nil, :id => nil}
25
+ start_auto
28
26
  end
29
27
 
30
28
  def enable_watch(message, params)
@@ -39,7 +37,7 @@ class DevWatch < ModSpox::Plugin
39
37
  reply(message.replyto, "#{channel.name} has been removed from the development watch list")
40
38
  end
41
39
  Setting.filter(:name => 'devwatch').first.value = vals
42
- run
40
+ update_auto
43
41
  else
44
42
  reply(message.replyto, "\2Error:\2 I have no record of #{params[:channel]}.")
45
43
  end
@@ -61,7 +59,7 @@ class DevWatch < ModSpox::Plugin
61
59
  vals[:url] = params[:url]
62
60
  reply(message.replyto, "OK")
63
61
  Setting.filter(:name => 'devwatch').first.value = vals
64
- run
62
+ update_auto
65
63
  else
66
64
  if(Setting[:devwatch].has_key?(:url))
67
65
  reply(message.replyto, "\2Devwatch URL:\2 #{Setting[:devwatch][:url]}")
@@ -76,38 +74,17 @@ class DevWatch < ModSpox::Plugin
76
74
  vals = Setting[:devwatch]
77
75
  vals[:interval] = params[:time].to_i
78
76
  Setting.filter(:name => 'devwatch').first.value = vals
79
- @timer.reset_period(params[:time].to_i) unless @timer.nil?
77
+ if(@timer[:action].nil?)
78
+ update_auto
79
+ else
80
+ @timer[:action].reset_period(params[:time].to_i)
81
+ end
80
82
  reply(message.replyto, "Devwatch announcement interval reset to: #{Helpers.format_seconds(params[:time].to_i)}")
81
83
  else
82
84
  reply(message.replyto, "Devwatch announcement interval set to: #{Helpers.format_seconds(Setting[:devwatch][:interval].to_i)}")
83
85
  end
84
86
  end
85
87
 
86
- def run
87
- @lock.synchronize do
88
- check_updates
89
- if(Setting[:devwatch].has_key?(:url) && Setting[:devwatch][:channels].size > 0)
90
- if(@timer.nil?)
91
- @pipeline << ModSpox::Messages::Internal::TimerAdd.new(self, Setting[:devwatch][:interval].to_i){check_updates}
92
- sleep(0.01) while @timer.nil?
93
- end
94
- else
95
- if(@timer)
96
- @pipeline << ModSpox::Messages::Internal::TimerRemove.new(@timer)
97
- sleep(0.01) until @timer.nil?
98
- end
99
- end
100
- end
101
- end
102
-
103
- def timer_response(message)
104
- if(message.origin == self && message.action_added?)
105
- @timer = message.action
106
- elsif(message.action == @timer && message.action_removed?)
107
- @timer = nil
108
- end
109
- end
110
-
111
88
  def check_updates
112
89
  if(Setting[:devwatch].has_key?(:url) && Setting[:devwatch][:channels].size > 0)
113
90
  src = open(Setting[:devwatch][:url])
@@ -117,7 +94,7 @@ class DevWatch < ModSpox::Plugin
117
94
  @original = item.elements['title'].text
118
95
  break
119
96
  end
120
- Logger.log("Initialized development watch RSS feed: #{@original}")
97
+ Logger.info("Initialized development watch RSS feed: #{@original}")
121
98
  else
122
99
  @new = doc
123
100
  print_new
@@ -150,5 +127,27 @@ class DevWatch < ModSpox::Plugin
150
127
  end
151
128
  end
152
129
  end
130
+
131
+ def get_timer(m)
132
+ if(m.id == @timer[:id])
133
+ @timer[:action] = m.action_added? ? m.action : nil
134
+ end
135
+ end
136
+
137
+ def update_auto
138
+ unless(@timer[:action].nil?)
139
+ @pipeline << Messages::Internal::TimerRemove.new(@timer[:action])
140
+ end
141
+ sleep(0.01)
142
+ start_auto
143
+ end
144
+
145
+ def start_auto
146
+ if(@timer[:action].nil? && Setting[:devwatch].has_key?(:url) && Setting[:devwatch][:channels].size > 0)
147
+ m = Messages::Internal::TimerAdd.new(self, Setting[:devwatch][:interval].to_i){ check_updates }
148
+ @timer[:id] = m.id
149
+ @pipeline << m
150
+ end
151
+ end
153
152
 
154
153
  end