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
@@ -50,6 +50,8 @@ class TwitterPlugin < Plugin
50
50
 
51
51
  nick = params[:nick] || @registry[m.sourcenick + "_username"]
52
52
 
53
+ friends = params[:friends]
54
+
53
55
  if not nick
54
56
  m.reply "you should specify the username of the twitter touse, or identify using 'twitter identify [username] [password]'"
55
57
  return false
@@ -58,11 +60,18 @@ class TwitterPlugin < Plugin
58
60
  user = URI.escape(nick)
59
61
 
60
62
  count = @bot.config['twitter.status_count']
61
- unless params[:friends]
63
+ unless friends
62
64
  uri = "http://twitter.com/statuses/user_timeline/#{user}.xml?count=#{count}"
63
65
  else
64
66
  count = @bot.config['twitter.friends_status_count']
65
- uri = "http://twitter.com/statuses/friends_timeline/#{user}.xml"
67
+ auth = ""
68
+ if m.private?
69
+ auth << URI.escape(@registry[m.sourcenick + "_username"])
70
+ auth << ":"
71
+ auth << URI.escape(@registry[m.sourcenick + "_password"])
72
+ auth << "@"
73
+ end
74
+ uri = "http://#{auth}twitter.com/statuses/friends_timeline/#{user}.xml"
66
75
  end
67
76
 
68
77
  response = @bot.httputil.get(uri, :headers => @header, :cache => false)
@@ -83,24 +92,34 @@ class TwitterPlugin < Plugin
83
92
  delta = ((time > now) ? time - now : now - time)
84
93
  msg = st.elements['text'].to_s + " (#{Utils.secs_to_string(delta.to_i)} ago via #{st.elements['source'].to_s})"
85
94
  author = ""
86
- if params[:friends]
95
+ if friends
87
96
  author = Utils.decode_html_entities(st.elements['user'].elements['name'].text) + ": " rescue ""
88
97
  end
89
98
  texts << author+Utils.decode_html_entities(msg).ircify_html
90
99
  }
91
- if params[:friends]
100
+ if friends
92
101
  # friends always return the latest 20 updates, so we clip the count
93
102
  texts[count..-1]=nil
94
103
  end
95
104
  rescue
96
105
  error $!
97
- m.reply "could not parse status for #{nick}"
106
+ if friends
107
+ m.reply "could not parse status for #{nick}'s friends"
108
+ else
109
+ m.reply "could not parse status for #{nick}"
110
+ end
98
111
  return false
99
112
  end
100
113
  m.reply texts.reverse.join("\n")
101
114
  return true
102
115
  else
103
- m.reply "could not get status for #{nick}"
116
+ if friends
117
+ rep = "could not get status for #{nick}'s friends"
118
+ rep << ", try asking in private" unless m.private?
119
+ else
120
+ rep = "could not get status for #{nick}"
121
+ end
122
+ m.reply rep
104
123
  return false
105
124
  end
106
125
  end
@@ -17,11 +17,13 @@ class UrbanPlugin < Plugin
17
17
  u = URBAN + URI.escape(word)
18
18
  u += '&page=' + p.to_s if p > 1
19
19
  s = @bot.httputil.get(u)
20
- return m.reply "Couldn't get the urban dictionary definition for #{word}" if s.nil?
20
+ return m.reply("Couldn't get the urban dictionary definition for #{word}") if s.nil?
21
21
 
