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
@@ -0,0 +1,83 @@
1
+ class NickServ < ModSpox::Plugin
2
+
3
+ #TODO: Add support for things like RECOVERY and GHOST
4
+
5
+ def initialize(pipeline)
6
+ super
7
+ admin = Models::Group.find_or_create(:name => 'admin')
8
+ add_sig(:sig => 'nickserv address( \S+)?', :method => :set_address, :group => admin,
9
+ :desc => 'Set/view address to send nickserv info to', :params => [:address])
10
+ add_sig(:sig => 'nickserv combo (\S+) (\S+)', :method => :set_combo, :group => admin,
11
+ :desc => 'Set nick/pass combo', :params => [:nick, :password], :req => 'private')
12
+ add_sig(:sig => 'nickserv show', :method => :output_info, :group => admin,
13
+ :desc => 'Show nickserv info', :req => 'private')
14
+ add_sig(:sig => 'nickserv send', :method => :send_combo, :group => admin,
15
+ :desc => 'Send nickserv info')
16
+ @nickserv = Models::Setting.find_or_create(:name => 'nickserv').value
17
+ unless(@nickserv.is_a?(Hash) && @nickserv.has_key?(:address) && @nickserv.has_key?(:combos))
18
+ @nickserv = {:address => nil, :combos => {}}
19
+ end
20
+ @pipeline.hook(self, :send_nickserv, :Incoming_Welcome)
21
+ end
22
+
23
+ # @nickserv = {:address => 'nickserv@blah', :combos => {'nick' => 'pass'}}
24
+
25
+ def set_address(message, params)
26
+ if(params[:address])
27
+ params[:address].strip!
28
+ @nickserv[:address] = params[:address]
29
+ save_info
30
+ reply message.replyto, "Nickserv address updated to: #{params[:address]}"
31
+ else
32
+ unless(@nickserv[:address].nil?)
33
+ reply message.replyto, "Nickserv address set to: #{@nickserv[:address]}"
34
+ else
35
+ reply message.replyto, "\2Error:\2 Nickserv address has not been set"
36
+ end
37
+ end
38
+ end
39
+
40
+ def set_combo(message, params)
41
+ @nickserv[:combos][params[:nick].to_sym] = params[:password]
42
+ save_info
43
+ reply message.replyto, "Nickserv password saved for nick: \2#{params[:nick]}\2"
44
+ end
45
+
46
+ def output_info(message, params)
47
+ output = ["\2Nickserv information dump:\2"]
48
+ output << "Address used to send identification: #{@nickserv[:address].nil? ? 'unset' : @nickserv[:address]}"
49
+ @nickserv[:combos].each_pair{|k,v| output << "#{k} -> #{v}"}
50
+ reply message.replyto, output
51
+ end
52
+
53
+ def send_combo(message, params)
54
+ output = 'Identification sent to nickserv'
55
+ begin
56
+ identify
57
+ rescue Object => boom
58
+ output = boom.to_s
59
+ ensure
60
+ reply message.replyto, output
61
+ end
62
+ end
63
+
64
+ def send_nickserv(m)
65
+ identify
66
+ end
67
+
68
+ private
69
+
70
+ def save_info
71
+ s = Models::Setting.filter(:name => 'nickserv').first.update(:value => @nickserv)
72
+ end
73
+
74
+ def identify
75
+ raise Exceptions::BotException.new('No address set for nickserv') if @nickserv[:address].nil?
76
+ if(@nickserv[:combos].has_key?(me.nick.to_sym))
77
+ @pipeline << Messages::Outgoing::Privmsg.new(@nickserv[:address], "IDENTIFY #{@nickserv[:combos][me.nick.to_sym]}")
78
+ else
79
+ raise Exceptions::BotException.new("No nickserv password available for: #{me.nick.nick}")
80
+ end
81
+ end
82
+
83
+ end
@@ -9,7 +9,7 @@ class PhpCli < ModSpox::Plugin
9
9
  @path = Config[:plugin_directory] + '/phpcli'
10
10
  @botini = @path + '/bot.ini'
11
11
  unless(File.directory?(@path))
