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
@@ -186,7 +186,7 @@ module Config
186
186
  unless newval.include? val
187
187
  newval << val
188
188
  validate_item(val) or raise ArgumentError, "invalid item: #{val}"
189
- validate(newval) or raise ArgumentError, "invalid value: #{newval.to_s}"
189
+ validate(newval) or raise ArgumentError, "invalid value: #{newval.inspect}"
190
190
  set(newval)
191
191
  end
192
192
  end
@@ -262,9 +262,10 @@ module Config
262
262
  return unless @bot
263
263
 
264
264
  @changed = false
265
- if(File.exist?("#{@bot.botclass}/conf.yaml"))
265
+ conf = @bot.path 'conf.yaml'
266
+ if File.exist? conf
266
267
  begin
267
- newconfig = YAML::load_file("#{@bot.botclass}/conf.yaml")
268
+ newconfig = YAML::load_file conf
268
269
  newconfig.each { |key, val|
269
270
  @config[key.to_sym] = val
270
271
  }
@@ -327,8 +328,10 @@ module Config
327
328
  return
328
329
  end
329
330
  begin
331
+ conf = @bot.path 'conf.yaml'
332
+ fnew = conf + '.new'
330
333
  debug "Writing new conf.yaml ..."
331
- File.open("#{@bot.botclass}/conf.yaml.new", "w") do |file|
334
+ File.open(fnew, "w") do |file|
332
335
  savehash = {}
