rbot 0.9.14 → 0.9.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (368) hide show
  1. data/AUTHORS +6 -2
  2. data/REQUIREMENTS +7 -1
  3. data/Rakefile +10 -32
  4. data/bin/rbot +6 -1
  5. data/bin/svnwatch-postcommit-hook +68 -0
  6. data/data/rbot/contrib/plugins/stats.rb +3 -3
  7. data/data/rbot/contrib/plugins/vandale.rb +1 -1
  8. data/data/rbot/filters/rss.rb +72 -0
  9. data/data/rbot/languages/finnish.lang +50 -0
  10. data/data/rbot/plugins/alias.rb +6 -6
  11. data/data/rbot/plugins/autorejoin.rb +41 -2
  12. data/data/rbot/plugins/bans.rb +100 -6
  13. data/data/rbot/plugins/bash.rb +9 -4
  14. data/data/rbot/plugins/cal.rb +1 -1
  15. data/data/rbot/plugins/chucknorris.rb +6 -6
  16. data/data/rbot/plugins/debugger.rb +7 -3
  17. data/data/rbot/plugins/deepthoughts.rb +1 -1
  18. data/data/rbot/plugins/delicious.rb +6 -2
  19. data/data/rbot/plugins/dice.rb +7 -7
  20. data/data/rbot/plugins/dict.rb +4 -3
  21. data/data/rbot/plugins/dictclient.rb +17 -13
  22. data/data/rbot/plugins/digg.rb +3 -3
  23. data/data/rbot/plugins/eightball.rb +1 -1
  24. data/data/rbot/plugins/factoids.rb +13 -4
  25. data/data/rbot/plugins/figlet.rb +4 -4
  26. data/data/rbot/plugins/forecast.rb +3 -3
  27. data/data/rbot/plugins/fortune.rb +14 -8
  28. data/data/rbot/plugins/freshmeat.rb +2 -2
  29. data/data/rbot/plugins/games/azgame.rb +72 -19
  30. data/data/rbot/plugins/games/hangman.rb +499 -0
  31. data/data/rbot/plugins/games/quiz.rb +15 -13
  32. data/data/rbot/plugins/games/roshambo.rb +1 -1
  33. data/data/rbot/plugins/games/roulette.rb +4 -4
  34. data/data/rbot/plugins/games/shiritori.rb +31 -31
  35. data/data/rbot/plugins/games/uno.rb +28 -6
  36. data/data/rbot/plugins/games/wheelfortune.rb +1 -3
  37. data/data/rbot/plugins/geoip.rb +83 -28
  38. data/data/rbot/plugins/googlefight.rb +64 -0
  39. data/data/rbot/plugins/greet.rb +45 -0
  40. data/data/rbot/plugins/grouphug.rb +40 -12
  41. data/data/rbot/plugins/imdb.rb +4 -4
  42. data/data/rbot/plugins/insult.rb +2 -2
  43. data/data/rbot/plugins/karma.rb +6 -5
  44. data/data/rbot/plugins/keywords.rb +26 -22
  45. data/data/rbot/plugins/lart.rb +5 -6
  46. data/data/rbot/plugins/lastfm.rb +488 -125
  47. data/data/rbot/plugins/lib_spotify.rb +84 -0
  48. data/data/rbot/plugins/linkbot.rb +1 -1
  49. data/data/rbot/plugins/markov.rb +567 -78
  50. data/data/rbot/plugins/math.rb +3 -3
  51. data/data/rbot/plugins/modes.rb +1 -1
  52. data/data/rbot/plugins/nickrecover.rb +1 -1
  53. data/data/rbot/plugins/nickserv.rb +7 -7
  54. data/data/rbot/plugins/note.rb +55 -0
  55. data/data/rbot/plugins/nslookup.rb +2 -2
  56. data/data/rbot/plugins/quakeauth.rb +4 -4
  57. data/data/rbot/plugins/quotes.rb +53 -19
  58. data/data/rbot/plugins/reaction.rb +76 -19
  59. data/data/rbot/plugins/remind.rb +3 -96
  60. data/data/rbot/plugins/ri.rb +1 -1
  61. data/data/rbot/plugins/rot13.rb +1 -1
  62. data/data/rbot/plugins/rss.rb +296 -190
  63. data/data/rbot/plugins/salut.rb +8 -8
  64. data/data/rbot/plugins/script.rb +48 -11
  65. data/data/rbot/plugins/search.rb +124 -28
  66. data/data/rbot/plugins/seen.rb +162 -31
  67. data/data/rbot/plugins/shortenurls.rb +1 -1
  68. data/data/rbot/plugins/slashdot.rb +19 -6
  69. data/data/rbot/plugins/spotify.rb +78 -0
  70. data/data/rbot/plugins/theyfightcrime.rb +10 -10
  71. data/data/rbot/plugins/time.rb +2 -2
  72. data/data/rbot/plugins/translator.rb +161 -85
  73. data/data/rbot/plugins/tube.rb +2 -2
  74. data/data/rbot/plugins/tumblr.rb +143 -0
  75. data/data/rbot/plugins/twitter.rb +25 -6
  76. data/data/rbot/plugins/urban.rb +6 -4
  77. data/data/rbot/plugins/url.rb +49 -10
  78. data/data/rbot/plugins/weather.rb +6 -6
  79. data/data/rbot/plugins/wserver.rb +5 -5
  80. data/data/rbot/plugins/youtube.rb +12 -12
  81. data/data/rbot/templates/lart/larts-italian +1 -1
  82. data/launch_here.rb +68 -0
  83. data/lib/rbot/botuser.rb +1 -1
  84. data/lib/rbot/compat19.rb +70 -0
  85. data/lib/rbot/config.rb +8 -6
  86. data/lib/rbot/core/auth.rb +37 -21
  87. data/lib/rbot/core/basics.rb +33 -2
  88. data/lib/rbot/core/config.rb +24 -17
  89. data/lib/rbot/core/filters_ui.rb +2 -2
  90. data/lib/rbot/core/irclog.rb +20 -11
  91. data/lib/rbot/core/remote.rb +9 -9
  92. data/lib/rbot/core/unicode.rb +4 -0
  93. data/lib/rbot/core/userdata.rb +16 -1
  94. data/lib/rbot/core/utils/extends.rb +76 -0
  95. data/lib/rbot/core/utils/filters.rb +47 -0
  96. data/lib/rbot/core/utils/httputil.rb +36 -26
  97. data/lib/rbot/core/utils/parse_time.rb +193 -0
  98. data/lib/rbot/core/utils/utils.rb +81 -56
  99. data/lib/rbot/core/utils/wordlist.rb +66 -0
  100. data/lib/rbot/core/wordlist_ui.rb +27 -0
  101. data/lib/rbot/irc.rb +59 -19
  102. data/lib/rbot/ircbot.rb +190 -58
  103. data/lib/rbot/ircsocket.rb +14 -8
  104. data/lib/rbot/language.rb +4 -3
  105. data/lib/rbot/load-gettext.rb +22 -9
  106. data/lib/rbot/message.rb +89 -18
  107. data/lib/rbot/messagemapper.rb +71 -19
  108. data/lib/rbot/plugins.rb +112 -44
  109. data/lib/rbot/{registry.rb → registry/bdb.rb} +226 -22
  110. data/lib/rbot/registry/tc.rb +531 -0
  111. data/lib/rbot/rfc2812.rb +33 -8
  112. data/lib/rbot/timer.rb +12 -20
  113. data/po/en_US/rbot-autorejoin.po +3 -0
  114. data/po/en_US/rbot-azgame.po +51 -43
  115. data/po/en_US/rbot-bash.po +15 -0
  116. data/po/en_US/rbot-dictclient.po +20 -20
  117. data/po/en_US/rbot-factoids.po +9 -9
  118. data/po/en_US/rbot-geoip.po +0 -0
  119. data/po/en_US/rbot-googlefight.po +24 -0
  120. data/po/en_US/rbot-grouphug.po +4 -4
  121. data/po/en_US/rbot-hangman.po +114 -0
  122. data/po/en_US/rbot-keywords.po +3 -3
  123. data/po/en_US/rbot-lastfm.po +268 -70
  124. data/po/en_US/rbot-markov.po +73 -2
  125. data/po/en_US/rbot-quotes.po +21 -21
  126. data/po/en_US/rbot-rss.po +6 -2
  127. data/po/en_US/rbot-script.po +3 -0
  128. data/po/en_US/rbot-seen.po +72 -0
  129. data/po/en_US/rbot-spell.po +2 -2
  130. data/po/en_US/rbot-translator.po +13 -13
  131. data/po/en_US/rbot-twitter.po +3 -3
  132. data/po/en_US/rbot-uno.po +131 -114
  133. data/po/en_US/rbot-wall.po +12 -13
  134. data/po/en_US/rbot-wheelfortune.po +41 -41
  135. data/po/en_US/rbot.po +254 -194
  136. data/po/fi/rbot-alias.po +82 -0
  137. data/po/fi/rbot-autoop.po +0 -0
  138. data/po/fi/rbot-autorejoin.po +20 -0
  139. data/po/fi/rbot-azgame.po +194 -0
  140. data/po/fi/rbot-bans.po +0 -0
  141. data/po/fi/rbot-bash.po +32 -0
  142. data/po/fi/rbot-botsnack.po +0 -0
  143. data/po/fi/rbot-cal.po +20 -0
  144. data/po/fi/rbot-chanserv.po +0 -0
  145. data/po/fi/rbot-chucknorris.po +0 -0
  146. data/po/fi/rbot-debugger.po +0 -0
  147. data/po/fi/rbot-deepthoughts.po +0 -0
  148. data/po/fi/rbot-delicious.po +0 -0
  149. data/po/fi/rbot-dice.po +0 -0
  150. data/po/fi/rbot-dict.po +0 -0
  151. data/po/fi/rbot-dictclient.po +111 -0
  152. data/po/fi/rbot-digg.po +0 -0
  153. data/po/fi/rbot-eightball.po +0 -0
  154. data/po/fi/rbot-excuse.po +0 -0
  155. data/po/fi/rbot-factoids.po +107 -0
  156. data/po/fi/rbot-figlet.po +36 -0
  157. data/po/fi/rbot-fish.po +0 -0
  158. data/po/fi/rbot-forecast.po +0 -0
  159. data/po/fi/rbot-fortune.po +0 -0
  160. data/po/fi/rbot-freshmeat.po +0 -0
  161. data/po/fi/rbot-geoip.po +0 -0
  162. data/po/fi/rbot-googlefight.po +24 -0
  163. data/po/fi/rbot-grouphug.po +35 -0
  164. data/po/fi/rbot-hangman.po +121 -0
  165. data/po/fi/rbot-hl2.po +0 -0
  166. data/po/fi/rbot-host.po +20 -0
  167. data/po/fi/rbot-imdb.po +0 -0
  168. data/po/fi/rbot-insult.po +0 -0
  169. data/po/fi/rbot-iplookup.po +0 -0
  170. data/po/fi/rbot-karma.po +0 -0
  171. data/po/fi/rbot-keywords.po +24 -0
  172. data/po/fi/rbot-lart.po +0 -0
  173. data/po/fi/rbot-lastfm.po +377 -0
  174. data/po/fi/rbot-linkbot.po +0 -0
  175. data/po/fi/rbot-markov.po +91 -0
  176. data/po/fi/rbot-math.po +0 -0
  177. data/po/fi/rbot-modes.po +0 -0
  178. data/po/fi/rbot-nickrecover.po +36 -0
  179. data/po/fi/rbot-nickserv.po +104 -0
  180. data/po/fi/rbot-nslookup.po +0 -0
  181. data/po/fi/rbot-quakeauth.po +0 -0
  182. data/po/fi/rbot-quiz.po +0 -0
  183. data/po/fi/rbot-quotes.po +108 -0
  184. data/po/fi/rbot-reaction.po +0 -0
  185. data/po/fi/rbot-remind.po +0 -0
  186. data/po/fi/rbot-remotectl.po +0 -0
  187. data/po/fi/rbot-ri.po +0 -0
  188. data/po/fi/rbot-roshambo.po +0 -0
  189. data/po/fi/rbot-rot13.po +0 -0
  190. data/po/fi/rbot-roulette.po +0 -0
  191. data/po/fi/rbot-rss.po +24 -0
  192. data/po/fi/rbot-salut.po +0 -0
  193. data/po/fi/rbot-script.po +20 -0
  194. data/po/fi/rbot-search.po +0 -0
  195. data/po/fi/rbot-seen.po +92 -0
  196. data/po/fi/rbot-shiritori.po +102 -0
  197. data/po/fi/rbot-shortenurls.po +0 -0
  198. data/po/fi/rbot-slashdot.po +0 -0
  199. data/po/fi/rbot-spell.po +54 -0
  200. data/po/fi/rbot-theyfightcrime.po +0 -0
  201. data/po/fi/rbot-threat.po +0 -0
  202. data/po/fi/rbot-time.po +0 -0
  203. data/po/fi/rbot-topic.po +0 -0
  204. data/po/fi/rbot-translator.po +77 -0
  205. data/po/fi/rbot-tube.po +0 -0
  206. data/po/fi/rbot-twitter.po +24 -0
  207. data/po/fi/rbot-uno.po +529 -0
  208. data/po/fi/rbot-urban.po +0 -0
  209. data/po/fi/rbot-url.po +0 -0
  210. data/po/fi/rbot-usermodes.po +0 -0
  211. data/po/fi/rbot-wall.po +32 -0
  212. data/po/fi/rbot-weather.po +0 -0
  213. data/po/fi/rbot-wheelfortune.po +205 -0
  214. data/po/fi/rbot-wow.po +0 -0
  215. data/po/fi/rbot-wserver.po +0 -0
  216. data/po/fi/rbot-youtube.po +58 -0
  217. data/po/fi/rbot.po +1152 -0
  218. data/po/fr/rbot-autorejoin.po +3 -0
  219. data/po/fr/rbot-azgame.po +51 -43
  220. data/po/fr/rbot-bash.po +15 -0
  221. data/po/fr/rbot-dictclient.po +20 -20
  222. data/po/fr/rbot-factoids.po +9 -9
  223. data/po/fr/rbot-geoip.po +0 -0
  224. data/po/fr/rbot-googlefight.po +24 -0
  225. data/po/fr/rbot-grouphug.po +4 -4
  226. data/po/fr/rbot-hangman.po +114 -0
  227. data/po/fr/rbot-keywords.po +3 -3
  228. data/po/fr/rbot-lastfm.po +268 -70
  229. data/po/fr/rbot-markov.po +74 -2
  230. data/po/fr/rbot-quotes.po +21 -21
  231. data/po/fr/rbot-rss.po +6 -2
  232. data/po/fr/rbot-script.po +3 -0
  233. data/po/fr/rbot-seen.po +72 -0
  234. data/po/fr/rbot-spell.po +2 -2
  235. data/po/fr/rbot-translator.po +13 -13
  236. data/po/fr/rbot-twitter.po +3 -3
  237. data/po/fr/rbot-uno.po +132 -114
  238. data/po/fr/rbot-wall.po +8 -9
  239. data/po/fr/rbot-wheelfortune.po +41 -41
  240. data/po/fr/rbot.po +268 -197
  241. data/po/it/rbot-autorejoin.po +3 -0
  242. data/po/it/rbot-azgame.po +50 -42
  243. data/po/it/rbot-bash.po +15 -0
  244. data/po/it/rbot-dictclient.po +20 -20
  245. data/po/it/rbot-factoids.po +9 -9
  246. data/po/it/rbot-geoip.po +0 -0
  247. data/po/it/rbot-googlefight.po +24 -0
  248. data/po/it/rbot-grouphug.po +4 -4
  249. data/po/it/rbot-hangman.po +114 -0
  250. data/po/it/rbot-keywords.po +3 -3
  251. data/po/it/rbot-lastfm.po +268 -70
  252. data/po/it/rbot-markov.po +75 -3
  253. data/po/it/rbot-quotes.po +21 -21
  254. data/po/it/rbot-rss.po +7 -3
  255. data/po/it/rbot-script.po +19 -0
  256. data/po/it/rbot-seen.po +72 -0
  257. data/po/it/rbot-spell.po +2 -2
  258. data/po/it/rbot-translator.po +13 -13
  259. data/po/it/rbot-twitter.po +3 -3
  260. data/po/it/rbot-uno.po +137 -116
  261. data/po/it/rbot-wall.po +8 -9
  262. data/po/it/rbot-wheelfortune.po +41 -41
  263. data/po/it/rbot.po +265 -208
  264. data/po/ja/rbot-autorejoin.po +3 -0
  265. data/po/ja/rbot-azgame.po +51 -43
  266. data/po/ja/rbot-bash.po +15 -0
  267. data/po/ja/rbot-dictclient.po +20 -20
  268. data/po/ja/rbot-factoids.po +9 -9
  269. data/po/ja/rbot-geoip.po +0 -0
  270. data/po/ja/rbot-googlefight.po +24 -0
  271. data/po/ja/rbot-grouphug.po +4 -4
  272. data/po/ja/rbot-hangman.po +114 -0
  273. data/po/ja/rbot-keywords.po +3 -3
  274. data/po/ja/rbot-lastfm.po +268 -70
  275. data/po/ja/rbot-markov.po +73 -2
  276. data/po/ja/rbot-quotes.po +21 -21
  277. data/po/ja/rbot-rss.po +6 -2
  278. data/po/ja/rbot-script.po +3 -0
  279. data/po/ja/rbot-seen.po +72 -0
  280. data/po/ja/rbot-spell.po +2 -2
  281. data/po/ja/rbot-translator.po +13 -13
  282. data/po/ja/rbot-twitter.po +3 -3
  283. data/po/ja/rbot-uno.po +131 -114
  284. data/po/ja/rbot-wall.po +8 -9
  285. data/po/ja/rbot-wheelfortune.po +41 -41
  286. data/po/ja/rbot.po +248 -192
  287. data/po/rbot-alias.pot +2 -2
  288. data/po/rbot-autorejoin.pot +21 -0
  289. data/po/rbot-azgame.pot +51 -43
  290. data/po/rbot-bash.pot +33 -0
  291. data/po/rbot-cal.pot +2 -2
  292. data/po/rbot-dictclient.pot +21 -21
  293. data/po/rbot-factoids.pot +10 -10
  294. data/po/rbot-figlet.pot +2 -2
  295. data/po/rbot-geoip.pot +0 -0
  296. data/po/rbot-googlefight.pot +25 -0
  297. data/po/rbot-grouphug.pot +6 -6
  298. data/po/rbot-hangman.pot +115 -0
  299. data/po/rbot-host.pot +2 -2
  300. data/po/rbot-keywords.pot +4 -4
  301. data/po/rbot-lastfm.pot +270 -72
  302. data/po/rbot-markov.pot +74 -3
  303. data/po/rbot-nickrecover.pot +2 -2
  304. data/po/rbot-nickserv.pot +2 -2
  305. data/po/rbot-quotes.pot +22 -22
  306. data/po/rbot-rss.pot +7 -3
  307. data/po/rbot-script.pot +21 -0
  308. data/po/rbot-seen.pot +90 -0
  309. data/po/rbot-shiritori.pot +2 -2
  310. data/po/rbot-spell.pot +3 -3
  311. data/po/rbot-translator.pot +14 -14
  312. data/po/rbot-twitter.pot +4 -4
  313. data/po/rbot-uno.pot +132 -115
  314. data/po/rbot-wall.pot +2 -2
  315. data/po/rbot-wheelfortune.pot +42 -42
  316. data/po/rbot-youtube.pot +2 -2
  317. data/po/rbot.pot +249 -193
  318. data/po/zh_CN/rbot-autorejoin.po +3 -0
  319. data/po/zh_CN/rbot-azgame.po +50 -42
  320. data/po/zh_CN/rbot-bash.po +15 -0
  321. data/po/zh_CN/rbot-dictclient.po +20 -20
  322. data/po/zh_CN/rbot-factoids.po +9 -9
  323. data/po/zh_CN/rbot-geoip.po +0 -0
  324. data/po/zh_CN/rbot-googlefight.po +24 -0
  325. data/po/zh_CN/rbot-grouphug.po +4 -4
  326. data/po/zh_CN/rbot-hangman.po +114 -0
  327. data/po/zh_CN/rbot-keywords.po +3 -3
  328. data/po/zh_CN/rbot-lastfm.po +268 -70
  329. data/po/zh_CN/rbot-markov.po +73 -2
  330. data/po/zh_CN/rbot-quotes.po +21 -21
  331. data/po/zh_CN/rbot-rss.po +6 -2
  332. data/po/zh_CN/rbot-script.po +3 -0
  333. data/po/zh_CN/rbot-seen.po +72 -0
  334. data/po/zh_CN/rbot-spell.po +2 -2
  335. data/po/zh_CN/rbot-translator.po +13 -13
  336. data/po/zh_CN/rbot-twitter.po +3 -3
  337. data/po/zh_CN/rbot-uno.po +131 -114
  338. data/po/zh_CN/rbot-wall.po +7 -8
  339. data/po/zh_CN/rbot-wheelfortune.po +41 -41
  340. data/po/zh_CN/rbot.po +248 -192
  341. data/po/zh_TW/rbot-autorejoin.po +3 -0
  342. data/po/zh_TW/rbot-azgame.po +50 -42
  343. data/po/zh_TW/rbot-bash.po +15 -0
  344. data/po/zh_TW/rbot-dictclient.po +20 -20
  345. data/po/zh_TW/rbot-factoids.po +9 -9
  346. data/po/zh_TW/rbot-geoip.po +0 -0
  347. data/po/zh_TW/rbot-googlefight.po +24 -0
  348. data/po/zh_TW/rbot-grouphug.po +4 -4
  349. data/po/zh_TW/rbot-hangman.po +114 -0
  350. data/po/zh_TW/rbot-keywords.po +3 -3
  351. data/po/zh_TW/rbot-lastfm.po +268 -70
  352. data/po/zh_TW/rbot-markov.po +73 -2
  353. data/po/zh_TW/rbot-quotes.po +21 -21
  354. data/po/zh_TW/rbot-rss.po +6 -2
  355. data/po/zh_TW/rbot-script.po +3 -0
  356. data/po/zh_TW/rbot-seen.po +72 -0
  357. data/po/zh_TW/rbot-spell.po +2 -2
  358. data/po/zh_TW/rbot-translator.po +13 -13
  359. data/po/zh_TW/rbot-twitter.po +3 -3
  360. data/po/zh_TW/rbot-uno.po +131 -114
  361. data/po/zh_TW/rbot-wall.po +7 -8
  362. data/po/zh_TW/rbot-wheelfortune.po +41 -41
  363. data/po/zh_TW/rbot.po +253 -194
  364. data/setup.rb +4 -4
  365. metadata +127 -18
  366. data/README +0 -43
  367. data/data/rbot/plugins/fish.rb +0 -121
  368. data/lib/rbot/dbhash.rb +0 -199