12
- FileUtils.mkdir_p(@path)
12
+ FileUtils.mkdir_p(@path)
13
13
  end
14
14
  result = Helpers.safe_exec('which php')
15
15
  raise NoInterpreter.new if result.empty?
@@ -18,21 +18,16 @@ class PhpCli < ModSpox::Plugin
18
18
  ini.write($ini)
19
19
  ini.close
20
20
  end
21
- php = Group.find_or_create(:name => 'PHP')
21
+ php = Group.find_or_create(:name => 'php')
22
22
  admin = Group.filter(:name => 'admin').first
23
23
  Signature.find_or_create(:signature => 'php (on|off)', :plugin => name, :method => 'set_channel', :group_id => admin.pk,
24
24
  :description => 'Add or remove channel from allowing PHP command').params = [:action]
25
25
  Signature.find_or_create(:signature => 'php (?!on|off)(.+)', :plugin => name, :method => 'execute_php', :group_id => php.pk,
26
26
  :description => 'Execute PHP code').params = [:code]
27
- @channels = Setting.find(:name => 'phpcli')
28
- if(@channels.nil?)
29
- Logger.log("WE ARE NIL PEOPLE")
30
- @channels = []
31
- else
32
- @channels = @channels.value
33
- end
27
+ @channels = Setting.filter(:name => 'phpcli').first
28
+ @channels = @channels.nil? ? [] : @channels.value
34
29
  end
35
-
30
+
36
31
  def set_channel(message, params)
37
32
  return unless message.is_public?
38
33
  if(params[:action] == 'on')
@@ -55,7 +50,7 @@ class PhpCli < ModSpox::Plugin
55
50
  end
56
51
  end
57
52
  end
58
-
53
+
59
54
  def execute_php(message, params)
60
55
  return unless @channels.include?(message.target.pk)
61
56
  filepath = @path + "/#{rand(99999)}.bot.php"
@@ -83,12 +78,14 @@ class PhpCli < ModSpox::Plugin
83
78
  reply message.replyto, "Result: "+output
84
79
  end
85
80
  File.delete(filepath)
86
- rescue
87
- reply message.replyto, "\2Error:\2 Timeout reached. Script execution terminated"
81
+ rescue Timeout::Error => boom
82
+ reply message.replyto, "\2Error:\2 Timeout reached: #{boom}"
83
+ rescue Object => boom
84
+ reply message.replyto, "\2Error:\2 Script execution terminated. (#{boom})"
88
85
  File.delete(filepath)
89
86
  end
90
87
  end
91
-
88
+
92
89
  class NoInterpreter < Exceptions::BotException
93
90
  end
94
91
 
@@ -115,7 +112,7 @@ safe_mode_exec_dir = /tmp/mod_spox/php
115
112
  safe_mode_allowed_env_vars = PHP_
116
113
  safe_mode_protected_env_vars = LD_LIBRARY_PATH
117
114
  open_basedir = /tmp/mod_spox