22
- notfound = s.match %r{<div style="color: #669FCE"><i>.*?</i> isn't defined}
22
+ notfound = s.match %r{<i>.*?</i> isn't defined}
23
23
 
24
- numpages = s[%r{<div id='paginator'>.*?</div>}m].scan(/\d+/).collect {|x| x.to_i}.max || 1
24
+ numpages = if s[%r{<div id='paginator'>.*?</div>}m]
25
+ $&.scan(/\d+/).collect {|x| x.to_i}.max || 1
26
+ else 1 end
25
27
 
26
28
  rv = Array.new
27
29
  s.scan(%r{<td class='index'[^>]*>.*?(\d+)\..*?</td>.*?<td class='word'>(?:<a.*?>)?([^>]+)(?:</a>)?</td>.*?<div class='definition'>(.+?)</div>.*?<div class='example'>(.+?)</div>}m) do |num, wrd, desc, ex|
@@ -48,7 +50,7 @@ class UrbanPlugin < Plugin
48
50
  resp = @bot.httputil.head('http://www.urbandictionary.com/random.php',
49
51
  :max_redir => -1,
50
52
  :cache => false)
51
- return m.reply "Couldn't get a random urban dictionary word" if resp.nil?
53
+ return m.reply("Couldn't get a random urban dictionary word") if resp.nil?
52
54
  if resp.code == "302" && (loc = resp['location'])
53
55
  words = URI.unescape(loc.match(/define.php\?term=(.*)$/)[1]) rescue nil
54
56
  end
@@ -28,7 +28,12 @@ class UrlPlugin < Plugin
28
28
  :default => ['localhost', '^192\.168\.', '^10\.', '^127\.', '^172\.(1[6-9]|2\d|31)\.'],
29
29
  :on_change => Proc.new { |bot, v| bot.plugins['url'].reset_no_info_hosts },
30
30
  :desc => "A list of regular expressions matching hosts for which no info should be provided")
31
-
31
+ Config.register Config::ArrayValue.new('url.only_on_channels',
32
+ :desc => "Show link info only on these channels",
33
+ :default => [])
34
+ Config.register Config::ArrayValue.new('url.ignore',
35
+ :desc => "Don't show link info for urls from users represented as hostmasks on this list. Useful for ignoring other bots, for example.",
36
+ :default => [])
32
37
 
33
38
  def initialize
34
39
  super
@@ -37,6 +42,8 @@ class UrlPlugin < Plugin
37
42
  @bot.config.items[:'url.display_link_info'].set_string(@bot.config['url.display_link_info'].to_s)
38
43
  end
39
44
  reset_no_info_hosts
45
+ self.filter_group = :htmlinfo
46
+ load_filters
40
47
  end
41
48
 
42
49
  def reset_no_info_hosts
@@ -69,7 +76,7 @@ class UrlPlugin < Plugin
69
76
  checks.flatten!
70
77
 
71
78
  unless checks.grep(@no_info_hosts).empty?
72
- return "Sorry, info retrieval for #{url.host} (#{checks.first}) is disabled"
79
+ return ( opts[:always_reply] ? "Sorry, info retrieval for #{url.host} (#{checks.first}) is disabled" : false )
73
80
  end
74
81
 
75
82
  logopts = opts.dup
@@ -81,6 +88,7 @@ class UrlPlugin < Plugin
81
88
  debug "+ getting info for #{url.request_uri}"
82
89
  info = @bot.filter(:htmlinfo, url)
83
90
  debug info
91
+ logopts[:htmlinfo] = info
84
92
  resp = info[:headers]
85
93
 
86
94
  logopts[:title] = title = info[:title]
@@ -120,7 +128,23 @@ class UrlPlugin < Plugin
120
128
  return extra.join(", ") if title or not @bot.config['url.titles_only']
121
129
  end
122
130
 
123
- def handle_urls(m, urls, display_info=@bot.config['url.display_link_info'])
131
+ def handle_urls(m, params={})
132
+ opts = {
133
+ :display_info => @bot.config['url.display_link_info'],
134
+ :channels => @bot.config['url.only_on_channels'],
135
+ :ignore => @bot.config['url.ignore']
136
+ }.merge params
137
+ urls = opts[:urls]
138
+ display_info= opts[:display_info]
139
+ channels = opts[:channels]
140
+ ignore = opts[:ignore]
141
+
142
+ unless channels.empty?
143
+ return unless channels.map { |c| c.downcase }.include?(m.channel.downcase)
144
+ end
145
+
146
+ ignore.each { |u| return if m.source.matches?(u) }
147
+
124
148
  return if urls.empty?
125
149
  debug "found urls #{urls.inspect}"
126
150
  list = m.public? ? @registry[m.target] : nil
@@ -128,12 +152,13 @@ class UrlPlugin < Plugin
128
152
  urls_displayed = 0
129
153
  urls.each do |urlstr|
130
154
  debug "working on #{urlstr}"
131
- next unless urlstr =~ /^https?:/
155
+ next unless urlstr =~ /^https?:\/\/./
132
156
  title = nil
133
157
  debug "Getting title for #{urlstr}..."
134
158
  reply = nil
135
159
  begin
136
160
  title = get_title_for_url(urlstr,
161
+ :always_reply => m.address?,
137
162
  :nick => m.source.nick,
138
163
  :channel => m.channel,
139
164
  :ircline => m.message)
@@ -145,16 +170,25 @@ class UrlPlugin < Plugin
145
170
  # with the last character stripped. this might generate invalid URIs
146
171
  # (e.g. because "some.url" gets chopped to some.url%2, so catch that too
147
172
  if e.message =~ /\(404 - Not Found\)/i or e.kind_of?(URI::InvalidURIError)
148
- # chop off last character, and retry if we still have enough string to
149
- # look like a minimal URL
150
- retry if urlstr.chop! and urlstr =~ /^https?:\/\/./
173
+ # chop off last non-word character from the unescaped version of
174
+ # the URL, and retry if we still have enough string to look like a
175
+ # minimal URL
176
+ unescaped = URI.unescape(urlstr)
177
+ debug "Unescaped: #{unescaped}"
178
+ if unescaped.sub!(/\W$/,'') and unescaped =~ /^https?:\/\/./
179
+ urlstr.replace URI.escape(unescaped, OUR_UNSAFE)
180
+ retry
181
+ else
182
+ debug "Not retrying #{unescaped}"
183
+ end
151
184
  end
152
185
  reply = "Error #{e.message}"
153
186
  end
154
187
 
155
188
  if display_info > urls_displayed
156
189
  if reply
157
- m.plainreply(reply, :overlong => :truncate)
190
+ m.reply reply, :overlong => :truncate, :to => :public,
191
+ :nick => (m.address? ? :auto : false)
158
192
  urls_displayed += 1
159
193
  end
160
194
  end
@@ -177,7 +211,12 @@ class UrlPlugin < Plugin
177
211
  def info(m, params)
178
212
  escaped = URI.escape(params[:urls].to_s, OUR_UNSAFE)
179
213
  urls = URI.extract(escaped)
180
- Thread.new { handle_urls(m, urls, params[:urls].length) }
214
+ Thread.new do
215
+ handle_urls(m,
216
+ :urls => urls,
217
+ :display_info => params[:urls].length,
218
+ :channels => [])
219
+ end
181
220
  end
182
221
 
183
222
  def message(m)
@@ -186,7 +225,7 @@ class UrlPlugin < Plugin
186
225
  escaped = URI.escape(m.message, OUR_UNSAFE)
187
226
  urls = URI.extract(escaped, ['http', 'https'])
188
227
  return if urls.empty?
189
- Thread.new { handle_urls(m, urls) }
228
+ Thread.new { handle_urls(m, :urls => urls) }
190
229
  end
191
230
 
192
231
  def reply_urls(opts={})
@@ -35,9 +35,9 @@ class CurrentConditions
35
35
  end
36
36
  rescue OpenURI::HTTPError => e
37
37
  case e
38
- when /304/:
38
+ when /304/
39
39
  @iscached = true
40
- when /404/:
40
+ when /404/
41
41
  raise "Data for #{@station} not found"
42
42
  else
43
43
  raise "Error retrieving data: #{e}"
@@ -71,18 +71,18 @@ class WeatherPlugin < Plugin
71
71
  Config.register Config::BooleanValue.new('weather.advisory',
72
72
  :default => true,
73
73
  :desc => "Should the bot report special weather advisories when any is present?")
74
-
74
+
75
75
  def help(plugin, topic="")
76
76
  case topic
77
77
  when "nws"
78
78
  "weather nws <station> => display the current conditions at the location specified by the NOAA National Weather Service station code <station> ( lookup your station code at http://www.nws.noaa.gov/data/current_obs/ )"
79
79
  when "station", "wu"
80
- "weather [<units>] <location> => display the current conditions at the location specified, looking it up on the Weather Underground site; you can use 'station <code>' to look up data by station code ( lookup your station code at http://www.weatherunderground.com/ ); you can optionally set <units> to 'metric' or 'english' if you only want data with the units; use 'both' for units to go back to having both."
80
+ "weather [<units>] <location> => display the current conditions at the location specified, looking it up on the Weather Underground site; you can use 'station <code>' to look up data by station code ( lookup your station code at http://www.weatherunderground.com/ ); you can optionally set <units> to 'metric' or 'english' if you only want data with the units; use 'both' for units to go back to having both."
81
81
  else
82
82
  "weather information lookup. Looks up weather information for the last location you specified. See topics 'nws' and 'wu' for more information"
83
83
  end
84
84
  end
85
-
85
+
86
86
  def initialize
87
87
  super
88
88
 
@@ -91,7 +91,7 @@ class WeatherPlugin < Plugin
91
91
  @wu_url = "http://mobile.wunderground.com/cgi-bin/findweather/getForecast?brand=mobile%s&query=%s"
92
92
  @wu_station_url = "http://mobile.wunderground.com/auto/mobile%s/global/stations/%s.html"
93
93
  end
94
-
94
+
95
95
  def weather(m, params)
96
96
  if params[:where].empty?
97
97
  if @registry.has_key?(m.sourcenick)
@@ -12,20 +12,20 @@ class WserverPlugin < Plugin
12
12
  m.reply "cowardly refusing to follow more than 3 redirects"
13
13
  return
14
14
  end
15
-
15
+
16
16
  begin
17
17
  uri = URI.parse(hostname)
18
18
  rescue URI::InvalidURIError => err
19
19
  m.reply "#{hostname} is not a valid URI"
20
20
  return
21
21
  end
22
-
22
+
23
23
  unless(uri)
24
24
  m.reply "incorrect usage: " + help(m.plugin)
25
25
  return
26
26
  end
27
-
28
-
27
+
28
+
29
29
  resp = @bot.httputil.head(uri)
30
30
  server = resp['Server']
31
31
  if(server && server.length > 0)
@@ -34,7 +34,7 @@ class WserverPlugin < Plugin
34
34
  m.reply "couldn't tell what #{uri.host} is running"
35
35
  end
36
36
 
37
- if(resp.code == "302" || resp.code == "301")
37
+ if(resp.code == "302" || resp.code == "301")
38
38
  newloc = resp['location']
39
39
  newuri = URI.parse(newloc)
40
40
  # detect and ignore incorrect redirects (to relative paths etc)
@@ -27,7 +27,7 @@ class YouTubePlugin < Plugin
27
27
  def youtube_filter(s)
28
28
  loc = Utils.check_location(s, /youtube\.com/)
29
29
  return nil unless loc
30
- if s[:text].include? '<div id="watch-vid-title">'
30
+ if s[:text].include? '<div id="watch-vid-title"'
31
31
  vid = @bot.filter(:"youtube.video", s)
32
32
  return nil unless vid
33
33
  content = _("Category: %{cat}. Rating: %{rating}. Author: %{author}. Duration: %{duration}. %{views} views, faved %{faves} times. %{desc}") % vid
@@ -62,11 +62,11 @@ class YouTubePlugin < Plugin
62
62
  :title => (e.elements["media:group/media:title"].text rescue nil),
63
63
  :desc => (e.elements["media:group/media:description"].text rescue nil),
64
64
  :cat => (e.elements["media:group/media:category"].text rescue nil),
65
- :seconds => (e.elements["media:group/yt:duration/@seconds"].value.to_i rescue nil),
66
- :url => (e.elements["media:group/media:player/@url"].value rescue nil),
67
- :rating => (("%s/%s" % [e.elements["gd:rating/@average"].value, e.elements["gd:rating/@max"].value]) rescue nil),
68
- :views => (e.elements["yt:statistics/@viewCount"].value rescue nil),
69
- :faves => (e.elements["yt:statistics/@favoriteCount"].value rescue nil)
65
+ :seconds => (e.elements["media:group/yt:duration/"].attributes["seconds"].to_i rescue nil),
66
+ :url => (e.elements["media:group/media:player/"].attributes["url"] rescue nil),
67
+ :rating => (("%s/%s" % [e.elements["gd:rating"].attributes["average"], e.elements["gd:rating/@max"].value]) rescue nil),
68
+ :views => (e.elements["yt:statistics"].attributes["viewCount"] rescue nil),
69
+ :faves => (e.elements["yt:statistics"].attributes["favoriteCount"] rescue nil)
70
70
  }