@@ -16,15 +16,6 @@ require 'set'
16
16
  begin
17
17
  require 'htmlentities'
18
18
  rescue LoadError
19
- gems = nil
20
- begin
21
- gems = require 'rubygems'
22
- rescue LoadError
23
- gems = false
24
- end
25
- if gems
26
- retry
27
- else
28
19
  module ::Irc
29
20
  module Utils
30
21
  UNESCAPE_TABLE = {
@@ -108,7 +99,6 @@ rescue LoadError
108
99
  }
109
100
  end
110
101
  end
111
- end
112
102
  end
113
103
 
114
104
  begin
@@ -121,15 +111,6 @@ begin
121
111
  end
122
112
  end
123
113
  rescue LoadError
124
- gems = nil
125
- begin
126
- gems = require 'rubygems'
127
- rescue LoadError
128
- gems = false
129
- end
130
- if gems
131
- retry
132
- else
133
114
  module ::Irc
134
115
  module Utils
135
116
  # Some regular expressions to manage HTML data
@@ -150,7 +131,6 @@ rescue LoadError
150
131
  AFTER_PAR2_REGEX = /<br(?:\s+[^>]*)?\/?>.*?<\/?(?:br|p|div|html|body|table|td|tr)(?:\s+[^>]*)?\/?>/im