118
- disable_functions = fscanf fputs chown chmod copy delete fflush file flock ftell glob link fseek lstat move_uploaded_file rename realpath set_file_buffer touch fprintf chgrp fgetss readfile dio_close dio_fnctl dio_open dio_read dio_seek dio_stat dio_tcsetattr dio_truncate dio_write chdir chroot dir closedir getcwd opendir readdir rewinddir scandir posix_kill posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid posix_getpwnam posix_getpwuid posix_getwuid posix_getrlimit posix_getsid posix_getuid posix_isatty posix_mkfifo posix_mknod posix_setegid posix_setgid posix_setpgid posix_setsid posix_setuid posix_strerror posix_times posix_ttyname posix_uname expect_expectl expect_popen sleep time_sleep_until usleep pfsockopen fsockopen openlog debugger_on proc_open pclose popen fsockopen fread set_time_limit ini_set ini_alter ini_restore exec system passthru proc_close proc_nice proc_open proc_terminiate shell_exec sleep usleep pcntl_fork pcntl_exec pcntl_alarm pcntl_getpriority pcntl_setpriority pcntl_waitpid pcntl_wexitstatus pcntl_wifexited pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig readline_add_history readline_callback_handler_install readline_callback_handler_remove readline_callback_read_char readline_clear_history readline_completion_function readline_info readline_list_history readline_on_new_line readline_read_history readline_redisplay readline_write_history readline dl set_include_path set_magic_quotes_runtime file_put_contents fwrite fputs copy fputcsv tmpfile symlink tempnam mysql_connect unlink putenv ftp_connect socket_create socket_create socket_close socket_accept socket_bind socket_close socket_connect socket_create_listen socket_create_pair socket_get_option socket_listen socket_read socket_recv socket_select socket_send socket_sendto shmop_close shmop_open shmop_delete shmop_read shmop_size shmop_write msg_get_queue msg_receive msg_remove_queue msg_send msg_set_queue msg_stat_queue msg_acquire sem_aquire sem_release sem_get sem_remove mail time_nanosleep usleep
115
+ disable_functions = fscanf fputs chown chmod copy delete fflush file flock ftell glob link fseek lstat move_uploaded_file rename realpath set_file_buffer touch fprintf chgrp fgetss readfile dio_close dio_fnctl dio_open dio_read dio_seek dio_stat dio_tcsetattr dio_truncate dio_write chdir chroot dir closedir getcwd opendir readdir rewinddir scandir posix_kill posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid posix_getpwnam posix_getpwuid posix_getwuid posix_getrlimit posix_getsid posix_getuid posix_isatty posix_mkfifo posix_mknod posix_setegid posix_setgid posix_setpgid posix_setsid posix_setuid posix_strerror posix_times posix_ttyname posix_uname expect_expectl expect_popen sleep time_sleep_until usleep pfsockopen fsockopen openlog debugger_on proc_open pclose popen fsockopen fread set_time_limit ini_set ini_alter ini_restore exec system passthru proc_close proc_nice proc_open proc_terminiate shell_exec sleep usleep pcntl_fork pcntl_exec pcntl_alarm pcntl_getpriority pcntl_setpriority pcntl_waitpid pcntl_wexitstatus pcntl_wifexited pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig readline_add_history readline_callback_handler_install readline_callback_handler_remove readline_callback_read_char readline_clear_history readline_completion_function readline_info readline_list_history readline_on_new_line readline_read_history readline_redisplay readline_write_history readline dl set_include_path set_magic_quotes_runtime file_put_contents fwrite fputs copy fputcsv tmpfile symlink tempnam mysql_connect unlink putenv ftp_connect socket_create socket_create socket_close socket_accept socket_bind socket_close socket_connect socket_create_listen socket_create_pair socket_get_option socket_listen socket_read socket_recv socket_select socket_send socket_sendto shmop_close shmop_open shmop_delete shmop_read shmop_size shmop_write msg_get_queue msg_receive msg_remove_queue msg_send msg_set_queue msg_stat_queue msg_acquire sem_aquire sem_release sem_get sem_remove mail time_nanosleep usleep include include_once require require_once ftp_alloc ftp_cdup ftp_chdir ftp_chmod ftp_close ftp_connect ftp_delete ftp_exec ftp_fget ftp_fput ftp_get ftp_get_option ftp_login ftp_mdtm ftp_mkdir ftp_nb_continue ftp_nb_fget ftp_nb_fput ftp_nb_get ftp_nb_put
119
116
  disable_classes = dir
120
117
  expose_php = On
121
118
  max_execution_time = 10
@@ -1,4 +1,5 @@
1
1
  require 'cgi'
2
+ require 'open-uri'
2
3
 
3
4
  # Inspired from an old plugin for the original mod_spox
4
5
  # Original development: spox & Ryan "pizza_milkshake" Flynn
@@ -79,12 +80,14 @@ class PhpFuncLookup < ModSpox::Plugin
79
80
 
80
81
  def phpfunc(m, params)
81
82
  name = params[:name].downcase
82
- Logger.log "phpfunc name=#{name}"
83
+ Logger.info "phpfunc name=#{name}"
83
84
  if name =~ /^\S+$/ && name =~ /\*/