71
71
  if vid[:desc]
72
72
  vid[:desc].gsub!(/\s+/m, " ")
@@ -77,12 +77,12 @@ class YouTubePlugin < Plugin
77
77
  vid[:duration] = _("unknown duration")
78
78
  end
79
79
  e.elements.each("media:group/media:content") { |c|
80
- if url = (c.elements["@url"].value rescue nil)
81
- type = c.elements["@type"].value rescue nil
82
- medium = c.elements["@medium"].value rescue nil
83
- expression = c.elements["@expression"].value rescue nil
84
- seconds = c.elements["@duration"].value.to_i rescue nil
85
- fmt = case num_fmt = (c.elements["@yt:format"].value rescue nil)
80
+ if url = (c.attributes["url"] rescue nil)
81
+ type = c.attributes["type"] rescue nil
82
+ medium = c.attributes["medium"] rescue nil
83
+ expression = c.attributes["expression"] rescue nil
84
+ seconds = c.attributes["duration"].to_i rescue nil
85
+ fmt = case num_fmt = (c.attributes["yt:format"] rescue nil)
86
86
  when "1"
87
87
  "h263+amr"
88
88
  when "5"
@@ -4,7 +4,7 @@ costringe <who> a programmare in Perl per 3 settimane
4
4
  manda l'indirizzo email di <who> a 50 noti spammer
5
5
  restringe il terminale di <who> a 40x24
6
6
  ruba il the di <who>
7
- picchia <who> a sangue sulle gengive con una mazza ferrata arrugginata
7
+ picchia <who> a sangue sulle gengive con una mazza ferrata arrugginita
8
8
  vende <who> su eBay
9
9
  ficca un peperoncino su per il culo di <who>
10
10
  fa <who> a fettine
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Load rbot from this directory. (No need to install it with setup.rb)
4
+ #
5
+
6
+ SCM_DIR = File.expand_path File.dirname(__FILE__)
7
+ puts "Running from #{SCM_DIR}"
8
+
9
+ $:.unshift File.join(SCM_DIR, 'lib')
10
+
11
+ $version = '0.9.15'
12
+
13
+ pwd = Dir.pwd
14
+ begin
15
+ Dir.chdir SCM_DIR
16
+
17
+ if File.exists? '.git'
18
+ begin
19
+ git_out = `git log -1 --pretty=raw | git name-rev --stdin`.split("\n")
20
+ commit, branch_spec = git_out.first.scan(/^commit (\S+)(?: \((\S+)\))?$/).first
21
+ $version_timestamp = git_out[4].split[-2].to_i
22
+ subject = git_out[6].strip rescue ""
23
+ subject[77..-1] = "..." if subject.length > 80
24
+ rev = "revision #{commit[0,7]}"
25
+ rev << " [#{subject}]" unless subject.empty?
26
+ changes = `git diff-index --stat HEAD`.split("\n").last.split(", ").first rescue nil
27
+ rev << ", #{changes.strip}" if changes
28
+ if branch_spec
29
+ tag, branch, offset = branch_spec.scan(/^(?:(tag)s\/)?(\S+?)(?:^0)?(?:~(\d+))?$/).first
30
+ tag ||= "branch"
31
+ branch << " #{tag}"
32
+ branch << "-#{offset}" if offset
33
+ else
34
+ branch = "unknown branch"
35
+ end
36
+ rescue => e
37
+ puts e.inspect
38
+ branch = "unknown branch"
39
+ rev = "unknown revision"
40
+ end
41
+ $version << " (#{branch}, #{rev})"
42
+ elsif File.directory? File.join(SCM_DIR, '.svn')
43
+ rev = " (unknown revision)"
44
+ begin
45
+ svn_out = `svn info`
46
+ rev = " (revision #{$1}" if svn_out =~ /Last Changed Rev: (\d+)/
47
+ svn_st = `svn st #{SCM_DIR}`
48
+ rev << ", local changes" if svn_st =~ /^[MDA] /
49
+ rev << ")"
50
+ rescue => e
51
+ puts e.inspect
52
+ end
53
+ $version += rev
54
+ end
55
+ ensure
56
+ Dir.chdir pwd
57
+ end
58
+
59
+ module Irc
60
+ class Bot
61
+ module Config
62
+ @@datadir = File.join SCM_DIR, 'data/rbot'
63
+ @@coredir = File.join SCM_DIR, 'lib/rbot/core'
64
+ end
65
+ end
66
+ end
67
+
68
+ load File.join(SCM_DIR, 'bin/rbot')
@@ -24,7 +24,7 @@ require 'rbot/maskdb'
24
24
  # }
25
25
  # }
26
26
  # end
27
- #
27
+ #
28
28
 
29
29
  module Irc
30
30
  class Bot
@@ -0,0 +1,70 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: ruby 1.9 compatibility (monkey)patches
5
+
6
+ require 'timeout'
7
+ require "thread"
8
+
9
+ class ConditionVariable
10
+
11
+ def wait(mutex, timeout=nil)
12
+ begin
13
+ # TODO: mutex should not be used
14
+ @waiters_mutex.synchronize do
15
+ @waiters.push(Thread.current)
16
+ end
17
+ if timeout
18
+ elapsed = mutex.sleep timeout if timeout > 0.0
19
+ unless timeout > 0.0 and elapsed < timeout
20
+ t = @waiters_mutex.synchronize { @waiters.delete Thread.current }
21
+ signal unless t # if we got notified, pass it along
22
+ raise TimeoutError, "wait timed out"
23
+ end
24
+ else
25
+ mutex.sleep
26
+ end
27
+ end
28
+ nil
29
+ end
30
+
31
+ end
32
+
33
+ require 'monitor'
34
+
35
+ module MonitorMixin
36
+
37
+ class ConditionVariable
38
+
39
+ def wait(timeout = nil)
40
+ #if timeout
41
+ # raise NotImplementedError, "timeout is not implemented yet"
42
+ #end
43
+ @monitor.__send__(:mon_check_owner)
44
+ count = @monitor.__send__(:mon_exit_for_cond)
45
+ begin
46
+ @cond.wait(@monitor.instance_variable_get("@mon_mutex"), timeout)
47
+ return true
48
+ ensure
49
+ @monitor.__send__(:mon_enter_for_cond, count)
50
+ end
51
+ end
52
+
53
+ def signal
54
+ @monitor.__send__(:mon_check_owner)
55
+ @cond.signal
56
+ end
57
+
58
+ def broadcast
59
+ @monitor.__send__(:mon_check_owner)
60
+ @cond.broadcast
61
+ end
62
+
63
+ end # ConditionVariable
64
+
65
+ def self.extend_object(obj)
66
+ super(obj)
67
+ obj.__send__(:mon_initialize)
68
+ end
69
+
70
+ end # MonitorMixin