151
132
  end
152
133
  end
153
- end
154
134
  end
155
135
 
156
136
  module ::Irc
@@ -169,7 +149,7 @@ module ::Irc
169
149
  def Utils.bot=(b)
170
150
  debug "initializing utils"
171
151
  @@bot = b
172
- @@safe_save_dir = "#{@@bot.botclass}/safe_save"
152
+ @@safe_save_dir = @@bot.path('safe_save')
173
153
  end
174
154
 
175
155
 
@@ -179,10 +159,12 @@ module ::Irc
179
159
  SEC_PER_HR = SEC_PER_MIN * 60
180
160
  # Seconds per day
181
161
  SEC_PER_DAY = SEC_PER_HR * 24
162
+ # Seconds per week
163
+ SEC_PER_WK = SEC_PER_DAY * 7
182
164
  # Seconds per (30-day) month
183
165
  SEC_PER_MNTH = SEC_PER_DAY * 30
184
- # Second per (30*12 = 360 day) year
185
- SEC_PER_YR = SEC_PER_MNTH * 12
166
+ # Second per (non-leap) year
167
+ SEC_PER_YR = SEC_PER_DAY * 365
186
168
 
187
169
  # Auxiliary method needed by Utils.secs_to_string
188
170
  def Utils.secs_to_string_case(array, var, string, plural)