84
85
  parse_wildcard(m, name)
85
86
  elsif name =~ /^\$/
86
- parse_predefined(m, name)
87
- elsif name =~ /^\S+$/ && filename = find_file(name)
87
+ parse_predefined(m, name)
88
+ elsif name =~ /^\S+$/ && filename = find_control_file(name)
89
+ parse_control(m, name, filename)
90
+ elsif name =~ /^\S+$/ && filename = find_function_file(name)
88
91
  parse_function(m, name, filename)
89
92
  elsif @ops.has_key?(name)
90
93
  parse_operator(m, name)
@@ -93,7 +96,7 @@ class PhpFuncLookup < ModSpox::Plugin
93
96
 
94
97
  def fetch(m, params)
95
98
  reply m.replyto, "Fetching PHP manual (This could take a few minutes)"
96
- fetch_manual
99
+ fetch_manual(m)
97
100
  end
98
101
 
99
102
  def listen(m)
@@ -147,26 +150,27 @@ class PhpFuncLookup < ModSpox::Plugin
147
150
 
148
151
  private
149
152
 
150
- def find_file(name)
153
+ def find_function_file(name)
151
154
  Dir.new(@manual).each do |filename|
152
155
  return filename if filename.downcase == "function.#{name.gsub(/(_|->)/, '-').downcase}.html"
153
156
  end
154
157
  return nil
155
158
  end
159
+
160
+ def find_control_file(name)
161
+ Dir.new(@manual).each do |filename|
162
+ return filename if filename.downcase == "control-structures.#{name}.html"
163
+ end
164
+ return nil
165
+ end
156
166
 
157
167
  def fetch_manual(message=nil, params=nil)
158
168
  Thread.new do
159
- manual_site = 'http://us.php.net/'
160
- Logger.log "Fetching PHP manual from #{manual_site}"
161
- connection = Net::HTTP.new("us.php.net", 80)
162
- File.open("#{@path}/manual.tar.gz", 'w'){ |manual|
163
- connection.get('/distributions/manual/php_manual_en.tar.gz', nil){ |line|
164
- manual.write(line)
165
- }
166
- }
169
+ Logger.info 'Fetching PHP manual from http://us.php.net'
170
+ open("#{@path}/manual.tar.gz", 'w').write(open('http://us.php.net/distributions/manual/php_manual_en.tar.gz').read)
167
171
  Dir.chdir(@path)
168
172
  Helpers.safe_exec("tar -xzf #{@path}/manual.tar.gz", 60)
169
- Logger.log "PHP manual fetching complete."
173
+ Logger.info "PHP manual fetching complete."
170
174
  reply message.replyto, "PHP manual fetch is now complete" unless message.nil?
171
175
  end
172
176
  end
@@ -200,9 +204,9 @@ class PhpFuncLookup < ModSpox::Plugin
200
204
 
201
205
  def parse_wildcard(m, name)
202
206
  matches = []
203
- pattern = name.gsub(/\*/, '.*?')
207
+ pattern = name.gsub(/\*/, '.*?').gsub(/_/, '-')
204
208
  Dir.open(@manual).each do |file|
