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
@@ -10,6 +10,9 @@
10
10
  # encoding. The plugin takes care of translation to/from utf-8 on server IO,
11
11
  # if necessary (translation charsets are configurable).
12
12
 
13
+ # TODO autoconfigure using server-provided allowed charset when these are
14
+ # available, see also comment in irc.rb
15
+
13
16
  require 'iconv'
14
17
 
15
18
  class UnicodePlugin < CoreBotModule
@@ -21,6 +24,7 @@ class UnicodePlugin < CoreBotModule
21
24
  Config.register Config::ArrayValue.new(
22
25
  'encoding.charsets', :default => ['utf-8', 'cp1252', 'iso-8859-15'],
23
26
  :desc => "Ordered list of iconv(3) charsets the bot should try",
27
+ :validate_item => Proc.new { |x| !!(Iconv.new('utf-8', x) rescue nil) },
24
28
  :on_change => Proc.new { |bot, v| reconfigure_filter(bot) })
25
29
 
26
30
  class UnicodeFilter
@@ -25,7 +25,7 @@ module ::Irc
25
25
  #
26
26
  # If you have to do large-scale editing of the Bot data Hash,
27
27
  # please use with_botdata.
28
- #
28
+ #
29
29
  def set_botdata(key, value=nil, &block)
30
30
  Irc::Utils.bot.plugins['userdata'].set_data(self, key, value, &block)
31
31
  end
@@ -38,6 +38,13 @@ module ::Irc
38
38
  Irc::Utils.bot.plugins['userdata'].with_data(self, &block)
39
39
  end
40
40
 
41
+ # This method removes the data associated with the key, returning
42
+ # the value of the deleted key.
43
+
44
+ def delete_botdata(*keys)
45
+ Irc::Utils.bot.plugins['userdata'].delete_data(self, *keys)
46
+ end
47
+
41
48
  end
42
49
  end
43
50
 
@@ -138,6 +145,14 @@ class UserDataModule < CoreBotModule
138
145
  return h
139
146
  end
140
147
 
148
+ def delete_data(user, *keys)
149
+ h = get_data_hash(user)
150
+ debug h
151
+ rv = keys.map { |k| h.delete k }
152
+ set_data_hash(user, h)
153
+ rv.size == 1 ? rv.first : rv
154
+ end
155
+
141
156
  def handle_get(m, params)
142
157
  user = m.server.get_user(params[:nick]) || m.source
143
158
  key = params[:key].intern
@@ -124,7 +124,50 @@ class ::Array
124
124
  replace shuffle
125
125
  end
126
126
  end
127
+ end
128
+
129
+ module ::Enumerable
130
+ # This method is an advanced version of #join
131
+ # allowing fine control of separators:
132
+ #
133
+ # [1,2,3].conjoin(', ', ' and ')
134
+ # => "1, 2 and 3
135
+ #
136
+ # [1,2,3,4].conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' }
137
+ # => "1.2-3.4"
138
+ #
139
+ # Code lifted from the ruby facets project:
140
+ # <http://facets.rubyforge.org>
141
+ # git-rev: c8b7395255b977d3c7de268ff563e3c5bc7f1441
142
+ # file: lib/core/facets/array/conjoin.rb
143
+ def conjoin(*args, &block)
144
+ num = count - 1
145
+
146
+ return first.to_s if num < 1
147
+
148
+ sep = []
149
+
150
+ if block_given?
151
+ num.times do |i|
152
+ sep << yield(i, *slice(i, 2))
153
+ end
154
+ else
155
+ options = (Hash === args.last) ? args.pop : {}
156
+ separator = args.shift || ""
157
+ options[-1] = args.shift unless args.empty?
158
+
159
+ sep = [separator] * num
160
+
161
+ if options.key?(:last)
162
+ options[-1] = options.delete(:last)
163
+ end
164
+ options[-1] ||= _(" and ")
127
165
 
166
+ options.each{ |i, s| sep[i] = s }
167
+ end
168
+
169
+ zip(sep).join
170
+ end
128
171
  end
129
172
 
130
173
  # Extensions to the Range class
@@ -202,6 +245,29 @@ class ::String
202
245
  warning "unknown :a_href option #{val} passed to ircify_html" if val
203
246
  end
204
247
 