@@ -244,44 +226,54 @@ module ::Irc
244
226
  # :date_format, used with <tt>to_formatted_s<tt>, default to :default
245
227
  def Utils.timeago(time, options = {})
246
228
  start_date = options.delete(:start_date) || Time.new
247
- date_format = options.delete(:date_format) || :default
248
- delta_minutes = (start_date.to_i - time.to_i).floor / 60
249
- if delta_minutes.abs <= (8724*60) # eight weeks? I'm lazy to count days for longer than that
250
- distance = Utils.distance_of_time_in_words(delta_minutes);
251
- if delta_minutes < 0
229
+ date_format = options.delete(:date_format) || "%x"
230
+ delta = (start_date - time).round
231
+ if delta.abs < 2
232
+ _("right now")
233
+ else
234
+ distance = Utils.age_string(delta)
235
+ if delta < 0
252
236
  _("%{d} from now") % {:d => distance}
253
237
  else
254
238
  _("%{d} ago") % {:d => distance}
255
239
  end
256
- else
257
- return _("on %{date}") % {:date => system_date.to_formatted_s(date_format)}
258
240
  end
259
241
  end
260
- # Translates a number of minutes into verbal distances.
261
- # e.g. 0.5 => less than a minute
262
- # 70 => about one hour
263
- def Utils.distance_of_time_in_words(minutes)
264
- case
265
- when minutes < 1
266
- _("less than a minute")
267
- when minutes < 50
268
- _("%{m} minutes") % {:m => minutes}
269
- when minutes < 90
270
- _("about one hour")
271
- when minutes < 1080
272
- _("%{m} hours") % {:m => (minutes / 60).round}
273
- when minutes < 1440
274
- _("one day")
275
- when minutes < 2880
276
- _("about one day")
242
+
243
+ # Converts age in seconds to "nn units". Inspired by previous attempts
244
+ # but also gitweb's age_string() sub
245
+ def Utils.age_string(secs)
246
+ case
247
+ when secs < 0
248
+ Utils.age_string(-secs)
249
+ when secs > 2*SEC_PER_YR
250
+ _("%{m} years") % { :m => secs/SEC_PER_YR }
251
+ when secs > 2*SEC_PER_MNTH
252
+ _("%{m} months") % { :m => secs/SEC_PER_MNTH }
253
+ when secs > 2*SEC_PER_WK
254
+ _("%{m} weeks") % { :m => secs/SEC_PER_WK }
255
+ when secs > 2*SEC_PER_DAY
256
+ _("%{m} days") % { :m => secs/SEC_PER_DAY }
257
+ when secs > 2*SEC_PER_HR
258
+ _("%{m} hours") % { :m => secs/SEC_PER_HR }
259
+ when (20*SEC_PER_MIN..40*SEC_PER_MIN).include?(secs)
260
+ _("half an hour")
261
+ when (50*SEC_PER_MIN..70*SEC_PER_MIN).include?(secs)
262
+ # _("about one hour")
263
+ _("an hour")
264
+ when (80*SEC_PER_MIN..100*SEC_PER_MIN).include?(secs)
265
+ _("an hour and a half")
266
+ when secs > 2*SEC_PER_MIN
267
+ _("%{m} minutes") % { :m => secs/SEC_PER_MIN }
268
+ when secs > 1
269
+ _("%{m} seconds") % { :m => secs }
277
270
  else