205
- if(file =~ /^(.+?#{pattern}.+?)\.html/)
209
+ if(file =~ /^(function\.#{pattern})\.html/)
206
210
  match = $1
207
211
  if(match =~ /^function\.(.+?)\-/)
208
212
  if(@classlist.include?($1.downcase))
@@ -211,11 +215,9 @@ class PhpFuncLookup < ModSpox::Plugin
211
215
  else
212
216
  match.gsub!(/[-]/, '_')
213
217
  end
214
- match.gsub!(/^function\./, '')
215
- else
216
- match = nil
217
218
  end
218
- matches << match unless match.nil?
219
+ match.gsub!(/^function\./, '')
220
+ matches << match unless match.empty?
219
221
  end
220
222
  end
221
223
  matches.sort!
@@ -223,6 +225,7 @@ class PhpFuncLookup < ModSpox::Plugin
223
225
  if(matches.empty?)
224
226
  output = "\2Error:\2 No matches found"
225
227
  else
228
+ output << "Matches against term: \2#{name}:\2"
226
229
  output << matches.values_at(0..19).join(', ')
227
230
  end
228
231
  reply m.replyto, output
@@ -233,7 +236,7 @@ class PhpFuncLookup < ModSpox::Plugin
233
236
  page.gsub!(/[\r\n]/, '')
234
237
  versions = page =~ /<p class="verinfo">(.+?)<\/p>/i ? $1 : '(UNKNOWN)'
235
238
  proto = page =~ /<div class="methodsynopsis dc-description">(.+?)<\/div>/i ? $1 : name
236
- desc = page =~ /<p class="refpurpose dc-title">.+? — (.+?)<\/p>/i ? $1 : '(UNKNOWN)'
239
+ desc = page =~ /<p class="(para rdfs-comment|simpara)">(.+?)<\/p>/i ? $2.strip : '(UNKNOWN)'
237
240
  versions = CGI::unescapeHTML(versions)
238
241
  proto = CGI::unescapeHTML(proto.gsub(/<.+?>/, ' ').gsub(/[\s]+/, ' '))
239
242
  desc = CGI::unescapeHTML(desc.gsub(/<.+?>/, ' ').gsub(/[\s]+/, ' '))
@@ -245,13 +248,42 @@ class PhpFuncLookup < ModSpox::Plugin
245
248
  end
246
249
 
247
250
  def parse_operator(m, name)
248
- Logger.log "parse_operator name=#{name}"
251
+ Logger.info "parse_operator name=#{name}"
249
252
  name.downcase!
250
253
  type, title, ejemplo = @ops[name]
251
- output = ["\2#{name}\2 is the \2#{title.to_a.join("\2 or \2")}\2 operator"]
252
- type.to_a.each do |t|
253
- output << "http://php.net/manual/en/language.operators.#{t}.php"
254
+ if(title.is_a?(Array))
255
+ output = ["\2#{name}\2 is the \2#{title.join("\2 or \2")}\2 operator"]
256
+ if(ejemplo.is_a?(Array))
257
+ (0..(ejemplo.size - 1)).each do |i|
258
+ output << "\2Example (#{type[i]}):\2 #{ejemplo[i]}"
259
+ end
260
+ elsif(!ejemplo.nil?)
261
+ output << "\2Example (#{type}):\2 #{ejemplo}"
262
+ end
263
+ type.each do |t|
264
+ output << "http://php.net/manual/en/language.operators.#{t}.php"
265
+ end
266
+ else
267
+ output = ["\2#{name}\2 is the \2#{title}\2 operator"]
268
+ output << "\2Example usage:\2 #{ejemplo}" unless ejemplo.nil? || ejemplo.empty?
269
+ output << "http://php.net/manual/en/language.operators.#{type}.php"
254
270
  end
271
+ reply m.replyto, output
272
+ end
273
+
274
+ def parse_control(m, name, filename)
275
+ page = File.open("#{@manual}/#{filename}", 'r').readlines.join('')
276
+ page.gsub!(/[\r\n]/, '')
277
+ con = page =~ /<h2 class="title"><i>([^<]+)</ ? $1 : '(UNKNOWN)'
278
+ par = page =~ /^.+?<p class="para">(.+?)<div/ ? $1.strip : '(UNKNOWN)'
279
+ Logger.info("Match: #{par}")
280
+ par = par.gsub(/<.+?>/, ' ').gsub(/\s{2,}/, ' ')
281
+ par.gsub!(/\.[^\.]+:$/, '.')
282
+ #par.slice!(0..199) if par.size > 200
283
+ output = ["\2Control structure: #{con}\2"]
284
+ output << par
285
+ output << "http://www.php.net/manual/en/#{filename.gsub(/\.html$/, '.php')}"
286
+ reply m.replyto, output
255
287
  end
256
288
 
257
289
  def populate_classes
@@ -23,15 +23,16 @@ class Quotes < ModSpox::Plugin
23
23
  if(params[:term] =~ /^\d+$/)
24
24
  quote = Quote[params[:term].to_i]
25
25
  else
26
- quote = Quote.filter(:quote => Regexp.new(params[:term])).first
26
+ ids = Quote.filter(:quote => Regexp.new(params[:term], Regexp::IGNORECASE)).map(:id)
27
+ quote = Quote[ids[rand(ids.size)].to_i]
27
28
  reg = true
28
29
  end
29
30
  else
30
31
  ids = Quote.select(:id).map(:id)
31
- quote = Quote[ids[rand(ids.size - 1)].to_i]
32
+ quote = Quote[ids[rand(ids.size)].to_i]
32
33
  end
33
34
  if(quote)
34
- reply message.replyto, "\2[\2#{quote.pk}\2|\2#{quote.added.year}/#{sprintf('%02d', quote.added.month)}/#{sprintf('%02d', quote.added.day)}\2]:\2 #{reg ? quote.quote.gsub(/(#{params[:term]})/, "\2\\1\2") : quote.quote}"
35
+ reply message.replyto, "\2[\2#{quote.pk}\2|\2#{quote.added.year}/#{sprintf('%02d', quote.added.month)}/#{sprintf('%02d', quote.added.day)}\2]:\2 #{reg ? quote.quote.gsub(/(#{params[:term]})/i, "\2\\1\2") : quote.quote}"
35
36
  else
36
37
  reply message.replyto, "\2Error:\2 Failed to find quote"
37
38
  end
@@ -46,7 +47,7 @@ class Quotes < ModSpox::Plugin
46
47
  end
47
48
 
48
49
  def searchquote(message, params)
49
- result = Quote.filter(:quote => Regexp.new(params[:term]))
50
+ result = Quote.filter(:quote => Regexp.new(params[:term], Regexp::IGNORECASE))
50
51
  if(result.size > 0)
51
52
  ids = result.map(:id)
52
53
  ids.sort!
@@ -0,0 +1,160 @@
1
+ class RegexTracker < ModSpox::Plugin
2
+
3
+ include Models
4
+ def initialize(pipeline)
5
+ super
6
+ track = Group.find_or_create(:name => 'track')
7
+ add_sig(:sig => 'track info (\d+)', :method => :score, :desc => 'Show info on regex tracking',
8
+ :params => [:id])
9
+ add_sig(:sig => 'track list(\s\S+)?', :method => :list, :desc => 'List currently tracked regex', :params => [:channel])
10
+ add_sig(:sig => 'track add (.+)', :method => :add, :desc => 'Add new regex for tracking',
11
+ :params => [:regex], :group => track)
12
+ add_sig(:sig => 'track remove (\d+)', :method => :remove, :desc => 'Remove regex from tracking',
13
+ :params => [:id], :group => track)
14
+ add_sig(:sig => 'track modify (\d+) (.+)', :method => :modify, :desc => 'Modify regex',
15
+ :params => [:id, :regex], :group => track)
16
+ @pipeline.hook(self, :check, :Incoming_Privmsg)
17
+ TrackInfo.create_table unless TrackInfo.table_exists?
18
+ @cache = {}
19
+ build_cache
20
+ end
21
+
22
+ def check(message)
23
+ return unless @cache.has_key?(message.target.pk.to_i)
24
+ time = Time.now
25
+ @cache[message.target.pk.to_i].each do |t|
26
+ if(message.message =~ /#{t[:regex]}/)
27
+ ti = TrackInfo[t[:id]]
28
+ if(ti.last_score.year != time.year || ti.last_score.yday != time.yday)
29
+ ti.score_today = 0
30
+ end
31
+ ti.last_score = Time.now
32
+ ti.score_today += 1
33
+ ti.score_total += 1
34
+ ti.save
35
+ end
36
+ end
37
+ end
38
+
39
+ def list(message, params)
40
+ output = ''
41
+ begin
42
+ raise 'No channel given for list' if message.is_private? && !params[:channel]
43
+ channel = params[:channel] ? Helpers.find_model(params[:channel].strip, false) : message.target
44
+ if(TrackInfo.filter(:channel_id => channel.pk).count > 0)
45
+ output = []
46
+ output << "\2Currently tracked regexs in #{channel.name}"
47
+ TrackInfo.filter(:channel_id => channel.pk).each do |t|
48
+ output << "\2ID:\2 #{t.pk} --- \2REGEX:\2 #{t.regex}"
49
+ end
50
+ else
51
+ output = 'Error: Nothing is currently being tracked'
52
+ end
53
+ rescue Object => boom
54
+ output = "Error: #{boom}"
55
+ ensure
56
+ reply message.replyto, output
57
+ end
58
+ end
59
+
60
+ def add(message, params)
61
+ output = ''
62
+ begin
63
+ r = Regexp.new(params[:regex])
64
+ t = TrackInfo.new
65
+ t.regex = params[:regex]
66
+ t.channel = message.target
67
+ t.last_score = Time.now
68
+ t.save
69
+ build_cache
70
+ output = "New regex has been added for tracking (ID: #{t.pk})"
71
+ rescue Object => boom
72
+ output = "Failed to save regex: #{boom}"
73
+ ensure
74
+ reply message.replyto, output
75
+ end
76
+ end
77
+
78
+ def remove(message, params)
79
+ id = params[:id].to_i
80
+ tis = TrackInfo.filter(:id => id)
81
+ if(tis.count > 0)
82
+ tis.destroy
83
+ build_cache
84
+ reply message.replyto, "Regex has been removed (ID: #{id})"
85
+ else
86
+ reply message.replyto, "Failed to find regex being tracked with ID: #{id}"
87
+ end
88
+ end
89
+
90
+ def modify(message, params)
91
+ id = params[:id].to_i
92
+ tis = TrackInfo.filter(:id => id)
93
+ output = ''
94
+ begin
95
+ r = Regexp.new(params[:regex])
96
+ if(tis.count > 0)
97
+ t = tis.first
98
+ t.regex = params[:regex]
99
+ t.save
100
+ build_cache
101
+ output = "Regex has been update (ID: #{t.pk})"
102
+ else
103
+ output = "Failed to locate tracking regex (ID: #{id})"
104
+ end
105
+ rescue Object => boom
106
+ output = "Failed to save regex. #{boom}"
107
+ ensure
108
+ reply message.replyto, output
109
+ end
110
+ end
111
+
112
+ def score(message, params)
113
+ id = params[:id].to_i
114
+ t = TrackInfo.filter(:id => id).first
115
+ if(t)
116
+ reply message.replyto, "\2(#{id})\2: Regex: #{t.regex}, Today: #{t.score_today}, Total: #{t.score_total}, Last occurance: #{t.last_score}"
117
+ else
118
+ reply message.replyto, "Failed to find tracking regex with ID: #{id}"
119
+ end
120
+ end
121
+
122
+ def build_cache
123
+ @cache = {}
124
+ TrackInfo.all.each do |t|
125
+ @cache[t.channel_id.to_i] = [] unless @cache.has_key?(t.channel_id.to_i)
126
+ @cache[t.channel_id.to_i] << {:id => t.pk, :regex => t.regex}
127
+ end
128
+ end
129
+
130
+ class TrackInfo < Sequel::Model
131
+ set_schema do
132
+ primary_key :id, :null => false
133
+ varchar :regex, :null => false
134
+ integer :score_total, :null => false, :default => 0
135
+ integer :score_today, :null => false, :default => 0
136
+ timestamp :last_score, :null => false
137
+ foreign_key :channel_id, :table => :channels, :null => false
138
+ index [:regex, :channel_id], :unique => true
139
+ end
140
+
141
+ def channel
142
+ Channel[channel_id]
143
+ end
144
+
145
+ def channel=(chan)
146
+ raise Exceptions::InvalidType.new('Channel model was expected') unless chan.is_a?(Models::Channel)
147
+ values[:channel_id] = chan.pk
148
+ end
149
+
150
+ def regex=(r)
151
+ r = [Marshal.dump(r)].pack('m')
152
+ super(r)
153
+ end
154
+
155
+ def regex
156
+ values[:regex] ? Marshal.load(values[:regex].unpack('m')[0]) : nil
157
+ end
158
+ end
159
+
160
+ end