spox-mod_spox 0.3.1

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.
Files changed (268) hide show
  1. data/CHANGELOG +174 -0
  2. data/INSTALL +15 -0
  3. data/LICENSE +674 -0
  4. data/README.rdoc +73 -0
  5. data/bin/mod_spox +112 -0
  6. data/data/mod_spox/extras/AOLSpeak.rb +257 -0
  7. data/data/mod_spox/extras/AutoKick.rb +152 -0
  8. data/data/mod_spox/extras/AutoMode.rb +122 -0
  9. data/data/mod_spox/extras/AutoRejoin.rb +37 -0
  10. data/data/mod_spox/extras/Bash.rb +55 -0
  11. data/data/mod_spox/extras/Bouncer.rb +220 -0
  12. data/data/mod_spox/extras/Bullshit.rb +19 -0
  13. data/data/mod_spox/extras/Bytes.rb +11 -0
  14. data/data/mod_spox/extras/Confess.rb +244 -0
  15. data/data/mod_spox/extras/DCC.rb +182 -0
  16. data/data/mod_spox/extras/DevWatch.rb +153 -0
  17. data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
  18. data/data/mod_spox/extras/EightBall.rb +33 -0
  19. data/data/mod_spox/extras/FML.rb +35 -0
  20. data/data/mod_spox/extras/FloodKicker.rb +129 -0
  21. data/data/mod_spox/extras/Fortune.rb +76 -0
  22. data/data/mod_spox/extras/GoogleIt.rb +13 -0
  23. data/data/mod_spox/extras/Headers.rb +59 -0
  24. data/data/mod_spox/extras/Karma.rb +302 -0
  25. data/data/mod_spox/extras/Locator.rb +44 -0
  26. data/data/mod_spox/extras/Logger.rb +182 -0
  27. data/data/mod_spox/extras/LolSpeak.rb +21 -0
  28. data/data/mod_spox/extras/NickServ.rb +84 -0
  29. data/data/mod_spox/extras/PhpCli.rb +308 -0
  30. data/data/mod_spox/extras/PhpFuncLookup.rb +297 -0
  31. data/data/mod_spox/extras/Pinger.rb +11 -0
  32. data/data/mod_spox/extras/Quotes.rb +79 -0
  33. data/data/mod_spox/extras/RegexTracker.rb +158 -0
  34. data/data/mod_spox/extras/Roulette.rb +267 -0
  35. data/data/mod_spox/extras/RubyCli.rb +93 -0
  36. data/data/mod_spox/extras/Search.rb +49 -0
  37. data/data/mod_spox/extras/Seen.rb +150 -0
  38. data/data/mod_spox/extras/Slashdot.rb +35 -0
  39. data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
  40. data/data/mod_spox/extras/Talk.rb +32 -0
  41. data/data/mod_spox/extras/Topten.rb +103 -0
  42. data/data/mod_spox/extras/TracTicket.rb +66 -0
  43. data/data/mod_spox/extras/Translate.rb +132 -0
  44. data/data/mod_spox/extras/Twitter.rb +458 -0
  45. data/data/mod_spox/extras/UrbanDictionary.rb +55 -0
  46. data/data/mod_spox/extras/Weather.rb +55 -0
  47. data/data/mod_spox/plugins/Authenticator.rb +289 -0
  48. data/data/mod_spox/plugins/Banner.rb +585 -0
  49. data/data/mod_spox/plugins/BotNick.rb +18 -0
  50. data/data/mod_spox/plugins/Helper.rb +49 -0
  51. data/data/mod_spox/plugins/Initializer.rb +35 -0
  52. data/data/mod_spox/plugins/Joiner.rb +23 -0
  53. data/data/mod_spox/plugins/Nicker.rb +14 -0
  54. data/data/mod_spox/plugins/Parter.rb +23 -0
  55. data/data/mod_spox/plugins/Permissions.rb +60 -0
  56. data/data/mod_spox/plugins/PluginLoader.rb +180 -0
  57. data/data/mod_spox/plugins/Ponger.rb +70 -0
  58. data/data/mod_spox/plugins/PoolConfig.rb +52 -0
  59. data/data/mod_spox/plugins/Quitter.rb +15 -0
  60. data/data/mod_spox/plugins/Servers.rb +57 -0
  61. data/data/mod_spox/plugins/Status.rb +31 -0
  62. data/data/mod_spox/plugins/Triggers.rb +85 -0
  63. data/lib/mod_spox/BaseConfig.rb +51 -0
  64. data/lib/mod_spox/Bot.rb +604 -0
  65. data/lib/mod_spox/BotConfig.rb +65 -0
  66. data/lib/mod_spox/ConfigurationWizard.rb +180 -0
  67. data/lib/mod_spox/Database.rb +51 -0
  68. data/lib/mod_spox/Exceptions.rb +84 -0
  69. data/lib/mod_spox/Helpers.rb +122 -0
  70. data/lib/mod_spox/Loader.rb +60 -0
  71. data/lib/mod_spox/Logger.rb +37 -0
  72. data/lib/mod_spox/MessageFactory.rb +112 -0
  73. data/lib/mod_spox/Pipeline.rb +207 -0
  74. data/lib/mod_spox/Plugin.rb +97 -0
  75. data/lib/mod_spox/PluginHolder.rb +22 -0
  76. data/lib/mod_spox/PluginManager.rb +257 -0
  77. data/lib/mod_spox/PriorityQueue.rb +69 -0
  78. data/lib/mod_spox/Socket.rb +201 -0
  79. data/lib/mod_spox/Sockets.rb +226 -0
  80. data/lib/mod_spox/Timer.rb +60 -0
  81. data/lib/mod_spox/Version.rb +14 -0
  82. data/lib/mod_spox/handlers/BadNick.rb +19 -0
  83. data/lib/mod_spox/handlers/Bounce.rb +24 -0
  84. data/lib/mod_spox/handlers/Created.rb +27 -0
  85. data/lib/mod_spox/handlers/Handler.rb +39 -0
  86. data/lib/mod_spox/handlers/Invite.rb +28 -0
  87. data/lib/mod_spox/handlers/Join.rb +38 -0
  88. data/lib/mod_spox/handlers/Kick.rb +36 -0
  89. data/lib/mod_spox/handlers/LuserChannels.rb +19 -0
  90. data/lib/mod_spox/handlers/LuserClient.rb +18 -0
  91. data/lib/mod_spox/handlers/LuserMe.rb +16 -0
  92. data/lib/mod_spox/handlers/LuserOp.rb +19 -0
  93. data/lib/mod_spox/handlers/LuserUnknown.rb +19 -0
  94. data/lib/mod_spox/handlers/Mode.rb +62 -0
  95. data/lib/mod_spox/handlers/Motd.rb +38 -0
  96. data/lib/mod_spox/handlers/MyInfo.rb +24 -0
  97. data/lib/mod_spox/handlers/Names.rb +86 -0
  98. data/lib/mod_spox/handlers/Nick.rb +50 -0
  99. data/lib/mod_spox/handlers/NickInUse.rb +19 -0
  100. data/lib/mod_spox/handlers/Notice.rb +35 -0
  101. data/lib/mod_spox/handlers/Part.rb +39 -0
  102. data/lib/mod_spox/handlers/Ping.rb +25 -0
  103. data/lib/mod_spox/handlers/Pong.rb +23 -0
  104. data/lib/mod_spox/handlers/Privmsg.rb +39 -0
  105. data/lib/mod_spox/handlers/Quit.rb +29 -0
  106. data/lib/mod_spox/handlers/Topic.rb +38 -0
  107. data/lib/mod_spox/handlers/Welcome.rb +30 -0
  108. data/lib/mod_spox/handlers/Who.rb +83 -0
  109. data/lib/mod_spox/handlers/Whois.rb +117 -0
  110. data/lib/mod_spox/handlers/YourHost.rb +20 -0
  111. data/lib/mod_spox/messages/Messages.rb +6 -0
  112. data/lib/mod_spox/messages/incoming/BadNick.rb +16 -0
  113. data/lib/mod_spox/messages/incoming/Bounce.rb +18 -0
  114. data/lib/mod_spox/messages/incoming/Created.rb +15 -0
  115. data/lib/mod_spox/messages/incoming/Invite.rb +21 -0
  116. data/lib/mod_spox/messages/incoming/Join.rb +19 -0
  117. data/lib/mod_spox/messages/incoming/Kick.rb +26 -0
  118. data/lib/mod_spox/messages/incoming/LuserChannels.rb +15 -0
  119. data/lib/mod_spox/messages/incoming/LuserClient.rb +24 -0
  120. data/lib/mod_spox/messages/incoming/LuserMe.rb +18 -0
  121. data/lib/mod_spox/messages/incoming/LuserOp.rb +15 -0
  122. data/lib/mod_spox/messages/incoming/LuserUnknown.rb +15 -0
  123. data/lib/mod_spox/messages/incoming/Message.rb +22 -0
  124. data/lib/mod_spox/messages/incoming/Mode.rb +42 -0
  125. data/lib/mod_spox/messages/incoming/Motd.rb +18 -0
  126. data/lib/mod_spox/messages/incoming/MyInfo.rb +24 -0
  127. data/lib/mod_spox/messages/incoming/Names.rb +24 -0
  128. data/lib/mod_spox/messages/incoming/Nick.rb +26 -0
  129. data/lib/mod_spox/messages/incoming/NickInUse.rb +15 -0
  130. data/lib/mod_spox/messages/incoming/Notice.rb +9 -0
  131. data/lib/mod_spox/messages/incoming/Part.rb +21 -0
  132. data/lib/mod_spox/messages/incoming/Ping.rb +18 -0
  133. data/lib/mod_spox/messages/incoming/Pong.rb +9 -0
  134. data/lib/mod_spox/messages/incoming/Privmsg.rb +90 -0
  135. data/lib/mod_spox/messages/incoming/Quit.rb +18 -0
  136. data/lib/mod_spox/messages/incoming/Topic.rb +21 -0
  137. data/lib/mod_spox/messages/incoming/TopicInfo.rb +21 -0
  138. data/lib/mod_spox/messages/incoming/Welcome.rb +27 -0
  139. data/lib/mod_spox/messages/incoming/Who.rb +18 -0
  140. data/lib/mod_spox/messages/incoming/Whois.rb +49 -0
  141. data/lib/mod_spox/messages/incoming/YourHost.rb +18 -0
  142. data/lib/mod_spox/messages/internal/BotInitialized.rb +11 -0
  143. data/lib/mod_spox/messages/internal/ChangeNick.rb +15 -0
  144. data/lib/mod_spox/messages/internal/Connected.rb +20 -0
  145. data/lib/mod_spox/messages/internal/ConnectionFailed.rb +23 -0
  146. data/lib/mod_spox/messages/internal/DCCListener.rb +12 -0
  147. data/lib/mod_spox/messages/internal/DCCRequest.rb +12 -0
  148. data/lib/mod_spox/messages/internal/DCCSocket.rb +19 -0
  149. data/lib/mod_spox/messages/internal/Disconnected.rb +8 -0
  150. data/lib/mod_spox/messages/internal/Disconnecting.rb +8 -0
  151. data/lib/mod_spox/messages/internal/EstablishConnection.rb +22 -0
  152. data/lib/mod_spox/messages/internal/HaltBot.rb +8 -0
  153. data/lib/mod_spox/messages/internal/NickRequest.rb +9 -0
  154. data/lib/mod_spox/messages/internal/NickResponse.rb +15 -0
  155. data/lib/mod_spox/messages/internal/PluginLoadRequest.rb +21 -0
  156. data/lib/mod_spox/messages/internal/PluginLoadResponse.rb +17 -0
  157. data/lib/mod_spox/messages/internal/PluginModuleRequest.rb +14 -0
  158. data/lib/mod_spox/messages/internal/PluginModuleResponse.rb +18 -0
  159. data/lib/mod_spox/messages/internal/PluginReload.rb +18 -0
  160. data/lib/mod_spox/messages/internal/PluginRequest.rb +18 -0
  161. data/lib/mod_spox/messages/internal/PluginResponse.rb +21 -0
  162. data/lib/mod_spox/messages/internal/PluginUnloadRequest.rb +9 -0
  163. data/lib/mod_spox/messages/internal/PluginUnloadResponse.rb +9 -0
  164. data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
  165. data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
  166. data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
  167. data/lib/mod_spox/messages/internal/Request.rb +15 -0
  168. data/lib/mod_spox/messages/internal/Response.rb +15 -0
  169. data/lib/mod_spox/messages/internal/Shutdown.rb +8 -0
  170. data/lib/mod_spox/messages/internal/SignaturesUpdate.rb +8 -0
  171. data/lib/mod_spox/messages/internal/StatusRequest.rb +10 -0
  172. data/lib/mod_spox/messages/internal/StatusResponse.rb +18 -0
  173. data/lib/mod_spox/messages/internal/TimerAdd.rb +36 -0
  174. data/lib/mod_spox/messages/internal/TimerClear.rb +16 -0
  175. data/lib/mod_spox/messages/internal/TimerRemove.rb +23 -0
  176. data/lib/mod_spox/messages/internal/TimerResponse.rb +34 -0
  177. data/lib/mod_spox/messages/internal/TriggersUpdate.rb +8 -0
  178. data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
  179. data/lib/mod_spox/messages/outgoing/Admin.rb +15 -0
  180. data/lib/mod_spox/messages/outgoing/Away.rb +11 -0
  181. data/lib/mod_spox/messages/outgoing/ChannelMode.rb +25 -0
  182. data/lib/mod_spox/messages/outgoing/Connect.rb +24 -0
  183. data/lib/mod_spox/messages/outgoing/Die.rb +9 -0
  184. data/lib/mod_spox/messages/outgoing/Info.rb +15 -0
  185. data/lib/mod_spox/messages/outgoing/Invite.rb +19 -0
  186. data/lib/mod_spox/messages/outgoing/Ison.rb +15 -0
  187. data/lib/mod_spox/messages/outgoing/Join.rb +19 -0
  188. data/lib/mod_spox/messages/outgoing/Kick.rb +23 -0
  189. data/lib/mod_spox/messages/outgoing/Kill.rb +19 -0
  190. data/lib/mod_spox/messages/outgoing/Links.rb +19 -0
  191. data/lib/mod_spox/messages/outgoing/List.rb +19 -0
  192. data/lib/mod_spox/messages/outgoing/Lusers.rb +19 -0
  193. data/lib/mod_spox/messages/outgoing/Motd.rb +16 -0
  194. data/lib/mod_spox/messages/outgoing/Names.rb +20 -0
  195. data/lib/mod_spox/messages/outgoing/Nick.rb +16 -0
  196. data/lib/mod_spox/messages/outgoing/Notice.rb +12 -0
  197. data/lib/mod_spox/messages/outgoing/Oper.rb +19 -0
  198. data/lib/mod_spox/messages/outgoing/Part.rb +19 -0
  199. data/lib/mod_spox/messages/outgoing/Pass.rb +16 -0
  200. data/lib/mod_spox/messages/outgoing/Ping.rb +11 -0
  201. data/lib/mod_spox/messages/outgoing/Pong.rb +17 -0
  202. data/lib/mod_spox/messages/outgoing/Privmsg.rb +43 -0
  203. data/lib/mod_spox/messages/outgoing/Quit.rb +11 -0
  204. data/lib/mod_spox/messages/outgoing/Raw.rb +16 -0
  205. data/lib/mod_spox/messages/outgoing/Rehash.rb +9 -0
  206. data/lib/mod_spox/messages/outgoing/Restart.rb +9 -0
  207. data/lib/mod_spox/messages/outgoing/ServList.rb +19 -0
  208. data/lib/mod_spox/messages/outgoing/Simple.rb +12 -0
  209. data/lib/mod_spox/messages/outgoing/Squery.rb +19 -0
  210. data/lib/mod_spox/messages/outgoing/Squit.rb +19 -0
  211. data/lib/mod_spox/messages/outgoing/Stats.rb +18 -0
  212. data/lib/mod_spox/messages/outgoing/Summon.rb +23 -0
  213. data/lib/mod_spox/messages/outgoing/Time.rb +15 -0
  214. data/lib/mod_spox/messages/outgoing/Topic.rb +19 -0
  215. data/lib/mod_spox/messages/outgoing/Trace.rb +15 -0
  216. data/lib/mod_spox/messages/outgoing/Unaway.rb +9 -0
  217. data/lib/mod_spox/messages/outgoing/User.rb +23 -0
  218. data/lib/mod_spox/messages/outgoing/UserHost.rb +15 -0
  219. data/lib/mod_spox/messages/outgoing/UserMode.rb +19 -0
  220. data/lib/mod_spox/messages/outgoing/Users.rb +15 -0
  221. data/lib/mod_spox/messages/outgoing/Version.rb +16 -0
  222. data/lib/mod_spox/messages/outgoing/Who.rb +23 -0
  223. data/lib/mod_spox/messages/outgoing/WhoWas.rb +23 -0
  224. data/lib/mod_spox/messages/outgoing/Whois.rb +19 -0
  225. data/lib/mod_spox/migrations/001_initialize_models.rb +115 -0
  226. data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
  227. data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
  228. data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
  229. data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
  230. data/lib/mod_spox/models/Auth.rb +65 -0
  231. data/lib/mod_spox/models/AuthMask.rb +13 -0
  232. data/lib/mod_spox/models/Channel.rb +89 -0
  233. data/lib/mod_spox/models/Config.rb +30 -0
  234. data/lib/mod_spox/models/Group.rb +30 -0
  235. data/lib/mod_spox/models/Models.rb +4 -0
  236. data/lib/mod_spox/models/Nick.rb +195 -0
  237. data/lib/mod_spox/models/NickMode.rb +32 -0
  238. data/lib/mod_spox/models/Server.rb +27 -0
  239. data/lib/mod_spox/models/Setting.rb +52 -0
  240. data/lib/mod_spox/models/Signature.rb +52 -0
  241. data/lib/mod_spox/models/Trigger.rb +9 -0
  242. data/lib/mod_spox/rfc2812.rb +49 -0
  243. data/populate_gemspec.rb +15 -0
  244. data/tests/BotHolder.rb +24 -0
  245. data/tests/handlers/tc_BadNick.rb +21 -0
  246. data/tests/handlers/tc_Created.rb +24 -0
  247. data/tests/handlers/tc_Invite.rb +50 -0
  248. data/tests/handlers/tc_Join.rb +33 -0
  249. data/tests/handlers/tc_Kick.rb +32 -0
  250. data/tests/handlers/tc_Mode.rb +85 -0
  251. data/tests/handlers/tc_Names.rb +35 -0
  252. data/tests/handlers/tc_Nick.rb +55 -0
  253. data/tests/handlers/tc_Part.rb +44 -0
  254. data/tests/handlers/tc_Ping.rb +40 -0
  255. data/tests/handlers/tc_Pong.rb +28 -0
  256. data/tests/handlers/tc_Privmsg.rb +85 -0
  257. data/tests/handlers/tc_Quit.rb +40 -0
  258. data/tests/handlers/tc_Who.rb +50 -0
  259. data/tests/handlers/tc_Whois.rb +61 -0
  260. data/tests/models/tc_Auth.rb +39 -0
  261. data/tests/models/tc_Channel.rb +52 -0
  262. data/tests/models/tc_Config.rb +19 -0
  263. data/tests/models/tc_Nick.rb +144 -0
  264. data/tests/models/tc_NickMode.rb +40 -0
  265. data/tests/models/tc_Setting.rb +21 -0
  266. data/tests/models/tc_Signature.rb +14 -0
  267. data/tests/run_tests.rb +6 -0
  268. metadata +362 -0