278
- _("%{m} days") % {:m => (minutes / 1440).round}
271
+ _("one second")
272
+ end
279
273
  end
280
- end
281
-
282
274
 
283
275
  # Execute an external program, returning a String obtained by redirecting
284
- # the program's standards errors and output
276
+ # the program's standards errors and output
285
277
  #
286
278
  def Utils.safe_exec(command, *args)
287
279
  IO.popen("-") { |p|
@@ -292,15 +284,34 @@ module ::Irc
292
284
  $stderr.reopen($stdout)
293
285
  exec(command, *args)
294
286
  rescue Exception => e
295
- puts "exec of #{command} led to exception: #{e.pretty_inspect}"
296
- Kernel::exit! 0
287
+ puts "exception #{e.pretty_inspect} trying to run #{command}"
288
+ Kernel::exit! 1
297
289
  end
298
290
  puts "exec of #{command} failed"
299
- Kernel::exit! 0
291
+ Kernel::exit! 1
300
292
  end
301
293
  }
302
294
  end
303
295
 
296
+ # Try executing an external program, returning true if the run was successful
297
+ # and false otherwise
298
+ def Utils.try_exec(command, *args)
299
+ IO.popen("-") { |p|
300
+ if p.nil?
301
+ begin
302
+ $stderr.reopen($stdout)
303
+ exec(command, *args)
304
+ rescue Exception => e
305
+ Kernel::exit! 1
306
+ end
307
+ Kernel::exit! 1
308
+ else
309
+ debug p.readlines
310
+ end
311
+ }
312
+ debug $?
313
+ return $?.success?
314
+ end
304
315
 