248
+ # If opts[:img] is defined, it should be a String. Each image
249
+ # will be replaced by the string itself, replacing occurrences of
250
+ # %{alt} %{dimensions} and %{src} with the alt text, image dimensions
251
+ # and URL
252
+ if val = opts[:img]
253
+ if val.kind_of? String
254
+ txt.gsub!(/<img\s+(.*?)\s*\/?>/) do |imgtag|
255
+ attrs = Hash.new
256
+ imgtag.scan(/([[:alpha:]]+)\s*=\s*(['"])?(.*?)\2/) do |key, quote, value|
257
+ k = key.downcase.intern rescue 'junk'
258
+ attrs[k] = value
259
+ end
260
+ attrs[:alt] ||= attrs[:title]
261
+ attrs[:width] ||= '...'
262
+ attrs[:height] ||= '...'
263
+ attrs[:dimensions] ||= "#{attrs[:width]}x#{attrs[:height]}"
264
+ val % attrs
265
+ end
266
+ else
267
+ warning ":img option is not a string"
268
+ end
269
+ end
270
+
205
271
  # Paragraph and br tags are converted to whitespace
206
272
  txt.gsub!(/<\/?(p|br)(?:\s+[^>]*)?\s*\/?\s*>/i, ' ')
207
273
  txt.gsub!("\n", ' ')
@@ -283,6 +349,16 @@ class ::String
283
349
  def ircify_html_title
284
350
  self.get_html_title.ircify_html rescue nil
285
351
  end
352
+
353
+ # This method is used to wrap a nonempty String by adding
354
+ # the prefix and postfix
355
+ def wrap_nonempty(pre, post, opts={})
356
+ if self.empty?
357
+ String.new
358
+ else
359
+ "#{pre}#{self}#{post}"
360
+ end
361
+ end
286
362
  end
287
363
 
288
364
 
@@ -148,6 +148,53 @@ module ::Irc
148
148
 
149
149
  register_filter(:identity) { |stream| stream }
150
150
  end
151
+
152
+ module Plugins
153
+ class BotModule
154
+ # read accessor for the default filter group for this BotModule
155
+ def filter_group
156
+ @filter_group ||= name
157
+ end
158
+
159
+ # write accessor for the default filter group for this BotModule
160
+ def filter_group=(name)
161
+ @filter_group = name
162
+ end
163
+
164
+ # define a filter defaulting to the default filter group
165
+ # for this BotModule
166
+ def define_filter(filter, &block)
167
+ @bot.register_filter(filter, self.filter_group, &block)
168
+ end
169
+
170
+ # load filters associated with the BotModule by looking in
171
+ # the path(s) specified by the :path option, defaulting to
172
+ # * Config::datadir/filters/<name>.rb
173
+ # * botclass/filters/<name>.rb
174
+ # (note that as <name> we use #dirname() rather than #name(),
175
+ # since we're looking for datafiles; this is only relevant
176
+ # for the very few plugins whose dirname differs from name)
177
+ def load_filters(options={})
178
+ case options[:path]
179
+ when nil
180
+ file = "#{self.dirname}.rb"
181
+ paths = [
182
+ File.join(Config::datadir, 'filters', file),
183
+ @bot.path('filters', file)
184
+ ]
185
+ when Array
186
+ paths = options[:path]
187
+ else
188
+ paths = [options[:path]]
189
+ end
190
+
191
+ paths.each do |file|
192
+ instance_eval(File.read(file), file) if File.exist?(file)
193
+ end
194
+ end
195
+ end
196
+ end
197
+
151
198
  end
152
199
  end
153
200
 
@@ -25,7 +25,7 @@ require 'zlib'
25
25
  module ::Net
26
26
  class HTTPResponse
27
27
  attr_accessor :no_cache
28
- if !instance_methods.include?('raw_body')
28
+ unless method_defined? :raw_body
29
29
  alias :raw_body :body
30
30
  end
31
31
 
@@ -99,7 +99,7 @@ module ::Net
99
99
  end
100
100
  when 'deflate'
101
101
  debug "inflating body"
102
- # From http://www.koders.com/ruby/fid927B4382397E5115AC0ABE21181AB5C1CBDD5C17.aspx?s=thread:
102
+ # From http://www.koders.com/ruby/fid927B4382397E5115AC0ABE21181AB5C1CBDD5C17.aspx?s=thread:
103
103
  # -MAX_WBITS stops zlib from looking for a zlib header
104
104
  inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
105
105
  begin
@@ -190,7 +190,7 @@ class HttpUtil
190
190
  Bot::Config.register Bot::Config::IntegerValue.new('http.max_cache_time',
191
191
  :default => 60*24,
192
192
  :desc => "After how many minutes since first use a cached document is considered to be expired")
193
- Bot::Config.register Bot::Config::IntegerValue.new('http.no_expire_cache',
193
+ Bot::Config.register Bot::Config::BooleanValue.new('http.no_expire_cache',
194
194
  :default => false,
195
195
  :desc => "Set this to true if you want the bot to never expire the cached pages")
196
196
  Bot::Config.register Bot::Config::IntegerValue.new('http.info_bytes',
@@ -389,7 +389,7 @@ class HttpUtil
389
389
  end
390
390
  end
391
391
 
392
- h = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port, proxy_user, proxy_port)
392
+ h = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port, proxy_user, proxy_pass)
393
393
  h.use_ssl = true if uri.scheme == "https"
394
394
 
395
395
  h.read_timeout = opts[:read_timeout]
@@ -482,6 +482,14 @@ class HttpUtil
482
482
  #
483
483
  def get_response(uri_or_s, options = {}, &block) # :yields: resp
484
484
  uri = uri_or_s.kind_of?(URI) ? uri_or_s : URI.parse(uri_or_s.to_s)
485
+ unless URI::HTTP === uri
486
+ if uri.scheme
487
+ raise "#{uri.scheme.inspect} URI scheme is not supported"
488
+ else
489
+ raise "don't know what to do with #{uri.to_s.inspect}"
490
+ end
491
+ end
492
+
485
493
  opts = {
486
494
  :max_redir => @bot.config['http.max_redir'],
487
495
  :yield => :final,
@@ -490,7 +498,6 @@ class HttpUtil
490
498
  }.merge(options)
491
499
 
492
500
  resp = nil
493
- cached = nil
494
501
 
495
502
  req_class = case opts[:method].to_s.downcase.intern
496
503
  when :head, :"net::http::head"
@@ -524,7 +531,9 @@ class HttpUtil
524
531
 
525
532
  debug "get_response(#{uri}, #{opts.inspect})"
526
533
 
527
- if opts[:cache] && cached = @cache[cache_key]
534
+ cached = @cache[cache_key]
535
+
536
+ if opts[:cache] && cached
528
537
  debug "got cached"
529
538
  if !cached.expired?
530
539
  debug "using cached"
@@ -537,7 +546,10 @@ class HttpUtil
537
546
  headers['Range'] = opts[:range] if opts[:range]
538
547
  headers['Authorization'] = opts[:auth_head] if opts[:auth_head]
539
548
 
540
- cached.setup_headers(headers) if cached && (req_class == Net::HTTP::Get)
549
+ if opts[:cache] && cached && (req_class == Net::HTTP::Get)
550
+ cached.setup_headers headers
551
+ end
552
+
541
553
  req = req_class.new(uri.request_uri, headers)
542
554
  if uri.user && uri.password
543
555
  req.basic_auth(uri.user, uri.password)
@@ -547,22 +559,23 @@ class HttpUtil
547
559
  debug "prepared request: #{req.to_hash.inspect}"
548
560
 
549
561
  begin
550
- get_proxy(uri, opts).start do |http|
551
- http.request(req) do |resp|
552
- resp['x-rbot-location'] = uri.to_s
553
- if Net::HTTPNotModified === resp
554
- debug "not modified"
555
- begin
556
- cached.revalidate(resp)
557
- rescue Exception => e
558
- error e
562
+ get_proxy(uri, opts).start do |http|
563
+ http.request(req) do |resp|
564
+ resp['x-rbot-location'] = uri.to_s
565
+ if Net::HTTPNotModified === resp
566
+ debug "not modified"
567
+ begin
568
+ cached.revalidate(resp)
569
+ rescue Exception => e
570
+ error e
571
+ end
572
+ debug "reusing cached"
573
+ resp = cached.response
574
+ elsif Net::HTTPServerError === resp || Net::HTTPClientError === resp
575
+ debug "http error, deleting cached obj" if cached
576
+ @cache.delete(cache_key)
559
577
  end
560
- debug "reusing cached"
561
- resp = cached.response
562
- elsif Net::HTTPServerError === resp || Net::HTTPClientError === resp
563
- debug "http error, deleting cached obj" if cached
564
- @cache.delete(cache_key)
565
- elsif opts[:cache]
578
+
566
579
  begin
567
580
  return handle_response(uri, resp, opts, &block)
568
581
  ensure
@@ -571,11 +584,8 @@ class HttpUtil
571
584
  @cache[cache_key] = cached
572
585
  end
573
586
  end
574
- return ret
575
587
  end
576
- return handle_response(uri, resp, opts, &block)
577
588
  end
578
- end
579
589
  rescue Exception => e
580
590
  error e
581
591
  raise e.message
@@ -630,7 +640,7 @@ class HttpUtil
630
640
  opts = {:method => :post, :body => data, :cache => false}.merge(options)
631
641
  begin
632
642
  resp = get_response(uri, opts, &block)
633
- raise 'http error' unless Net::HTTPOK === resp
643
+ raise 'http error' unless Net::HTTPOK === resp or Net::HTTPCreated === resp
634
644
  return resp
635
645
  rescue Exception => e
636
646
  error e
@@ -0,0 +1,193 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: rbot time parsing utilities
5
+ #
6
+ # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7
+ #
8
+ # These routines read a string and return the number of seconds they
9
+ # represent.
10
+
11
+ module ::Irc
12
+ module Utils
13
+ module ParseTime
14
+ FLOAT_RX = /((?:\d*\.)?\d+)/
15
+
16
+ ONE_TO_NINE = {
17
+ :one => 1,
18
+ :two => 2,
19
+ :three => 3,
20
+ :four => 4,
21
+ :five => 5,
22
+ :six => 6,
23
+ :seven => 7,
24
+ :eight => 8,
25
+ :nine => 9,
26
+ }
27
+
28
+ ONE_TO_NINE_RX = Regexp.new ONE_TO_NINE.keys.join('|')
29
+
30
+ TEENS_ETC = {
31
+ :an => 1,
32
+ :a => 1,
33
+ :ten => 10,
34
+ :eleven => 11,
35
+ :twelve => 12,
36
+ :thirteen => 13,
37
+ :fourteen => 14,
38
+ :fifteen => 15,
39
+ :sixteen => 16,
40
+ :seventeen => 17,
41
+ :eighteen => 18,
42
+ :nineteen => 19,
43
+ }
44
+
45
+ TEENS_ETC_RX = Regexp.new TEENS_ETC.keys.join('|')
46
+
47
+ ENTIES = {
48
+ :twenty => 20,
49
+ :thirty => 30,
50
+ :forty => 40,
51
+ :fifty => 50,
52
+ :sixty => 60,
53
+ }
54
+
55
+ ENTIES_RX = Regexp.new ENTIES.keys.join('|')
56
+
57
+ LITNUM_RX = /(#{ONE_TO_NINE_RX})|(#{TEENS_ETC_RX})|(#{ENTIES_RX})\s*(#{ONE_TO_NINE_RX})?/
58
+
59
+ FRACTIONS = {
60
+ :"half" => 0.5,
61
+ :"half a" => 0.5,
62
+ :"half an" => 0.5,
63
+ :"a half" => 0.5,
64
+ :"a quarter" => 0.25,
65
+ :"a quarter of" => 0.25,
66
+ :"a quarter of a" => 0.25,
67
+ :"a quarter of an" => 0.25,
68
+ :"three quarter" => 0.75,
69
+ :"three quarters" => 0.75,
70
+ :"three quarter of" => 0.75,
71
+ :"three quarters of" => 0.75,
72
+ :"three quarter of a" => 0.75,
73
+ :"three quarters of a" => 0.75,
74
+ :"three quarter of an" => 0.75,
75
+ :"three quarters of an" => 0.75,
76
+ }
77
+
78
+ FRACTION_RX = Regexp.new FRACTIONS.keys.join('|')
79
+
80
+ UNITSPEC_RX = /(years?|months?|s(?:ec(?:ond)?s?)?|m(?:in(?:ute)?s?)?|h(?:(?:ou)?rs?)?|d(?:ays?)?|weeks?)/
81
+
82
+ # str must much UNITSPEC_RX
83
+ def ParseTime.time_unit(str)
84
+ case str[0,1].intern
85
+ when :s
86
+ 1
87
+ when :m
88
+ if str[1,1] == 'o'
89
+ # months
90
+ 3600*24*30
91
+ else
92
+ #minutes
93
+ 60
94
+ end
95
+ when :h
96
+ 3600
97
+ when :d
98
+ 3600*24
99
+ when :w
100
+ 3600*24*7
101
+ when :y
102
+ 3600*24*365
103
+ end
104
+ end
105
+
106
+ # example: half an hour, two and a half weeks, 5 seconds, an hour and 5 minutes
107
+ def ParseTime.parse_period(str)
108
+ clean = str.gsub(/\s+/, ' ').strip
109
+
110
+ sofar = 0
111
+ until clean.empty?
112
+ if clean.sub!(/^(#{FRACTION_RX})\s+#{UNITSPEC_RX}/, '')
113
+ # fraction followed by unit
114
+ num = FRACTIONS[$1.intern]
115
+ unit = ParseTime.time_unit($2)
116
+ elsif clean.sub!(/^#{FLOAT_RX}\s*(?:\s+and\s+(#{FRACTION_RX})\s+)?#{UNITSPEC_RX}/, '')
117
+ # float plus optional fraction followed by unit
118
+ num = $1.to_f
119
+ frac = $2
120
+ unit = ParseTime.time_unit($3)
121
+ clean.strip!
122
+ if frac.nil? and clean.sub!(/^and\s+(#{FRACTION_RX})/, '')
123
+ frac = $1
124
+ end
125
+ if frac
126
+ num += FRACTIONS[frac.intern]
127
+ end
128
+ elsif clean.sub!(/^(?:#{LITNUM_RX})\s+(?:and\s+(#{FRACTION_RX})\s+)?#{UNITSPEC_RX}/, '')
129
+ if $1
130
+ num = ONE_TO_NINE[$1.intern]
131
+ elsif $2
132
+ num = TEENS_ETC[$2.intern]
133
+ elsif $3
134
+ num = ENTIES[$3.intern]
135
+ if $4
136
+ num += ONE_TO_NINE[$4.intern]
137
+ end
138
+ end
139
+ frac = $5
140
+ unit = ParseTime.time_unit($6)
141
+ clean.strip!
142
+ if frac.nil? and clean.sub!(/^and\s+(#{FRACTION_RX})/, '')
143
+ frac = $1
144
+ end
145
+ if frac
146
+ num += FRACTIONS[frac.intern]
147
+ end
148
+ else
149
+ raise "invalid time string: #{clean} (parsed #{sofar} so far)"
150
+ end
151
+ sofar += num * unit
152
+ clean.sub!(/^and\s+/, '')
153
+ end
154
+ return sofar
155
+ end
156
+
157
+ # TODO 'at hh:mm:ss', 'next week, 'tomorrow', 'saturday' etc
158
+ end
159
+
160
+ def Utils.parse_time_offset(str)
161
+ case str
162
+ when /^(\d+):(\d+)(?:\:(\d+))?$/ # TODO refactor
163
+ hour = $1.to_i
164
+ min = $2.to_i
165
+ sec = $3.to_i
166
+ now = Time.now
167
+ later = Time.mktime(now.year, now.month, now.day, hour, min, sec)
168
+
169
+ # if the given hour is earlier than current hour, given timestr
170
+ # must have been meant to be in the future
171
+ if hour < now.hour || hour <= now.hour && min < now.min
172
+ later += 60*60*24
173
+ end
174
+
175
+ return later - now
176
+ when /^(\d+):(\d+)(am|pm)$/ # TODO refactor
177
+ hour = $1.to_i
178
+ min = $2.to_i
179
+ ampm = $3
180
+ if ampm == "pm"
181
+ hour += 12
182
+ end
183
+ now = Time.now
184
+ later = Time.mktime(now.year, now.month, now.day, hour, min, now.sec)
185
+ return later - now
186
+ else
187
+ ParseTime.parse_period(str)
188
+ end
189
+ end
190
+
191
+ end
192
+ end
193
+