@@ -0,0 +1,244 @@
1
+ require 'net/http'
2
+ require 'digest/md5'
3
+ require 'cgi'
4
+ require 'mod_spox/messages/internal/TimerAdd'
5
+ require 'mod_spox/messages/internal/TimerRemove'
6
+
7
+ # IMPORTANT NOTE: This plugin requires installation of the HTMLEntities gem
8
+ class Confess < ModSpox::Plugin
9
+
10
+ include Models
11
+
12
+ def initialize(pipeline)
13
+ super(pipeline)
14
+ begin
15
+ Confession.db = Sequel.sqlite(BotConfig[:userpath] + '/confessions.db')
16
+ rescue Object => boom
17
+ Logger.warn("Error: Unable to initialize this plugin: #{boom}")
18
+ raise Exceptions::BotException.new("Failed to create database: #{boom}")
19
+ end
20
+ Confession.build_confession && Confession.create_table unless Confession.table_exists?
21
+ add_sig(:sig => 'confess', :method => :confess, :desc => 'Print a confession')
22
+ add_sig(:sig => 'confess (?!score|count|fetcher|\+\+|\-\-)(.+)?', :method => :confess, :desc => 'Print a confession', :params => [:term])
23
+ add_sig(:sig => 'confess(\+\+|\-\-) ?(\d+)?', :method => :score, :desc => 'Score a confession', :params => [:score, :id])
24
+ add_sig(:sig => 'confess score (\d+)', :method => :show_score, :desc => 'Show a confession\'s score', :params => [:id])
25
+ add_sig(:sig => 'confess count', :method => :count, :desc => 'Current count of cached confessions')
26
+ add_sig(:sig => 'confess fetcher (start|stop)', :method => :fetcher, :desc => 'Turn confession fetcher on or off', :group => Group.filter(:name => 'admin').first, :params => [:status])
27
+ add_sig(:sig => 'confess count (.+)', :method => :count_matches, :desc => 'Show number entries matching search', :params => [:query])
28
+ Config.set(:confess, 'nofetch') if Config.val(:confess).nil?
29
+ @last_confession = {}
30
+ @fetch = false
31
+ @timer = {:action => nil, :id => nil}
32
+ @lock = Mutex.new
33
+ start_fetcher if Config.val(:confess) == 'fetch'
34
+ end
35
+
36
+ def destroy
37
+ Confession.db.disconnect
38
+ end
39
+
40
+ def confess(message, params)
41
+ begin
42
+ c = nil
43
+ pk = nil
44
+ @lock.synchronize do
45
+ if(params[:term])
46
+ return if params[:term] == 'count'
47
+ if(params[:term] =~ /^\d+$/)
48
+ c = Confession[params[:term].to_i]
49
+ else
50
+ cs = Confession.search(params[:term])
51
+ Logger.info("Size of confession results: #{cs.size}")
52
+ rand_idx = rand(cs.size - 1)
53
+ rand_id = cs[rand_idx].to_i
54
+ Logger.info("Random index to be used: #{rand_idx}")
55
+ Logger.info("Random ID to be used for confession: #{rand_id}")
56
+ c = Confession[rand_id]
57
+ end
58
+ else
59
+ c = Confession[rand(Confession.count) - 1]
60
+ end
61
+ unless c.nil?
62
+ pk = c.pk
63
+ c = c.confession
64
+ end
65
+ end
66
+ if(c)
67
+ reply message.replyto, "\2[#{pk}]\2: #{c}"
68
+ @last_confession[message.target.pk] = pk
69
+ else
70
+ reply message.replyto, "\2Error:\2 Failed to find confession"
71
+ end
72
+ rescue Object => boom
73
+ reply message.replyto, "Failed to locate a match. Error encountered: #{boom}"
74
+ end
75
+ end
76
+
77
+ def count_matches(m, params)
78
+ begin
79
+ @lock.synchronize do
80
+ reply m.replyto, "Number of matches for \2#{params[:query]}\2: #{Confession.search(params[:query]).size}"
81
+ end
82
+ rescue Object => boom
83
+ error m.replyto, "Failed to count matches. Reason: #{boom}"
84
+ end
85
+ end
86
+
87
+ def show_score(message, params)
88
+ pk = nil
89
+ score = nil
90
+ c = nil
91
+ @lock.synchronize do
92
+ c = Confession[params[:id].to_i]
93
+ if(c)
94
+ pk = c.pk
95
+ score = c.score.to_i
96
+ end
97
+ end
98
+ if(pk)
99
+ reply message.replyto, "\2[#{pk}]:\2 #{score}% of raters gave this confession a positive score"
100
+ else
101
+ reply message.replyto, "\2Error:\2 Failed to find confession with ID: #{params[:id]}"
102
+ end
103
+ end
104
+
105
+ def score(message, params)
106
+ c = nil
107
+ @lock.synchronize do
108
+ if(params[:id])
109
+ c = Confession[params[:id].to_i]
110
+ else
111
+ c = Confession[@last_confession[message.target.pk]] if @last_confession.has_key?(message.target.pk)
112
+ end
113
+ end
114
+ if(c)
115
+ @lock.synchronize do
116
+ if(params[:score] == '++')
117
+ c.update(:positive => c.positive.to_i + 1)
118
+ else
119
+ c.update(:negative => c.negative.to_i + 1)
120
+ end
121
+ c.update(:score => ((c.positive.to_f) / (c.positive.to_f + c.negative.to_f)) * 100.0)
122
+ end
123
+ else
124
+ reply message.replyto, "\2Error:\2 Failed to find confession to score"
125
+ end
126
+ end
127
+
128
+ def count(message, params)
129
+ c = 0
130
+ @lock.synchronize do
131
+ c = Confession.count
132
+ end
133
+ reply message.replyto, "Current number of stored confessions: #{c}"
134
+ end
135
+
136
+ def fetcher(message, params)
137
+ if(params[:status] == 'start')
138
+ if(Config.val(:confess) == 'fetch')
139
+ reply message.replyto, 'Confession fetcher is already running'
140
+ else
141
+ Config.set(:confess, 'fetch')
142
+ reply message.replyto, 'Confession fetcher is now running'
143
+ start_fetcher
144
+ end
145
+ else
146
+ if(Config.val(:confess) == 'fetch')
147
+ Config.set(:confess, 'nofetch')
148
+ stop_fetcher
149
+ reply message.replyto, 'Confession fetcher has been stopped'
150
+ else
151
+ reply message.replyto, 'Confession fetcher is not currently running'
152
+ end
153
+ end
154
+ end
155
+
156
+ def grab_page
157
+ begin
158
+ connection = Net::HTTP.new('www.grouphug.us', 80)
159
+ response = connection.request_get("/frontpage?page=#{rand(17349)+1}", nil)
160
+ response.value
161
+ page = response.body.gsub(/[\r\n]/, ' ')
162
+ Logger.info("Processing matches")
163
+ page.scan(/<div class="content">\s*<p>\s*(.+?)\s*<\/p>\s*<\/div>/).each{|match|
164
+ Logger.info("Match found: #{match[0]}")
165
+ conf = CGI::unescapeHTML(match[0])
166
+ conf = conf.gsub(/<.+?>/, ' ').gsub(/[\r\n]/, '').gsub(/\s+/, ' ')
167
+ conf = Helpers.convert_entities(conf)
168
+ Logger.info("Match turned into: #{conf}")
169
+ if conf.length < 300
170
+ begin
171
+ @lock.synchronize do
172
+ c = Confession.new(:hash => Digest::MD5.hexdigest(conf)).save
173
+ c.confession = conf
174
+ end
175
+ rescue Object => boom
176
+ Logger.warn('Warning: Fetched confession already found in database')
177
+ end
178
+ end
179
+ }
180
+ rescue Object => boom
181
+ Logger.warn("Error fetching data: #{boom}")
182
+ ensure
183
+ @timer[:action].reset_period(rand(1000)+1) unless @timer[:action].nil?
184
+ end
185
+ end
186
+
187
+ private
188
+
189
+ def start_fetcher
190
+ if(@timer[:action].nil?)
191
+ m = Messages::Internal::TimerAdd.new(self, rand(1000)+1){ grab_page }
192
+ @timer[:id] = m.id
193
+ @pipeline << m
194
+ end
195
+ end
196
+
197
+ def get_timer(m)
198
+ if(m.id == @timer[:id])
199
+ if(m.action_added?)
200
+ @timer[:action] = m.action
201
+ else
202
+ @timer = {:action => nil, :id => nil}
203
+ end
204
+ end
205
+ end
206
+
207
+ def stop_fetcher
208
+ unless(@timer[:action].nil?)
209
+ @pipeline << Messages::Internal::TimerRemove(@timer[:action])
210
+ end
211
+ end
212
+
213
+ class Confession < Sequel::Model
214
+ def Confession.build_confession
215
+ db << 'CREATE VIRTUAL TABLE `confessions_confession` USING FTS3(`confession` TEXT NOT NULL)'
216
+ end
217
+
218
+ set_schema do
219
+ text :hash, :null => false, :unique => true
220
+ integer :positive, :null => false, :default => 0
221
+ integer :negative, :null => false, :default => 0
222
+ float :score, :null => false, :default => 0
223
+ primary_key :id
224
+ end
225
+
226
+ def confession=(c)
227
+ if(confession)
228
+ db[:confessions_confession].filter('docid = ?', pk).update(:confession => c)
229
+ else
230
+ db[:confessions_confession] << {:docid => pk, :confession => c}
231
+ end
232
+ end
233
+
234
+ def confession
235
+ c = db[:confessions_confession].select(:confession).where('docid = ?', pk).first
236
+ return c.nil? ? nil : c[:confession]
237
+ end
238
+
239
+ def Confession.search(terms)
240
+ results = db['select docid from confessions_confession where confession match ?', terms].map(:docid)
241
+ end
242
+ end
243
+
244
+ end
@@ -0,0 +1,182 @@
1
+ ['ipaddr', 'socket', 'timeout',
2
+ 'mod_spox/messages/outgoing/Privmsg',
3
+ 'mod_spox/messages/internal/DCCListener'].each{|f| require f}
4
+
5
+ class DCC < ModSpox::Plugin
6
+
7
+ include Models
8
+
9
+ def initialize(pipeline)
10
+ super
11
+ group = Group.find_or_create(:name => 'dcc')
12
+ admin = Group.find_or_create(:name => 'admin')
13
+ add_sig(:sig => 'file list(\s(.+))?', :method => :file_list, :desc => 'List available DCC files', :group => group, :params => [:pattern])
14
+ add_sig(:sig => 'file get (.+)', :method => :file_get, :desc => 'Download file', :group => group, :params => [:filename])
15
+ add_sig(:sig => 'file ports (\d+)-(\d+)', :method => :set_ports, :desc => 'Set allowed DCC ports', :group => admin, :params => [:start, :end])
16
+ add_sig(:sig => 'file adddir (.+)', :method => :add_dir, :desc => 'Add directory to file list', :group => admin, :params => [:dir])
17
+ add_sig(:sig => 'file rmdir (\d+)', :method => :rm_dir, :desc => 'Remove directory from file list', :group => admin, :params => [:dir])
18
+ add_sig(:sig => 'file show dir', :method => :show_dirs, :desc => 'Show directories available to file list', :group => admin)
19
+ add_sig(:sig => 'file show ports', :method => :show_ports, :desc => 'Show allowed ports', :group => admin)
20
+ add_sig(:sig => 'file max wait(\s(\d+))?', :method => :max_wait, :desc => 'Show/set timeout for accepting files', :group => admin, :params => [:wait])
21
+ add_sig(:sig => 'dcc chat', :method => :dcc_chat, :desc => 'Start a DCC chat with the bot (useful if behind firewall', :group => group)
22
+ @servers = {}
23
+ @ports = Setting.val(:dcc_ports)
24
+ @ports = {:start => 49152, :end => 65535} if @ports.nil?
25
+ @dirs = Setting.find_or_create(:name => 'dcc_dirs').value
26
+ @dirs = [] unless @dirs.is_a?(Array)
27
+ @max_wait = Setting.val(:dcc_max_wait)
28
+ @max_wait = @max_wait.nil? ? 60 : @max_wait.to_i
29
+ end
30
+
31
+ def file_list(message, params)
32
+ matches = []
33
+ pattern = params[:pattern] ? Regexp.new(params[:pattern].strip!) : nil
34
+ @dirs.each do |path|
35
+ dir = Dir.new(path)
36
+ dir.each do |file|
37
+ next if File.directory?("#{dir.path}/#{file}") || (file[0] == 46 || file[0] == '.') || !File.readable?("#{dir.path}/#{file}")
38
+ unless(pattern.nil?)
39
+ if(pattern.match(file))
40
+ matches << dir.path + '/' + file + " - #{Helpers.format_size(File.size(dir.path + '/' + file))}"
41
+ end
42
+ else
43
+ matches << dir.path + '/' + file + " - #{Helpers.format_size(File.size(dir.path + '/' + file))}"
44
+ end
45
+ end
46
+ end
47
+ output = ["\2Files in available list:\2 (matching: #{params[:pattern] ? params[:pattern] : ''})"]
48
+ output = output + matches
49
+ reply message.replyto, output
50
+ end
51
+
52
+ def file_get(message, params)
53
+ @try = 0
54
+ socket = nil
55
+ port = 0
56
+ unless(@dirs.include?(File.dirname(params[:filename])))
57
+ reply message.replyto, "\2Error:\2 #{params[:filename]} is not within the allowed directories"
58
+ else
59
+ while(socket.nil? && @try < 3) do
60
+ begin
61
+ port = rand(@ports[:end] - @ports[:start]) + @ports[:start]
62
+ socket = Object::Socket.new(Object::Socket::AF_INET, Object::Socket::SOCK_STREAM, 0)
63
+ addr = Object::Socket.pack_sockaddr_in(port, me.address)
64
+ socket.bind(addr)
65
+ initialize_getter(socket, params[:filename])
66
+ rescue Object => boom
67
+ Logger.warn("Failed to initialize DCC TCPServer. Reason: #{boom}")
68
+ @try += 1
69
+ socket = nil
70
+ port = nil
71
+ end
72
+ end
73
+ if(socket.nil?)
74
+ reply message.replyto, "\2Error:\2 Failed to initialize file getter process."
75
+ else
76
+ ip = IPAddr.new(me.address).to_i
77
+ @pipeline << Messages::Outgoing::Privmsg.new(message.source, "SEND #{File.basename(params[:filename])} #{ip} #{port} #{File.size(params[:filename])}", false, true, 'DCC')
78
+ end
79
+ end
80
+ end
81
+
82
+ def max_wait(message, params)
83
+ wait = params[:wait].nil? ? nil : params[:wait].strip
84
+ unless(wait.nil?)
85
+ @max_wait = wait.to_i
86
+ record = Setting.find_or_create(:name => 'dcc_max_wait')
87
+ record.value = wait
88
+ record.save
89
+ reply message.replyto, "Timeout for file download changed to: #{@max_wait} seconds"
90
+ else
91
+ reply message.replyto, "Timeout for file download is: #{@max_wait} seconds"
92
+ end
93
+ end
94
+
95
+ def set_ports(message, params)
96
+ if(params[:start].to_i > 1024 && params[:end].to_i < 65536)
97
+ @ports = {:start => params[:start].to_i, :end => params[:end].to_i}
98
+ record = Setting.find_or_create(:name => 'dcc_ports')
99
+ record.value = @ports
100
+ record.save
101
+ reply message.replyto, "File ports have been updated to: #{@ports[:start]} - #{@ports[:end]}"
102
+ else
103
+ reply message.replyto, "\2Error:\2 Ports given are out of acceptable range (1025 - 65535)"
104
+ end
105
+ end
106
+
107
+ def add_dir(message, params)
108
+ if(File.readable?(params[:dir]))
109
+ if(@dirs.include?(dir))
110
+ reply message.replyto, "\2Error:\2 Given directory is already in available list. (#{params[:dir]})"
111
+ else
112
+ @dirs << dir
113
+ record = Setting.find_or_create(:name => 'dcc_dirs')
114
+ record.value = @dirs
115
+ record.save
116
+ reply message.replyto, "New directory added to DCC directory list: #{params[:dir]}"
117
+ end
118
+ else
119
+ reply message.replyto, "\2Error:\2 Given directory is not readable. (#{params[:dir]})"
120
+ end
121
+ end
122
+
123
+ def rm_dir(message, params)
124
+ if(@dirs.include?(params[:dir]))
125
+ @dirs.delete(params[:dir])
126
+ record = Setting.find_or_create(:name => 'dcc_dirs')
127
+ record.value = @dirs
128
+ record.save
129
+ reply message.replyto, "DCC directory successfully updated"
130
+ else
131
+ reply message.replyto, "\2Error:\2 Failed to find directory: #{params[:dir]} in available directory list"
132
+ end
133
+ end
134
+
135
+ def show_dirs(message, params)
136
+ output = []
137
+ output << "\2Directories available for DCC file list:\2"
138
+ output += @dirs
139
+ reply message.replyto, output
140
+ end
141
+
142
+ def show_ports(message, params)
143
+ reply message.replyto, "\2Allowed Ports:\2 #{@ports[:start]} - #{@ports[:end]}"
144
+ end
145
+
146
+ def dcc_chat(message, params)
147
+ @pipeline << Messages::Internal::DCCListener.new(message.source)
148
+ end
149
+
150
+ private
151
+
152
+ def initialize_getter(socket, filename)
153
+ @servers[socket.object_id] = Thread.new do
154
+ client = nil
155
+ addrinfo = nil
156
+ cport = nil
157
+ cip = nil
158
+ begin
159
+ Timeout::timeout(@max_wait) do
160
+ socket.listen(5)
161
+ client, addrinfo = socket.accept
162
+ cport, cip = Object::Socket.unpack_sockaddr_in(addrinfo)
163
+ end
164
+ Logger.info("Sending file: #{filename} to IP: #{cip}:#{cport}")
165
+ file = File.new(filename)
166
+ until((line = file.gets).nil?) do
167
+ client << line
168
+ end
169
+ Logger.info("Sending of file: #{filename} to IP: #{addrinfo} is now complete")
170
+ rescue Timeout::Error => boom
171
+ Logger.warn("Error sending file: #{filename}. Timeout exceeded (#{@max_wait} seconds)")
172
+ rescue Object => boom
173
+ Logger.warn("Error sending file: #{filename}. Unknown reason: #{boom}")
174
+ ensure
175
+ socket.close
176
+ client.close
177
+ @servers.delete(socket.object_id)
178
+ end
179
+ end
180
+ end
181
+
182
+ end
@@ -0,0 +1,153 @@
1
+ require 'rexml/document'
2
+ require 'open-uri'
3
+ require 'mod_spox/messages/internal/TimerAdd'
4
+ require 'mod_spox/messages/internal/TimerRemove'
5
+
6
+ class DevWatch < ModSpox::Plugin
7
+
8
+ include ModSpox::Models
9
+
10
+ def initialize(pipeline)
11
+ super(pipeline)
12
+ admin = Group.filter(:name => 'admin').first
13
+ add_sig(:sig => 'devwatch (on|off) (\S+)', :method => :enable_watch, :group => admin, :desc => 'Turn development watcher on/off in given channel', :params => [:status, :channel])
14
+ add_sig(:sig => 'devwatch list', :method => :watch_list, :group => admin, :desc => 'List all channels on the development watch list')
15
+ add_sig(:sig => 'devwatch url ?(\S+)?', :method => :set_url, :group => admin, :desc => 'Set URL for development RSS feed', :params => [:url])
16
+ add_sig(:sig => 'devwatch interval ?(\d+)?', :method => :set_interval, :group => admin, :desc => 'Set time interval for notifications', :params => [:time])
17
+ if(Setting.val(:devwatch).nil?)
18
+ Setting.find_or_create(:name => 'devwatch').value = {:channels => [], :interval => 300}
19
+ end
20
+ @original = nil
21
+ @new = nil
22
+ @timer = {:action => nil, :id => nil}
23
+ start_auto
24
+ check_updates
25
+ end
26
+
27
+ def enable_watch(message, params)
28
+ channel = Channel.filter(:name => params[:channel]).first
29
+ if(channel)
30
+ vals = Setting.val(:devwatch)
31
+ if(params[:status] == 'on')
32
+ vals[:channels] << channel.pk unless vals[:channels].include?(channel.pk)
33
+ reply(message.replyto, "#{channel.name} is now on the development watch list")
34
+ else
35
+ vals[:channels].delete(channel.pk) if vals[:channels].include?(channel.pk)
36
+ reply(message.replyto, "#{channel.name} has been removed from the development watch list")
37
+ end
38
+ Setting.filter(:name => 'devwatch').first.value = vals
39
+ update_auto
40
+ else
41
+ reply(message.replyto, "\2Error:\2 I have no record of #{params[:channel]}.")
42
+ end
43
+ end
44
+
45
+ def watch_list(message, params)
46
+ if(Setting.val(:devwatch)[:channels].empty?)
47
+ reply(message.replyto, "No channels currently on the development watch list")
48
+ else
49
+ chans = []
50
+ Setting.val(:devwatch)[:channels].each{|id| chans << Channel[id].name}
51
+ reply(message.replyto, "Channels on development watch list: #{chans.join(', ')}")
52
+ end
53
+ end
54
+
55
+ def set_url(message, params)
56
+ if(params[:url])
57
+ vals = Setting.val(:devwatch)
58
+ vals[:url] = params[:url]
59
+ reply(message.replyto, "OK")
60
+ Setting.filter(:name => 'devwatch').first.value = vals
61
+ update_auto
62
+ else
63
+ if(Setting.val(:devwatch).has_key?(:url))
64
+ reply(message.replyto, "\2Devwatch URL:\2 #{Setting.val(:devwatch)[:url]}")
65
+ else
66
+ reply(message.replyto, "\2Error:\2 No URL set for devwatch")
67
+ end
68
+ end
69
+ end
70
+
71
+ def set_interval(message, params)
72
+ if(params[:time])
73
+ vals = Setting.val(:devwatch)
74
+ vals[:interval] = params[:time].to_i
75
+ Setting.filter(:name => 'devwatch').first.value = vals
76
+ if(@timer[:action].nil?)
77
+ update_auto
78
+ else
79
+ @timer[:action].reset_period(params[:time].to_i)
80
+ end
81
+ reply(message.replyto, "Devwatch announcement interval reset to: #{Helpers.format_seconds(params[:time].to_i)}")
82
+ else
83
+ reply(message.replyto, "Devwatch announcement interval set to: #{Helpers.format_seconds(Setting.val(:devwatch)[:interval].to_i)}")
84
+ end
85
+ end
86
+
87
+ def check_updates
88
+ if(Setting.val(:devwatch).has_key?(:url) && Setting.val(:devwatch)[:channels].size > 0)
89
+ src = open(Setting.val(:devwatch)[:url])
90
+ doc = REXML::Document.new(src.read)
91
+ if @original.nil?
92
+ doc.elements.each('rss/channel/item') do |item|
93
+ @original = item.elements['title'].text
94
+ break
95
+ end
96
+ Logger.info("Initialized development watch RSS feed: #{@original}")
97
+ else
98
+ @new = doc
99
+ print_new
100
+ end
101
+ end
102
+ end
103
+
104
+ def print_new(max=5)
105
+ new_items = Array.new
106
+ # run through the list until we hit a duplicate #
107
+ i = 1
108
+ new_orig = nil
109
+ @new.elements.each('rss/channel/item') do |item|
110
+ if item.elements['title'].text == @original
111
+ break
112
+ else
113
+ new_orig = item.elements['title'].text if new_orig.nil?
114
+ new_items << "#{item.elements['title'].text}: #{item.elements['link'].text}"
115
+ end
116
+ i += 1
117
+ break if i > max
118
+ end
119
+ @original = new_orig.nil? ? @original : new_orig
120
+ if new_items.size > 0
121
+ new_items.reverse!
122
+ Setting.val(:devwatch)[:channels].each do |id|
123
+ channel = Channel[id]
124
+ new_items.each do |item|
125
+ reply(channel, item)
126
+ end
127
+ end
128
+ end
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.val(:devwatch).has_key?(:url) && Setting.val(:devwatch)[:channels].size > 0)
147
+ m = Messages::Internal::TimerAdd.new(self, Setting.val(:devwatch)[:interval].to_i){ check_updates }
148
+ @timer[:id] = m.id
149
+ @pipeline << m
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,47 @@
1
+ # ex: set ts=4 et:
2
+ require "net/http"
3
+
4
+ # downforeveryoneorjustme.com website-upness-checker plugin
5
+ # by pizza
6
+
7
+ class DownForEveryoneOrJustMe < ModSpox::Plugin
8
+
9
+ def initialize(pipeline)
10
+ super
11
+ add_sig(:sig => 'down ((?:(?:[a-z0-9][a-z0-9-]*)\.)+[a-z]+)',
12
+ :method => :down,
13
+ :desc => 'Check website status',
14
+ :params => [:domain])
15
+ @site = 'http://downforeveryoneorjustme.com/'
16
+ end
17
+
18
+ def down(m, params)
19
+ begin
20
+ # check for valid domain
21
+ domain = params[:domain].downcase
22
+ url = @site + domain
23
+ reply m.replyto, get_text(domain, url)
24
+ rescue Object => boom
25
+ error m.replyto, "Failed to fetch. #{boom}"
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def get_text(domain, url)
32
+ begin
33
+ t = "#{domain} appears "
34
+ data = Net::HTTP.get_response(URI.parse(url)).body
35
+ if /is up/.match(data)
36
+ t = t + "up"
37
+ else
38
+ t = t + "down"
39
+ end
40
+ return t
41
+ rescue Object => boom
42
+ Logger.error(boom)
43
+ raise boom
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,33 @@
1
+ require 'mod_spox/messages/outgoing/Privmsg'
2
+ class EightBall < ModSpox::Plugin
3
+
4
+ include Models
5
+
6
+ def initialize(pipeline)
7
+ super
8
+ add_sig(:sig => '8ball .+\?$', :method => :eightball, :desc => 'Ask the magic eightball a question')
9
+ @responses = ['Ask Again Later',
10
+ 'Better Not Tell You Now',
11
+ 'Concentrate and Ask Again',
12
+ 'Don\'t Count on It',
13
+ 'It Is Certain',
14
+ 'Most Likely',
15
+ 'My Reply is No',
16
+ 'My Sources Say No',
17
+ 'No',
18
+ 'Outlook Good',
19
+ 'Outlook Not So Good',
20
+ 'Reply Hazy, Try Again',
21
+ 'Signs Point to Yes',
22
+ 'Yes',
23
+ 'Yes, Definitely',
24
+ 'You May Rely On It']
25
+ end
26
+
27
+ def eightball(message, params)
28
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'shakes magic 8 ball...', true)
29
+ sleep(1)
30
+ reply message.replyto, "#{message.source.nick}: #{@responses[rand(@responses.size) - 1]}"
31
+ end
32
+
33
+ end