333
336
  @config.each { |key, val|
334
337
  savehash[key.to_s] = val
@@ -336,8 +339,7 @@ module Config
336
339
  file.puts savehash.to_yaml
337
340
  end
338
341
  debug "Officializing conf.yaml ..."
339
- File.rename("#{@bot.botclass}/conf.yaml.new",
340
- "#{@bot.botclass}/conf.yaml")
342
+ File.rename(fnew, conf)
341
343
  @changed = false
342
344
  rescue => e
343
345
  error "failed to write configuration file conf.yaml! #{$!}"
@@ -160,7 +160,7 @@ class AuthModule < CoreBotModule
160
160
  def auth_view_perm(m, params)
161
161
  begin
162
162
  if params[:user].nil?
163
- user = get_botusername_for(m.source)
163
+ user = get_botuser_for(m.source)
164
164
  return m.reply(_("you are owner, you can do anything")) if user.owner?
165
165
  else
166
166
  user = @bot.auth.get_botuser(params[:user].sub(/^all$/,"everyone"))
@@ -242,23 +242,27 @@ class AuthModule < CoreBotModule
242
242
  where = m.parse_channel_list(p[:where].to_s).first # should only be one anyway
243
243
  end
244
244
 
245
- # pseudo-message to find the template. The source is ignored, and the
246
- # target is set according to where the template should be checked
247
- # (public or private)
248
- # This might still fail in the case of 'everywhere' for commands there are
249
- # really only private
250
- case where
251
- when :"?"
252
- pseudo_target = @bot.myself
253
- when :*
254
- pseudo_target = m.channel
245
+ if p.has_key? :auth_path
246
+ auth_path = p[:auth_path]
255
247
  else
256
- pseudo_target = m.server.channel(where)
257
- end
248
+ # pseudo-message to find the template. The source is ignored, and the
249
+ # target is set according to where the template should be checked
250
+ # (public or private)
251
+ # This might still fail in the case of 'everywhere' for commands there are
252
+ # really only private
253
+ case where
254
+ when :"?"
255
+ pseudo_target = @bot.myself
256
+ when :*
257
+ pseudo_target = m.channel
258
+ else
259
+ pseudo_target = m.server.channel(where)
260
+ end
258
261
 
259
- pseudo = PrivMessage.new(bot, m.server, m.source, pseudo_target, p[:stuff].to_s)
262
+ pseudo = PrivMessage.new(bot, m.server, m.source, pseudo_target, p[:stuff].to_s)
260
263
 
261
- auth_path = find_auth(pseudo)
264
+ auth_path = find_auth(pseudo)
265
+ end
262
266
  debug auth_path
263
267
 
264
268
  if auth_path
@@ -407,9 +411,21 @@ class AuthModule < CoreBotModule
407
411
  when "hello"
408
412
  return _("hello: creates a bot user for the person issuing the command")
409
413
  when "allow"
410
- return _("allow <user> to do <sample command> [<where>]: gives botuser <user> the permissions to execute a command such as the provided sample command (in private or in channel, according to the optional <where>)")
414
+ return [
415
+ _("allow <user> to do <sample command> [<where>]: gives botuser <user> the permissions to execute a command such as the provided sample command"),
416
+ _("(in private or in channel, according to the optional <where>)."),
417
+ _("<sample command> should be a full command, not just the command keyword --"),
418
+ _("correct: allow user to do addquote stuff --"),
419
+ _("wrong: allow user to do addquote.")
420
+ ].join(" ")
411
421
  when "deny"
412
- return _("deny <user> from doing <sample command> [<where>]: removes from botuser <user> the permissions to execute a command such as the provided sample command (in private or in channel, according to the optional <where>)")
422
+ return [
423
+ _("deny <user> from doing <sample command> [<where>]: removes from botuser <user> the permissions to execute a command such as the provided sample command"),
424
+ _("(in private or in channel, according to the optional <where>)."),
425
+ _("<sample command> should be a full command, not just the command keyword --"),
426
+ _("correct: deny user from doing addquote stuff --"),
427
+ _("wrong: deny user from doing addquote.")
428
+ ].join(" ")
413
429
  else
414
430
  return _("auth commands: auth, login, whoami, who, permission[s], user, meet, hello, allow, deny")
415
431
  end
@@ -801,13 +817,13 @@ class AuthModule < CoreBotModule
801
817
 
802
818
  def auth_export(m, params)
803
819
 
804
- exportfile = "#{@bot.botclass}/new-auth.users"
820
+ exportfile = @bot.path "new-auth.users"
805
821
 
806
822
  what = params[:things]
807
823
 
808
824
  has_to = what[-2] == "to"
809
825
  if has_to
810
- exportfile = "#{@bot.botclass}/#{what[-1]}"
826
+ exportfile = @bot.path what[-1]
811
827
  what.slice!(-2,2)
812
828
  end
813
829
 
@@ -873,13 +889,13 @@ class AuthModule < CoreBotModule
873
889
 
874
890
  def auth_import(m, params)
875
891
 
876
- importfile = "#{@bot.botclass}/new-auth.users"
892
+ importfile = @bot.path "new-auth.users"
877
893
 
878
894
  what = params[:things]
879
895
 
880
896
  has_from = what[-2] == "from"
881
897
  if has_from
882
- importfile = "#{@bot.botclass}/#{what[-1]}"
898
+ importfile = @bot.path what[-1]
883
899
  what.slice!(-2,2)
884
900
  end
885
901
 
@@ -30,7 +30,11 @@ class BasicsModule < CoreBotModule
30
30
  # identification. Observe that this means the bot may not connect any channels
31
31
  # until the 'identified' method gets delegated
32
32
  def connect
33
- join_channels unless @bot.config['irc.join_after_identify']
33
+ if @bot.config['irc.join_after_identify']
34
+ log "waiting for identififcation before JOINing default channels"
35
+ else
36
+ join_channels
37
+ end
34
38
  end
35
39
 
36
40
  def ctcp_listen(m)
@@ -65,6 +69,20 @@ class BasicsModule < CoreBotModule
65
69
  end
66
70
  end
67
71
 
72
+ def bot_channel_list(m, param)
73
+ ret = _('I am in: ')
74
+ # sort the channels by the base name and then map with prefixes for the
75
+ # mode and display.
76
+ ret << @bot.channels.compact.sort { |a,b|
77
+ a.name.downcase <=> b.name.downcase
78
+ }.map { |c|
79
+ c.modes_of(@bot.myself).map{ |mo|
80
+ m.server.prefix_for_mode(mo)
81
+ }.to_s + c.name
82
+ }.join(', ')
83
+ m.reply ret
84
+ end
85
+
68
86
  def bot_quit(m, param)
69
87
  @bot.quit param[:msg].to_s
70
88
  end
@@ -73,6 +91,10 @@ class BasicsModule < CoreBotModule
73
91
  @bot.restart param[:msg].to_s
74
92
  end
75
93
 
94
+ def bot_reconnect(m, param)
95
+ @bot.reconnect param[:msg].to_s
96
+ end
97
+
76
98
  def bot_hide(m, param)
77
99
  @bot.join 0
78
100
  end
@@ -133,6 +155,8 @@ class BasicsModule < CoreBotModule
133
155
  _("quit [<message>] => quit IRC with message <message>")
134
156
  when "restart"
135
157
  _("restart => completely stop and restart the bot (including reconnect)")
158
+ when "reconnect"
159
+ _("reconnect => ask the bot to disconnect and then connect again")
136
160
  when "join"
137
161
  _("join <channel> [<key>] => join channel <channel> with secret key <key> if specified. #{@bot.myself} also responds to invites if you have the required access level")
138
162
  when "part"
@@ -172,6 +196,10 @@ basics.map "restart *msg",
172
196
  :action => 'bot_restart',
173
197
  :defaults => { :msg => nil },
174
198
  :auth_path => 'quit'
199
+ basics.map "reconnect *msg",
200
+ :action => 'bot_reconnect',
201
+ :defaults => { :msg => nil },
202
+ :auth_path => 'quit'
175
203
 
176
204
  basics.map "quiet [in] [:where]",
177
205
  :action => 'bot_quiet',
@@ -190,7 +218,7 @@ basics.map "mode :where :what *who",
190
218
  :action => 'bot_mode',
191
219
  :auth_path => 'talk::do'
192
220
 
193
- basics.map "join :chan :pass",
221
+ basics.map "join :chan :pass",
194
222
  :action => 'bot_join',
195
223
  :defaults => {:pass => nil},
196
224
  :auth_path => 'move'
@@ -198,6 +226,9 @@ basics.map "part :chan",
198
226
  :action => 'bot_part',
199
227
  :defaults => {:chan => nil},
200
228
  :auth_path => 'move'
229
+ basics.map "channels",
230
+ :action => 'bot_channel_list',
231
+ :auth_path => 'move'
201
232
  basics.map "hide",
202
233
  :action => 'bot_hide',
203
234
  :auth_path => 'move'
@@ -122,7 +122,7 @@ class ConfigModule < CoreBotModule
122
122
 
123
123
  def handle_add(m, params)
124
124
  key = params[:key].to_s.intern
125
- value = params[:value]
125
+ values = params[:value].to_s.split(/,\s+/)
126
126
  unless @bot.config.items.has_key?(key)
127
127
  m.reply _("no such config key %{key}") % {:key => key}
128
128
  return
@@ -132,11 +132,13 @@ class ConfigModule < CoreBotModule
132
132
  return
133
133
  end
134
134
  return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
135
- begin
136
- @bot.config.items[key].add(value)
137
- rescue ArgumentError => e
138
- m.reply _("failed to add %{value} to %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
139
- return
135
+ values.each do |value|
136
+ begin
137
+ @bot.config.items[key].add(value)
138
+ rescue ArgumentError => e
139
+ m.reply _("failed to add %{value} to %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
140
+ next
141
+ end
140
142
  end
141
143
  handle_get(m,{:key => key})
142
144
  m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
@@ -145,7 +147,7 @@ class ConfigModule < CoreBotModule
145
147
 
146
148
  def handle_rm(m, params)
147
149
  key = params[:key].to_s.intern
148
- value = params[:value]
150
+ values = params[:value].to_s.split(/,\s+/)
149
151
  unless @bot.config.items.has_key?(key)
150
152
  m.reply _("no such config key %{key}") % {:key => key}
151
153
  return
@@ -155,11 +157,13 @@ class ConfigModule < CoreBotModule
155
157
  return
156
158
  end
157
159
  return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
158
- begin
159
- @bot.config.items[key].rm(value)
160
- rescue ArgumentError => e
161
- m.reply _("failed to remove %{value} from %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
162
- return
160
+ values.each do |value|
161
+ begin
162
+ @bot.config.items[key].rm(value)
163
+ rescue ArgumentError => e
164
+ m.reply _("failed to remove %{value} from %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
165
+ next
166
+ end
163
167
  end
164
168
  handle_get(m,{:key => key})
165
169
  m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
@@ -228,7 +232,7 @@ class ConfigModule < CoreBotModule
228
232
  when "desc"
229
233
  _("config desc <key> => describe what key <key> configures")
230
234
  when "add"
231
- _("config add <value> to <key> => add value <value> to key <key> if <key> is an array")
235
+ _("config add <values> to <key> => add values <values> to key <key> if <key> is an array")
232
236
  when "rm"
233
237
  _("config rm <value> from <key> => remove value <value> from key <key> if <key> is an array")
234
238
  else
@@ -296,16 +300,19 @@ conf.map "version",
296
300
  conf.map 'config set :key *value',
297
301
  :action => 'handle_set',
298
302
  :auth_path => 'edit'
299
- conf.map 'config add :value to :key',
303
+ conf.map 'config add *value to :key',
300
304
  :action => 'handle_add',
301
305
  :auth_path => 'edit'
302
- conf.map 'config rm :value from :key',
306
+ conf.map 'config rm *value from :key',
307
+ :action => 'handle_rm',
308
+ :auth_path => 'edit'
309
+ conf.map 'config remove *value from :key',
303
310
  :action => 'handle_rm',
304
311
  :auth_path => 'edit'
305
- conf.map 'config del :value from :key',
312
+ conf.map 'config del *value from :key',
306
313
  :action => 'handle_rm',
307
314
  :auth_path => 'edit'
308
- conf.map 'config delete :value from :key',
315
+ conf.map 'config delete *value from :key',
309
316
  :action => 'handle_rm',
310
317
  :auth_path => 'edit'
311
318
  conf.map 'config unset :key',
@@ -27,7 +27,7 @@ class FiltersModule < CoreBotModule
27
27
  msg = _("no known filters")
28
28
  end
29
29
  else
30
- msg = _("known filters: ") << ar.join(", ")
30
+ msg = _("known filters: ") << ar.join(", ")
31
31
  end
32
32
  m.reply msg
33
33
  end
@@ -37,7 +37,7 @@ class FiltersModule < CoreBotModule
37
37
  if ar.empty?
38
38
  msg = _("no known filter groups")
39
39
  else
40
- msg = _("known filter groups: ") << ar.join(", ")
40
+ msg = _("known filter groups: ") << ar.join(", ")
41
41
  end
42
42
  m.reply msg
43
43
  end
@@ -23,6 +23,9 @@ class IrcLogModule < CoreBotModule
23
23
  Config.register Config::StringValue.new('irclog.filename_format',
24
24
  :default => '%%{where}', :requires_rescan => true,
25
25
  :desc => "filename pattern for the IRC log. You can put typical strftime keys such as %Y for year and %m for month, plus the special %%{where} key for location (channel name or user nick)")
26
+ Config.register Config::StringValue.new('irclog.timestamp_format',
27
+ :default => '[%Y/%m/%d %H:%M:%S]', :requires_rescan => true,
28
+ :desc => "timestamp pattern for the IRC log, using typical strftime keys")
26
29
 
27
30
  attr :nolog_rx, :dolog_rx
28
31
  def initialize
@@ -30,7 +33,9 @@ class IrcLogModule < CoreBotModule
30
33
  @queue = Queue.new
31
34
  @thread = Thread.new { loggers_thread }
32
35
  @logs = Hash.new
33
- Dir.mkdir("#{@bot.botclass}/logs") unless File.exist?("#{@bot.botclass}/logs")
36
+ logdir = @bot.path 'logs'
37
+ Dir.mkdir(logdir) unless File.exist?(logdir)
38
+ # TODO what shall we do if the logdir couldn't be created? (e.g. it existed as a file)
34
39
  event_irclog_list_changed(@bot.config['irclog.no_log'], @bot.config['irclog.do_log'])
35
40
  @fn_format = @bot.config['irclog.filename_format']
36
41
  end
@@ -41,6 +46,10 @@ class IrcLogModule < CoreBotModule
41
46
  return true
42
47
  end
43
48
 
49
+ def timestamp(time)
50
+ return time.strftime(@bot.config['irclog.timestamp_format'])
51
+ end
52
+
44
53
  def event_irclog_list_changed(nolist, dolist)
45
54
  @nolog_rx = nolist.empty? ? nil : Regexp.union(*(nolist.map { |r| r.to_irc_regexp }))
46
55
  debug "no log: #{@nolog_rx}"
@@ -54,8 +63,8 @@ class IrcLogModule < CoreBotModule
54
63
 
55
64
  def logfile_close(where_str, reason = 'unknown reason')
56
65
  f = @logs.delete(where_str) or return
57
- stamp = Time.now.strftime '%Y/%m/%d %H:%M:%S'
58
- f[1].puts "[#{stamp}] @ Log closed by #{@bot.myself.nick} (#{reason})"
66
+ stamp = timestamp(Time.now)
67
+ f[1].puts "#{stamp} @ Log closed by #{@bot.myself.nick} (#{reason})"
59
68
  f[1].close
60
69
  end
61
70
 
@@ -144,7 +153,7 @@ class IrcLogModule < CoreBotModule
144
153
  irclog "@ #{m.source} asked #{who} about #{[m.ctcp, m.message].join(' ')}", logtarget
145
154
  end
146
155
  else
147
- if m.public?
156
+ if m.public?
148
157
  irclog "<#{m.source}> #{m.logmessage}", m.target
149
158
  else
150
159
  irclog "<#{m.source}(#{m.sourceaddress})> #{m.logmessage}", m.source
@@ -237,7 +246,7 @@ class IrcLogModule < CoreBotModule
237
246
  end
238
247
 
239
248
  def logfilepath(where_str, now)
240
- File.join(@bot.botclass, 'logs', now.strftime(@fn_format) % { :where => where_str })
249
+ @bot.path('logs', now.strftime(@fn_format) % { :where => where_str })
241
250
  end
242
251
 
243
252
  protected
@@ -248,13 +257,13 @@ class IrcLogModule < CoreBotModule
248
257
  message, where = ls
249
258
  message = message.chomp
250
259
  now = Time.now
251
- stamp = now.strftime("%Y/%m/%d %H:%M:%S")
260
+ stamp = timestamp(now)
252
261
  if where.class <= Server
253
262
  where_str = "server"
254
263
  else
255
264
  where_str = where.downcase.gsub(/[:!?$*()\/\\<>|"']/, "_")
256
265
  end
257
- return unless can_log_on(where_str)
266
+ next unless can_log_on(where_str)
258
267
 
259
268
  # close the previous logfile if we're rotating
260
269
  if @logs.has_key? where_str
@@ -280,7 +289,7 @@ class IrcLogModule < CoreBotModule
280
289
  # If it's a file, we rename to filename.old.filedate
281
290
  up = dir.dup
282
291
  until File.exist? up
283
- up.replace File.dirname up
292
+ up.replace(File.dirname(up))
284
293
  end
285
294
  unless File.directory? up
286
295
  backup = up.dup
@@ -300,16 +309,16 @@ class IrcLogModule < CoreBotModule
300
309
  # it should be fine to create the file now
301
310
  f = File.new(fp, "a")
302
311
  f.sync = true
303
- f.puts "[#{stamp}] @ Log started by #{@bot.myself.nick}"
312
+ f.puts "#{stamp} @ Log started by #{@bot.myself.nick}"
304
313
  rescue Exception => e
305
314
  error e
306
315
  next
307
316
  end
308
317
  @logs[where_str] = [now, f]
309
318
  end
310
- @logs[where_str][1].puts "[#{stamp}] #{message}"
319
+ @logs[where_str][1].puts "#{stamp} #{message}"
311
320
  @logs[where_str][0] = now
312
- #debug "[#{stamp}] <#{where}> #{message}"
321
+ #debug "#{stamp} <#{where}> #{message}"
313
322
  end
314
323
  @logs.keys.each { |w| logfile_close(w, 'rescan or shutdown') }
315
324
  debug 'loggers_thread terminating'
@@ -136,7 +136,7 @@ class Bot
136
136
  raise "Botmodule #{botmodule.name} tried to unmap #{tmpl.inspect} that was handled by #{tmpl.botmodule}" unless tmpl.botmodule == botmodule.name
137
137
  debug "Unmapping #{tmpl.inspect}"
138
138
  @templates[handle] = nil
139
- @templates.clear unless @templates.nitems > 0
139
+ @templates.clear unless @templates.compact.size > 0
140
140
  end
141
141
 
142
142
  # We redefine the handle() method from MessageMapper, taking into account
@@ -147,7 +147,7 @@ class Bot
147
147
  #
148
148
  # Presently, the hash returned on success has only one key, :return, whose
149
149
  # value is the actual return value of the successfull dispatch.
150
- #
150
+ #
151
151
  # TODO this same kind of mechanism could actually be used in MessageMapper
152
152
  # itself to be able to handle the case of multiple plugins having the same
153
153
  # 'first word' ...
@@ -160,19 +160,19 @@ class Bot
160
160
  # Skip this element if it was unmapped
161
161
  next unless tmpl
162
162
  botmodule = @parent.plugins[tmpl.botmodule]
163
- options, failure = tmpl.recognize(m)
164
- if options.nil?
165
- failures << [tmpl, failure]
163
+ options = tmpl.recognize(m)
164
+ if options.kind_of? Failure
165
+ failures << options
166
166
  else
167
167
  action = tmpl.options[:action]
168
168
  unless botmodule.respond_to?(action)
169
- failures << [tmpl, "#{botmodule} does not respond to action #{action}"]
169
+ failures << NoActionFailure.new(tmpl, m)
170
170
  next
171
171
  end
172
172
  auth = tmpl.options[:full_auth_path]
173
173
  debug "checking auth for #{auth}"
174
174
  # We check for private permission
175
- if m.bot.auth.allow?(auth, m.source, '?')
175
+ if m.bot.auth.permit?(m.source, auth, '?')
176
176
  debug "template match found and auth'd: #{action.inspect} #{options.inspect}"
177
177
  return :return => botmodule.send(action, m, options)
178
178
  end
@@ -182,8 +182,8 @@ class Bot
182
182
  return false
183
183
  end
184
184
  end
185
- failures.each {|f, r|
186
- debug "#{f.inspect} => #{r}"
185
+ failures.each {|r|
186
+ debug "#{r.template.inspect} => #{r}"
187
187
  }
188
188
  debug "no handler found"
189
189
  return false