305
316
  # Safely (atomically) save to _file_, by passing a tempfile to the block
306
317
  # and then moving the tempfile to its final location when done.
@@ -620,7 +631,7 @@ module ::Irc
620
631
  # returns non-nil, its results are merged in _ds_ and returned. Otherwise
621
632
  # nil is returned.
622
633
  #
623
- # The input DataStream shuold have the downloaded HTML as primary key
634
+ # The input DataStream should have the downloaded HTML as primary key
624
635
  # (:text) and possibly a :headers key holding the resonse headers.
625
636
  #
626
637
  def Utils.try_htmlinfo_filters(ds)
@@ -629,7 +640,7 @@ module ::Irc
629
640
  cur = nil
630
641
  # TODO filter priority
631
642
  filters.each { |n|
632
- debug "testing filter #{n}"
643
+ debug "testing htmlinfo filter #{n}"
633
644
  cur = @@bot.filter(@@bot.global_filter_name(n, :htmlinfo), ds)
634
645
  debug "returned #{cur.pretty_inspect}"
635
646
  break if cur
@@ -711,6 +722,20 @@ module ::Irc
711
722
  return retval
712
723
  end
713
724
 
725
+ # Returns a comma separated list except for the last element
726
+ # which is joined in with specified conjunction
727
+ #
728
+ def Utils.comma_list(words, options={})
729
+ defaults = { :join_with => ", ", :join_last_with => _(" and ") }
730
+ opts = defaults.merge(options)
731
+
732
+ if words.size < 2
733
+ words.last
734
+ else
735
+ [words[0..-2].join(opts[:join_with]), words.last].join(opts[:join_last_with])
736
+ end
737
+ end
738
+
714
739
  end
715
740
  end
716
741
 
@@ -0,0 +1,66 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: rbot wordlist provider
5
+ #
6
+ # Author:: Raine Virta <rane@kapsi.fi>
7
+
8
+ require "find"
9
+
10
+ module ::Irc
11
+ class Bot
12
+ class Wordlist
13
+ def self.wordlist_base
14
+ @@wordlist_base ||= Utils.bot.path 'wordlists'
15
+ end
16
+
17
+ def self.get(path, options={})
18
+ opts = { :spaces => false }.merge(options)
19
+
20
+ wordlist_path = File.join(wordlist_base, path)
21
+ raise "wordlist not found: #{wordlist_path}" unless File.exist?(wordlist_path)
22
+
23
+ # Location is a directory -> combine all lists beneath it
24
+ wordlist = if File.directory?(wordlist_path)
25
+ wordlists = []
26
+ Find.find(wordlist_path) do |path|
27
+ next if path == wordlist_path
28
+ wordlists << path unless File.directory?(path)
29
+ end
30
+
31
+ wordlists.map { |list| File.readlines(list) }.flatten
32
+ else
33
+ File.readlines(wordlist_path)
34
+ end
35
+
36
+ # wordlists are assumed to be UTF-8, but we need to strip the BOM, if present
37
+ wordlist.map! { |l| l.sub("\xef\xbb\xbf",'').strip }
38
+ wordlist.reject do |word|
39
+ word =~ /\s/ && !opts[:spaces] ||
40
+ word.empty?
41
+ end
42
+ end
43
+
44
+ # Return an array with the list of available wordlists.
45
+ # Available options:
46
+ # pattern:: pattern that should be matched by the wordlist filename
47
+ def self.list(options={})
48
+ pattern = options[:pattern] || "**"
49
+ # refuse patterns that contain ../
50
+ return [] if pattern =~ /\.\.\//
51
+ striplen = self.wordlist_base.length+1
52
+ Dir.glob(File.join(self.wordlist_base, pattern)).map { |name|
53
+ name[striplen..-1]
54
+ }
55
+ end
56
+
57
+ def self.exist?(path)
58
+ fn = path.to_s
59
+ # refuse to check outside of the wordlist base directory
60
+ return false if fn =~ /\.\.\//
61
+ File.exist?(File.join(self.wordlist_base, fn))
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,27 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: wordlist management from IRC
5
+ #
6
+ # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7
+
8
+ class WordlistModule < CoreBotModule
9
+ def help(plugin, topic="")
10
+ _("wordlist list [<pattern>] => list wordlists (matching <pattern>)")
11
+ end
12
+
13
+ def do_list(m, p)
14
+ found = Wordlist.list(p)
15
+ if found.empty?
16
+ m.reply _("no wordlist found")
17
+ else
18
+ m.reply _("Wordlists: %{found}") % {
19
+ :found => found.sort.join(', ')
20
+ }
21
+ end
22
+ end
23
+ end
24
+
25
+ plugin = WordlistModule.new
26
+
27
+ plugin.map "wordlist list [:pattern]", :action => :do_list
@@ -21,6 +21,21 @@
21
21
 
22
22
  require 'singleton'
23
23
 
24
+ # The following monkeypatch is to fix a bug in Singleton where marshaling would
25
+ # fail when trying to restore a marshaled Singleton due to _load being declared
26
+ # private.
27
+ if RUBY_VERSION < '1.9'
28
+ module ::Singleton
29
+ public :_dump
30
+ end
31
+
32
+ class << Singleton
33
+ module SingletonClassMethods
34
+ public :_load
35
+ end
36
+ end
37
+ end
38
+
24
39
  class Object
25
40
 
26
41
  # We extend the Object class with a method that
@@ -33,7 +48,7 @@ class Object
33
48
 
34
49
  # We alias the to_s method to __to_s__ to make
35
50
  # it accessible in all classes
36
- alias :__to_s__ :to_s
51
+ alias :__to_s__ :to_s
37
52
  end
38
53
 
39
54
  # The Irc module is used to keep all IRC-related classes
@@ -129,7 +144,7 @@ module Irc
129
144
  include Singleton
130
145
 
131
146
  def initialize
132
- super('rfc1459', "\x41-\x5e", "\x61-\x7e")
147
+ super('rfc1459', "\x41-\x5a\x7b-\x7e", "\x61-\x7a\x5b-\x5e")
133
148
  end
134
149
 
135
150
  end
@@ -141,7 +156,7 @@ module Irc
141
156
  include Singleton
142
157
 
143
158
  def initialize
144
- super('strict-rfc1459', "\x41-\x5d", "\x61-\x7d")
159
+ super('strict-rfc1459', "\x41-\x5a\x7b-\x7d", "\x61-\x7a\x5b-\x5d")
145
160
  end
146
161
 
147
162
  end
@@ -258,7 +273,13 @@ class String
258
273
  # This method returns the Irc::Casemap whose name is the receiver
259
274
  #
260
275
  def to_irc_casemap
261
- Irc::Casemap.get(self) rescue raise TypeError, "Unkown Irc::Casemap #{self.inspect}"
276
+ begin
277
+ Irc::Casemap.get(self)
278
+ rescue
279
+ # raise TypeError, "Unkown Irc::Casemap #{self.inspect}"
280
+ error "Unkown Irc::Casemap #{self.inspect} requested, defaulting to rfc1459"
281
+ Irc::Casemap.get('rfc1459')
282
+ end
262
283
  end
263
284
 
264
285
  # This method returns a string which is the downcased version of the
@@ -542,7 +563,7 @@ class Regexp
542
563
  GEN_HOST = /#{HOSTNAME}|#{HOSTADDR}/
543
564
 
544
565
  # # FreeNode network replaces the host of affiliated users with
545
- # # 'virtual hosts'
566
+ # # 'virtual hosts'
546
567
  # # FIXME we need the true syntax to match it properly ...
547
568
  # PDPC_HOST_PART = /[0-9A-Za-z.-]+/
548
569
  # PDPC_HOST = /#{PDPC_HOST_PART}(?:\/#{PDPC_HOST_PART})+/
@@ -550,7 +571,7 @@ class Regexp
550
571
  # # NOTE: the final optional and non-greedy dot is needed because some
551
572
  # # servers (e.g. FreeNode) send the hostname of the services as "services."
552
573
  # # which is not RFC compliant, but sadly done.
553
- # GEN_HOST_EXT = /#{PDPC_HOST}|#{GEN_HOST}\.??/
574
+ # GEN_HOST_EXT = /#{PDPC_HOST}|#{GEN_HOST}\.??/
554
575
 
555
576
  # Sadly, different networks have different, RFC-breaking ways of cloaking
556
577
  # the actualy host address: see above for an example to handle FreeNode.
@@ -1308,6 +1329,13 @@ module Irc
1308
1329
  #
1309
1330
  class Channel
1310
1331
 
1332
+ # Return the non-prefixed part of a channel name.
1333
+ # Also works with ## channels found on some networks
1334
+ # (e.g. FreeNode)
1335
+ def self.npname(str)
1336
+ return str.to_s.sub(/^[&#+!]+/,'')
1337
+ end
1338
+
1311
1339
  include ServerOrCasemap
1312
1340
  attr_reader :name, :topic, :mode, :users
1313
1341
  alias :to_s :name
@@ -1350,7 +1378,7 @@ module Irc
1350
1378
  # Adds a user to the channel
1351
1379
  #
1352
1380
  def add_user(user, opts={})
1353
- silent = opts.fetch(:silent, false)
1381
+ silent = opts.fetch(:silent, false)
1354
1382
  if has_user?(user)
1355
1383
  warn "Trying to add user #{user} to channel #{self} again" unless silent
1356
1384
  else
@@ -1366,7 +1394,7 @@ module Irc
1366
1394
  #
1367
1395
  def initialize(name, topic=nil, users=[], opts={})
1368
1396
  raise ArgumentError, "Channel name cannot be empty" if name.to_s.empty?
1369
- warn "Unknown channel prefix #{name[0].chr}" if name !~ /^[&#+!]/
1397
+ warn "Unknown channel prefix #{name[0,1]}" if name !~ /^[&#+!]/
1370
1398
  raise ArgumentError, "Invalid character in #{name.inspect}" if name =~ /[ \x07,]/
1371
1399
 
1372
1400
  init_server_or_casemap(opts)
@@ -1403,31 +1431,31 @@ module Irc
1403
1431
  # The channel prefix
1404
1432
  #
1405
1433
  def prefix
1406
- name[0].chr
1434
+ name[0,1]
1407
1435
  end
1408
1436
 
1409
1437
  # A channel is local to a server if it has the '&' prefix
1410
1438
  #
1411
1439
  def local?
1412
- name[0] == 0x26
1440
+ name[0,1] == '&'
1413
1441
  end
1414
1442
 
1415
1443
  # A channel is modeless if it has the '+' prefix
1416
1444
  #
1417
1445
  def modeless?
1418
- name[0] == 0x2b
1446
+ name[0,1] == '+'
1419
1447
  end
1420
1448
 
1421
1449
  # A channel is safe if it has the '!' prefix
1422
1450
  #
1423
1451
  def safe?
1424
- name[0] == 0x21
1452
+ name[0,1] == '!'
1425
1453
  end
1426
1454
 
1427
1455
  # A channel is normal if it has the '#' prefix
1428
1456
  #
1429
1457
  def normal?
1430
- name[0] == 0x23
1458
+ name[0,1] == '#'
1431
1459
  end
1432
1460
 
1433
1461
  # Create a new mode
@@ -1646,7 +1674,7 @@ module Irc
1646
1674
  def parse_isupport(line)
1647
1675
  debug "Parsing ISUPPORT #{line.inspect}"
1648
1676
  ar = line.split(' ')
1649
- reparse = ""
1677
+ reparse = []
1650
1678
  ar.each { |en|
1651
1679
  prekey, val = en.split('=', 2)
1652
1680
  if prekey =~ /^-(.*)/
@@ -1658,7 +1686,15 @@ module Irc
1658
1686
  case key
1659
1687
  when :casemapping
1660
1688
  noval_warn(key, val) {
1661
- @supports[key] = val.to_irc_casemap
1689
+ if val == 'charset'
1690
+ reparse << "CASEMAPPING=(charset)"
1691
+ else
1692
+ # TODO some servers offer non-standard CASEMAPPINGs in the form
1693
+ # locale.charset[-options], which indicate an extended set of
1694
+ # allowed characters (mostly for nicks). This might be supported
1695
+ # with hooks for the unicode core module
1696
+ @supports[key] = val.to_irc_casemap
1697
+ end
1662
1698
  }
1663
1699
  when :chanlimit, :idchan, :maxlist, :targmax
1664
1700
  noval_warn(key, val) {
@@ -1696,7 +1732,7 @@ module Irc
1696
1732
  @supports[key] = val
1697
1733
  when :maxchannels
1698
1734
  noval_warn(key, val) {
1699
- reparse += "CHANLIMIT=(chantypes):#{val} "
1735
+ reparse << "CHANLIMIT=(chantypes):#{val} "
1700
1736
  }
1701
1737
  when :maxtargets
1702
1738
  noval_warn(key, val) {
@@ -1737,8 +1773,12 @@ module Irc
1737
1773
  @supports[key] = val.nil? ? true : val
1738
1774
  end
1739
1775
  }
1740
- reparse.gsub!("(chantypes)",@supports[:chantypes])
1741
- parse_isupport(reparse) unless reparse.empty?
1776
+ unless reparse.empty?
1777
+ reparse_str = reparse.join(" ")
1778
+ reparse_str.gsub!("(chantypes)",@supports[:chantypes])
1779
+ reparse_str.gsub!("(charset)",@supports[:charset] || 'rfc1459')
1780
+ parse_isupport(reparse_str)
1781
+ end
1742
1782
  end
1743
1783
 
1744
1784
  # Returns the casemap of the server.
@@ -1803,7 +1843,7 @@ module Irc
1803
1843
  return ex
1804
1844
  else
1805
1845
 
1806
- prefix = name[0].chr
1846
+ prefix = name[0,1]
1807
1847
 
1808
1848
  # Give a warning if the new Channel goes over some server limits.
1809
1849
  #