rbot 0.9.10 → 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (706) hide show
  1. data/AUTHORS +22 -4
  2. data/COPYING +5 -18
  3. data/ChangeLog +396 -0
  4. data/README +23 -25
  5. data/REQUIREMENTS +58 -12
  6. data/Rakefile +215 -0
  7. data/bin/rbot +47 -25
  8. data/bin/rbot-remote +76 -0
  9. data/data/rbot/languages/french.lang +5 -5
  10. data/data/rbot/languages/german.lang +4 -4
  11. data/data/rbot/languages/italian.lang +53 -0
  12. data/data/rbot/languages/japanese.lang +43 -0
  13. data/data/rbot/languages/russian.lang +60 -60
  14. data/data/rbot/languages/traditional_chinese.lang +75 -0
  15. data/data/rbot/plugins/alias.rb +192 -0
  16. data/data/rbot/plugins/autoop.rb +74 -37
  17. data/data/rbot/plugins/autorejoin.rb +15 -5
  18. data/data/rbot/plugins/bans.rb +454 -150
  19. data/data/rbot/plugins/bash.rb +173 -31
  20. data/data/rbot/plugins/botsnack.rb +37 -0
  21. data/data/rbot/plugins/cal.rb +11 -2
  22. data/data/rbot/plugins/chanserv.rb +132 -0
  23. data/data/rbot/plugins/chucknorris.rb +2 -2
  24. data/data/rbot/plugins/chucknorris.yml.gz +0 -0
  25. data/data/rbot/plugins/debugger.rb +136 -0
  26. data/data/rbot/plugins/deepthoughts.rb +89 -95
  27. data/data/rbot/plugins/delicious.rb +109 -0
  28. data/data/rbot/plugins/dice.rb +77 -25
  29. data/data/rbot/plugins/dict.rb +243 -0
  30. data/data/rbot/plugins/dictclient.rb +211 -0
  31. data/data/rbot/plugins/digg.rb +2 -2
  32. data/data/rbot/plugins/excuse.rb +4 -4
  33. data/data/rbot/plugins/factoids.rb +506 -0
  34. data/data/rbot/plugins/figlet.rb +127 -18
  35. data/data/rbot/plugins/fish.rb +93 -33
  36. data/data/rbot/plugins/forecast.rb +40 -27
  37. data/data/rbot/plugins/fortune.rb +86 -11
  38. data/data/rbot/plugins/freshmeat.rb +46 -12
  39. data/data/rbot/plugins/games/azgame.rb +565 -0
  40. data/data/rbot/plugins/games/quiz.rb +961 -0
  41. data/data/rbot/plugins/games/roshambo.rb +62 -0
  42. data/data/rbot/plugins/{roulette.rb → games/roulette.rb} +58 -8
  43. data/data/rbot/plugins/games/shiritori.rb +485 -0
  44. data/data/rbot/plugins/games/uno.rb +1205 -0
  45. data/data/rbot/plugins/games/wheelfortune.rb +615 -0
  46. data/data/rbot/plugins/grouphug.rb +76 -22
  47. data/data/rbot/plugins/hl2.rb +97 -0
  48. data/data/rbot/plugins/host.rb +10 -1
  49. data/data/rbot/plugins/httpd.rb.disabled +1 -0
  50. data/data/rbot/plugins/imdb.rb +511 -47
  51. data/data/rbot/plugins/insult.rb +32 -37
  52. data/data/rbot/plugins/iplookup.rb +224 -224
  53. data/data/rbot/plugins/karma.rb +45 -21
  54. data/data/rbot/plugins/keywords.rb +258 -160
  55. data/data/rbot/plugins/lart.rb +126 -95
  56. data/data/rbot/plugins/lastfm.rb +421 -12
  57. data/data/rbot/plugins/linkbot.rb +75 -0
  58. data/data/rbot/plugins/markov.rb +103 -46
  59. data/data/rbot/plugins/math.rb +6 -5
  60. data/data/rbot/plugins/modes.rb +114 -0
  61. data/data/rbot/plugins/nickrecover.rb +97 -0
  62. data/data/rbot/plugins/nickserv.rb +111 -48
  63. data/data/rbot/plugins/nslookup.rb +15 -19
  64. data/data/rbot/plugins/plugin.header +11 -0
  65. data/data/rbot/plugins/quakeauth.rb +74 -11
  66. data/data/rbot/plugins/quotes.rb +189 -233
  67. data/data/rbot/plugins/reaction.rb +415 -0
  68. data/data/rbot/plugins/remind.rb +11 -15
  69. data/data/rbot/plugins/remotectl.rb +29 -0
  70. data/data/rbot/plugins/ri.rb +74 -0
  71. data/data/rbot/plugins/rot13.rb +16 -1
  72. data/data/rbot/plugins/rss.rb +1219 -585
  73. data/data/rbot/plugins/salut.rb +226 -0
  74. data/data/rbot/plugins/script.rb +184 -0
  75. data/data/rbot/plugins/search.rb +233 -0
  76. data/data/rbot/plugins/seen.rb +44 -40
  77. data/data/rbot/plugins/shortenurls.rb +93 -0
  78. data/data/rbot/plugins/slashdot.rb +49 -11
  79. data/data/rbot/plugins/spell.rb +37 -27
  80. data/data/rbot/plugins/theyfightcrime.rb +36 -39
  81. data/data/rbot/plugins/threat.rb +25 -22
  82. data/data/rbot/plugins/time.rb +135 -0
  83. data/data/rbot/plugins/topic.rb +107 -50
  84. data/data/rbot/plugins/translator.rb +360 -0
  85. data/data/rbot/plugins/tube.rb +28 -40
  86. data/data/rbot/plugins/twitter.rb +187 -0
  87. data/data/rbot/plugins/urban.rb +62 -53
  88. data/data/rbot/plugins/url.rb +193 -409
  89. data/data/rbot/plugins/usermodes.rb +26 -0
  90. data/data/rbot/plugins/wall.rb +60 -0
  91. data/data/rbot/plugins/weather.rb +254 -598
  92. data/data/rbot/plugins/wow.rb +41 -37
  93. data/data/rbot/plugins/wserver.rb +17 -25
  94. data/data/rbot/plugins/youtube.rb +237 -0
  95. data/data/rbot/templates/lart/{larts → larts-english} +0 -0
  96. data/data/rbot/templates/lart/larts-italian +25 -0
  97. data/data/rbot/templates/lart/larts-japanese +10 -0
  98. data/data/rbot/templates/lart/{praises → praises-english} +0 -0
  99. data/data/rbot/templates/lart/praises-italian +4 -0
  100. data/data/rbot/templates/lart/praises-japanese +3 -0
  101. data/data/rbot/templates/quiz/win_messages +11 -0
  102. data/data/rbot/templates/salut/salut-english +40 -0
  103. data/data/rbot/templates/salut/salut-french +29 -0
  104. data/data/rbot/templates/salut/salut-italian +51 -0
  105. data/data/rbot/templates/salut/salut-japanese +31 -0
  106. data/lib/rbot/botuser.rb +940 -0
  107. data/lib/rbot/config-compat.rb +23 -0
  108. data/lib/rbot/config.rb +211 -276
  109. data/lib/rbot/core/auth.rb +1063 -0
  110. data/lib/rbot/core/basics.rb +214 -0
  111. data/lib/rbot/core/config.rb +330 -0
  112. data/lib/rbot/core/filters_ui.rb +64 -0
  113. data/lib/rbot/core/irclog.rb +292 -0
  114. data/lib/rbot/core/remote.rb +401 -0
  115. data/lib/rbot/core/unicode.rb +91 -0
  116. data/lib/rbot/core/userdata.rb +200 -0
  117. data/lib/rbot/core/utils/extends.rb +444 -0
  118. data/lib/rbot/core/utils/filters.rb +154 -0
  119. data/lib/rbot/core/utils/httputil.rb +689 -0
  120. data/lib/rbot/core/utils/utils.rb +717 -0
  121. data/lib/rbot/dbhash.rb +30 -9
  122. data/lib/rbot/irc.rb +1966 -0
  123. data/lib/rbot/ircbot.rb +816 -675
  124. data/lib/rbot/ircsocket.rb +246 -232
  125. data/lib/rbot/language.rb +86 -8
  126. data/lib/rbot/load-gettext.rb +154 -0
  127. data/lib/rbot/maskdb.rb +162 -0
  128. data/lib/rbot/message.rb +392 -65
  129. data/lib/rbot/messagemapper.rb +438 -94
  130. data/lib/rbot/pkgconfig.rb +6 -0
  131. data/lib/rbot/plugins.rb +713 -172
  132. data/lib/rbot/post-config.rb +1 -0
  133. data/lib/rbot/rbotconfig.rb +31 -12
  134. data/lib/rbot/registry.rb +79 -48
  135. data/lib/rbot/rfc2812.rb +927 -519
  136. data/lib/rbot/timer.rb +232 -167
  137. data/po/en_US/rbot-alias.po +82 -0
  138. data/po/en_US/rbot-autoop.po +0 -0
  139. data/po/en_US/rbot-autorejoin.po +0 -0
  140. data/po/en_US/rbot-azgame.po +200 -0
  141. data/po/en_US/rbot-bans.po +0 -0
  142. data/po/en_US/rbot-bash.po +0 -0
  143. data/po/en_US/rbot-botsnack.po +0 -0
  144. data/po/en_US/rbot-cal.po +3 -0
  145. data/po/en_US/rbot-chanserv.po +0 -0
  146. data/po/en_US/rbot-chucknorris.po +0 -0
  147. data/po/en_US/rbot-debugger.po +0 -0
  148. data/po/en_US/rbot-deepthoughts.po +0 -0
  149. data/po/en_US/rbot-delicious.po +0 -0
  150. data/po/en_US/rbot-dice.po +0 -0
  151. data/po/en_US/rbot-dict.po +0 -0
  152. data/po/en_US/rbot-dictclient.po +124 -0
  153. data/po/en_US/rbot-digg.po +0 -0
  154. data/po/en_US/rbot-eightball.po +0 -0
  155. data/po/en_US/rbot-excuse.po +0 -0
  156. data/po/en_US/rbot-factoids.po +107 -0
  157. data/po/en_US/rbot-figlet.po +36 -0
  158. data/po/en_US/rbot-fish.po +0 -0
  159. data/po/en_US/rbot-forecast.po +0 -0
  160. data/po/en_US/rbot-fortune.po +0 -0
  161. data/po/en_US/rbot-freshmeat.po +0 -0
  162. data/po/en_US/rbot-grouphug.po +18 -0
  163. data/po/en_US/rbot-hl2.po +0 -0
  164. data/po/en_US/rbot-host.po +3 -0
  165. data/po/en_US/rbot-imdb.po +0 -0
  166. data/po/en_US/rbot-insult.po +0 -0
  167. data/po/en_US/rbot-iplookup.po +0 -0
  168. data/po/en_US/rbot-karma.po +0 -0
  169. data/po/en_US/rbot-keywords.po +24 -0
  170. data/po/en_US/rbot-lart.po +0 -0
  171. data/po/en_US/rbot-lastfm.po +172 -0
  172. data/po/en_US/rbot-linkbot.po +0 -0
  173. data/po/en_US/rbot-markov.po +20 -0
  174. data/po/en_US/rbot-math.po +0 -0
  175. data/po/en_US/rbot-modes.po +0 -0
  176. data/po/en_US/rbot-nickrecover.po +40 -0
  177. data/po/en_US/rbot-nickserv.po +104 -0
  178. data/po/en_US/rbot-nslookup.po +0 -0
  179. data/po/en_US/rbot-quakeauth.po +0 -0
  180. data/po/en_US/rbot-quiz.po +0 -0
  181. data/po/en_US/rbot-quotes.po +108 -0
  182. data/po/en_US/rbot-reaction.po +0 -0
  183. data/po/en_US/rbot-remind.po +0 -0
  184. data/po/en_US/rbot-remotectl.po +0 -0
  185. data/po/en_US/rbot-ri.po +0 -0
  186. data/po/en_US/rbot-roshambo.po +0 -0
  187. data/po/en_US/rbot-rot13.po +0 -0
  188. data/po/en_US/rbot-roulette.po +0 -0
  189. data/po/en_US/rbot-rss.po +20 -0
  190. data/po/en_US/rbot-salut.po +0 -0
  191. data/po/en_US/rbot-script.po +0 -0
  192. data/po/en_US/rbot-search.po +0 -0
  193. data/po/en_US/rbot-seen.po +0 -0
  194. data/po/en_US/rbot-shiritori.po +113 -0
  195. data/po/en_US/rbot-shortenurls.po +0 -0
  196. data/po/en_US/rbot-slashdot.po +0 -0
  197. data/po/en_US/rbot-spell.po +54 -0
  198. data/po/en_US/rbot-theyfightcrime.po +0 -0
  199. data/po/en_US/rbot-threat.po +0 -0
  200. data/po/en_US/rbot-time.po +0 -0
  201. data/po/en_US/rbot-topic.po +0 -0
  202. data/po/en_US/rbot-translator.po +77 -0
  203. data/po/en_US/rbot-tube.po +0 -0
  204. data/po/en_US/rbot-twitter.po +24 -0
  205. data/po/en_US/rbot-uno.po +512 -0
  206. data/po/en_US/rbot-urban.po +0 -0
  207. data/po/en_US/rbot-url.po +0 -0
  208. data/po/en_US/rbot-usermodes.po +0 -0
  209. data/po/en_US/rbot-wall.po +33 -0
  210. data/po/en_US/rbot-weather.po +0 -0
  211. data/po/en_US/rbot-wheelfortune.po +205 -0
  212. data/po/en_US/rbot-wow.po +0 -0
  213. data/po/en_US/rbot-wserver.po +0 -0
  214. data/po/en_US/rbot-youtube.po +58 -0
  215. data/po/en_US/rbot.po +1097 -0
  216. data/po/fr/rbot-alias.po +97 -0
  217. data/po/fr/rbot-autoop.po +0 -0
  218. data/po/fr/rbot-autorejoin.po +0 -0
  219. data/po/fr/rbot-azgame.po +204 -0
  220. data/po/fr/rbot-bans.po +0 -0
  221. data/po/fr/rbot-bash.po +0 -0
  222. data/po/fr/rbot-botsnack.po +0 -0
  223. data/po/fr/rbot-cal.po +3 -0
  224. data/po/fr/rbot-chanserv.po +0 -0
  225. data/po/fr/rbot-chucknorris.po +0 -0
  226. data/po/fr/rbot-debugger.po +0 -0
  227. data/po/fr/rbot-deepthoughts.po +0 -0
  228. data/po/fr/rbot-delicious.po +0 -0
  229. data/po/fr/rbot-dice.po +0 -0
  230. data/po/fr/rbot-dict.po +0 -0
  231. data/po/fr/rbot-dictclient.po +134 -0
  232. data/po/fr/rbot-digg.po +0 -0
  233. data/po/fr/rbot-eightball.po +0 -0
  234. data/po/fr/rbot-excuse.po +0 -0
  235. data/po/fr/rbot-factoids.po +111 -0
  236. data/po/fr/rbot-figlet.po +37 -0
  237. data/po/fr/rbot-fish.po +0 -0
  238. data/po/fr/rbot-forecast.po +0 -0
  239. data/po/fr/rbot-fortune.po +0 -0
  240. data/po/fr/rbot-freshmeat.po +0 -0
  241. data/po/fr/rbot-grouphug.po +18 -0
  242. data/po/fr/rbot-hl2.po +0 -0
  243. data/po/fr/rbot-host.po +3 -0
  244. data/po/fr/rbot-imdb.po +0 -0
  245. data/po/fr/rbot-insult.po +0 -0
  246. data/po/fr/rbot-iplookup.po +0 -0
  247. data/po/fr/rbot-karma.po +0 -0
  248. data/po/fr/rbot-keywords.po +24 -0
  249. data/po/fr/rbot-lart.po +0 -0
  250. data/po/fr/rbot-lastfm.po +172 -0
  251. data/po/fr/rbot-linkbot.po +0 -0
  252. data/po/fr/rbot-markov.po +20 -0
  253. data/po/fr/rbot-math.po +0 -0
  254. data/po/fr/rbot-modes.po +0 -0
  255. data/po/fr/rbot-nickrecover.po +36 -0
  256. data/po/fr/rbot-nickserv.po +116 -0
  257. data/po/fr/rbot-nslookup.po +0 -0
  258. data/po/fr/rbot-quakeauth.po +0 -0
  259. data/po/fr/rbot-quiz.po +0 -0
  260. data/po/fr/rbot-quotes.po +138 -0
  261. data/po/fr/rbot-reaction.po +0 -0
  262. data/po/fr/rbot-remind.po +0 -0
  263. data/po/fr/rbot-remotectl.po +0 -0
  264. data/po/fr/rbot-ri.po +0 -0
  265. data/po/fr/rbot-roshambo.po +0 -0
  266. data/po/fr/rbot-rot13.po +0 -0
  267. data/po/fr/rbot-roulette.po +0 -0
  268. data/po/fr/rbot-rss.po +20 -0
  269. data/po/fr/rbot-salut.po +0 -0
  270. data/po/fr/rbot-script.po +0 -0
  271. data/po/fr/rbot-search.po +0 -0
  272. data/po/fr/rbot-seen.po +0 -0
  273. data/po/fr/rbot-shiritori.po +119 -0
  274. data/po/fr/rbot-shortenurls.po +0 -0
  275. data/po/fr/rbot-slashdot.po +0 -0
  276. data/po/fr/rbot-spell.po +56 -0
  277. data/po/fr/rbot-theyfightcrime.po +0 -0
  278. data/po/fr/rbot-threat.po +0 -0
  279. data/po/fr/rbot-time.po +0 -0
  280. data/po/fr/rbot-topic.po +0 -0
  281. data/po/fr/rbot-translator.po +90 -0
  282. data/po/fr/rbot-tube.po +0 -0
  283. data/po/fr/rbot-twitter.po +24 -0
  284. data/po/fr/rbot-uno.po +521 -0
  285. data/po/fr/rbot-urban.po +0 -0
  286. data/po/fr/rbot-url.po +0 -0
  287. data/po/fr/rbot-usermodes.po +0 -0
  288. data/po/fr/rbot-wall.po +33 -0
  289. data/po/fr/rbot-weather.po +0 -0
  290. data/po/fr/rbot-wheelfortune.po +255 -0
  291. data/po/fr/rbot-wow.po +0 -0
  292. data/po/fr/rbot-wserver.po +0 -0
  293. data/po/fr/rbot-youtube.po +64 -0
  294. data/po/fr/rbot.po +1133 -0
  295. data/po/it/rbot-alias.po +82 -0
  296. data/po/it/rbot-autoop.po +0 -0
  297. data/po/it/rbot-autorejoin.po +0 -0
  298. data/po/it/rbot-azgame.po +186 -0
  299. data/po/it/rbot-bans.po +0 -0
  300. data/po/it/rbot-bash.po +0 -0
  301. data/po/it/rbot-botsnack.po +0 -0
  302. data/po/it/rbot-cal.po +3 -0
  303. data/po/it/rbot-chanserv.po +0 -0
  304. data/po/it/rbot-chucknorris.po +0 -0
  305. data/po/it/rbot-debugger.po +0 -0
  306. data/po/it/rbot-deepthoughts.po +0 -0
  307. data/po/it/rbot-delicious.po +0 -0
  308. data/po/it/rbot-dice.po +0 -0
  309. data/po/it/rbot-dict.po +0 -0
  310. data/po/it/rbot-dictclient.po +111 -0
  311. data/po/it/rbot-digg.po +0 -0
  312. data/po/it/rbot-eightball.po +0 -0
  313. data/po/it/rbot-excuse.po +0 -0
  314. data/po/it/rbot-factoids.po +110 -0
  315. data/po/it/rbot-figlet.po +36 -0
  316. data/po/it/rbot-fish.po +0 -0
  317. data/po/it/rbot-forecast.po +0 -0
  318. data/po/it/rbot-fortune.po +0 -0
  319. data/po/it/rbot-freshmeat.po +0 -0
  320. data/po/it/rbot-grouphug.po +18 -0
  321. data/po/it/rbot-hl2.po +0 -0
  322. data/po/it/rbot-host.po +3 -0
  323. data/po/it/rbot-imdb.po +0 -0
  324. data/po/it/rbot-insult.po +0 -0
  325. data/po/it/rbot-iplookup.po +0 -0
  326. data/po/it/rbot-karma.po +0 -0
  327. data/po/it/rbot-keywords.po +24 -0
  328. data/po/it/rbot-lart.po +0 -0
  329. data/po/it/rbot-lastfm.po +172 -0
  330. data/po/it/rbot-linkbot.po +0 -0
  331. data/po/it/rbot-markov.po +20 -0
  332. data/po/it/rbot-math.po +0 -0
  333. data/po/it/rbot-modes.po +0 -0
  334. data/po/it/rbot-nickrecover.po +36 -0
  335. data/po/it/rbot-nickserv.po +104 -0
  336. data/po/it/rbot-nslookup.po +0 -0
  337. data/po/it/rbot-quakeauth.po +0 -0
  338. data/po/it/rbot-quiz.po +0 -0
  339. data/po/it/rbot-quotes.po +108 -0
  340. data/po/it/rbot-reaction.po +0 -0
  341. data/po/it/rbot-remind.po +0 -0
  342. data/po/it/rbot-remotectl.po +0 -0
  343. data/po/it/rbot-ri.po +0 -0
  344. data/po/it/rbot-roshambo.po +0 -0
  345. data/po/it/rbot-rot13.po +0 -0
  346. data/po/it/rbot-roulette.po +0 -0
  347. data/po/it/rbot-rss.po +20 -0
  348. data/po/it/rbot-salut.po +0 -0
  349. data/po/it/rbot-script.po +0 -0
  350. data/po/it/rbot-search.po +0 -0
  351. data/po/it/rbot-seen.po +0 -0
  352. data/po/it/rbot-shiritori.po +102 -0
  353. data/po/it/rbot-shortenurls.po +0 -0
  354. data/po/it/rbot-slashdot.po +0 -0
  355. data/po/it/rbot-spell.po +54 -0
  356. data/po/it/rbot-theyfightcrime.po +0 -0
  357. data/po/it/rbot-threat.po +0 -0
  358. data/po/it/rbot-time.po +0 -0
  359. data/po/it/rbot-topic.po +0 -0
  360. data/po/it/rbot-translator.po +77 -0
  361. data/po/it/rbot-tube.po +0 -0
  362. data/po/it/rbot-twitter.po +24 -0
  363. data/po/it/rbot-uno.po +564 -0
  364. data/po/it/rbot-urban.po +0 -0
  365. data/po/it/rbot-url.po +0 -0
  366. data/po/it/rbot-usermodes.po +0 -0
  367. data/po/it/rbot-wall.po +33 -0
  368. data/po/it/rbot-weather.po +0 -0
  369. data/po/it/rbot-wheelfortune.po +251 -0
  370. data/po/it/rbot-wow.po +0 -0
  371. data/po/it/rbot-wserver.po +0 -0
  372. data/po/it/rbot-youtube.po +64 -0
  373. data/po/it/rbot.po +1127 -0
  374. data/po/ja/rbot-alias.po +82 -0
  375. data/po/ja/rbot-autoop.po +0 -0
  376. data/po/ja/rbot-autorejoin.po +0 -0
  377. data/po/ja/rbot-azgame.po +194 -0
  378. data/po/ja/rbot-bans.po +0 -0
  379. data/po/ja/rbot-bash.po +0 -0
  380. data/po/ja/rbot-botsnack.po +0 -0
  381. data/po/ja/rbot-cal.po +3 -0
  382. data/po/ja/rbot-chanserv.po +0 -0
  383. data/po/ja/rbot-chucknorris.po +0 -0
  384. data/po/ja/rbot-debugger.po +0 -0
  385. data/po/ja/rbot-deepthoughts.po +0 -0
  386. data/po/ja/rbot-delicious.po +0 -0
  387. data/po/ja/rbot-dice.po +0 -0
  388. data/po/ja/rbot-dict.po +0 -0
  389. data/po/ja/rbot-dictclient.po +111 -0
  390. data/po/ja/rbot-digg.po +0 -0
  391. data/po/ja/rbot-eightball.po +0 -0
  392. data/po/ja/rbot-excuse.po +0 -0
  393. data/po/ja/rbot-factoids.po +107 -0
  394. data/po/ja/rbot-figlet.po +36 -0
  395. data/po/ja/rbot-fish.po +0 -0
  396. data/po/ja/rbot-forecast.po +0 -0
  397. data/po/ja/rbot-fortune.po +0 -0
  398. data/po/ja/rbot-freshmeat.po +0 -0
  399. data/po/ja/rbot-grouphug.po +18 -0
  400. data/po/ja/rbot-hl2.po +0 -0
  401. data/po/ja/rbot-host.po +3 -0
  402. data/po/ja/rbot-imdb.po +0 -0
  403. data/po/ja/rbot-insult.po +0 -0
  404. data/po/ja/rbot-iplookup.po +0 -0
  405. data/po/ja/rbot-karma.po +0 -0
  406. data/po/ja/rbot-keywords.po +24 -0
  407. data/po/ja/rbot-lart.po +0 -0
  408. data/po/ja/rbot-lastfm.po +172 -0
  409. data/po/ja/rbot-linkbot.po +0 -0
  410. data/po/ja/rbot-markov.po +20 -0
  411. data/po/ja/rbot-math.po +0 -0
  412. data/po/ja/rbot-modes.po +0 -0
  413. data/po/ja/rbot-nickrecover.po +36 -0
  414. data/po/ja/rbot-nickserv.po +104 -0
  415. data/po/ja/rbot-nslookup.po +0 -0
  416. data/po/ja/rbot-quakeauth.po +0 -0
  417. data/po/ja/rbot-quiz.po +0 -0
  418. data/po/ja/rbot-quotes.po +108 -0
  419. data/po/ja/rbot-reaction.po +0 -0
  420. data/po/ja/rbot-remind.po +0 -0
  421. data/po/ja/rbot-remotectl.po +0 -0
  422. data/po/ja/rbot-ri.po +0 -0
  423. data/po/ja/rbot-roshambo.po +0 -0
  424. data/po/ja/rbot-rot13.po +0 -0
  425. data/po/ja/rbot-roulette.po +0 -0
  426. data/po/ja/rbot-rss.po +20 -0
  427. data/po/ja/rbot-salut.po +0 -0
  428. data/po/ja/rbot-script.po +0 -0
  429. data/po/ja/rbot-search.po +0 -0
  430. data/po/ja/rbot-seen.po +0 -0
  431. data/po/ja/rbot-shiritori.po +115 -0
  432. data/po/ja/rbot-shortenurls.po +0 -0
  433. data/po/ja/rbot-slashdot.po +0 -0
  434. data/po/ja/rbot-spell.po +54 -0
  435. data/po/ja/rbot-theyfightcrime.po +0 -0
  436. data/po/ja/rbot-threat.po +0 -0
  437. data/po/ja/rbot-time.po +0 -0
  438. data/po/ja/rbot-topic.po +0 -0
  439. data/po/ja/rbot-translator.po +77 -0
  440. data/po/ja/rbot-tube.po +0 -0
  441. data/po/ja/rbot-twitter.po +24 -0
  442. data/po/ja/rbot-uno.po +512 -0
  443. data/po/ja/rbot-urban.po +0 -0
  444. data/po/ja/rbot-url.po +0 -0
  445. data/po/ja/rbot-usermodes.po +0 -0
  446. data/po/ja/rbot-wall.po +33 -0
  447. data/po/ja/rbot-weather.po +0 -0
  448. data/po/ja/rbot-wheelfortune.po +205 -0
  449. data/po/ja/rbot-wow.po +0 -0
  450. data/po/ja/rbot-wserver.po +0 -0
  451. data/po/ja/rbot-youtube.po +58 -0
  452. data/po/ja/rbot.po +999 -0
  453. data/po/rbot-alias.pot +83 -0
  454. data/po/rbot-autoop.pot +0 -0
  455. data/po/rbot-autorejoin.pot +0 -0
  456. data/po/rbot-azgame.pot +187 -0
  457. data/po/rbot-bans.pot +0 -0
  458. data/po/rbot-bash.pot +0 -0
  459. data/po/rbot-botsnack.pot +0 -0
  460. data/po/rbot-cal.pot +21 -0
  461. data/po/rbot-chanserv.pot +0 -0
  462. data/po/rbot-chucknorris.pot +0 -0
  463. data/po/rbot-debugger.pot +0 -0
  464. data/po/rbot-deepthoughts.pot +0 -0
  465. data/po/rbot-delicious.pot +0 -0
  466. data/po/rbot-dice.pot +0 -0
  467. data/po/rbot-dict.pot +0 -0
  468. data/po/rbot-dictclient.pot +112 -0
  469. data/po/rbot-digg.pot +0 -0
  470. data/po/rbot-eightball.pot +0 -0
  471. data/po/rbot-excuse.pot +0 -0
  472. data/po/rbot-factoids.pot +108 -0
  473. data/po/rbot-figlet.pot +37 -0
  474. data/po/rbot-fish.pot +0 -0
  475. data/po/rbot-forecast.pot +0 -0
  476. data/po/rbot-fortune.pot +0 -0
  477. data/po/rbot-freshmeat.pot +0 -0
  478. data/po/rbot-grouphug.pot +36 -0
  479. data/po/rbot-hl2.pot +0 -0
  480. data/po/rbot-host.pot +21 -0
  481. data/po/rbot-imdb.pot +0 -0
  482. data/po/rbot-insult.pot +0 -0
  483. data/po/rbot-iplookup.pot +0 -0
  484. data/po/rbot-karma.pot +0 -0
  485. data/po/rbot-keywords.pot +25 -0
  486. data/po/rbot-lart.pot +0 -0
  487. data/po/rbot-lastfm.pot +190 -0
  488. data/po/rbot-linkbot.pot +0 -0
  489. data/po/rbot-markov.pot +21 -0
  490. data/po/rbot-math.pot +0 -0
  491. data/po/rbot-modes.pot +0 -0
  492. data/po/rbot-nickrecover.pot +37 -0
  493. data/po/rbot-nickserv.pot +105 -0
  494. data/po/rbot-nslookup.pot +0 -0
  495. data/po/rbot-quakeauth.pot +0 -0
  496. data/po/rbot-quiz.pot +0 -0
  497. data/po/rbot-quotes.pot +109 -0
  498. data/po/rbot-reaction.pot +0 -0
  499. data/po/rbot-remind.pot +0 -0
  500. data/po/rbot-remotectl.pot +0 -0
  501. data/po/rbot-ri.pot +0 -0
  502. data/po/rbot-roshambo.pot +0 -0
  503. data/po/rbot-rot13.pot +0 -0
  504. data/po/rbot-roulette.pot +0 -0
  505. data/po/rbot-rss.pot +21 -0
  506. data/po/rbot-salut.pot +0 -0
  507. data/po/rbot-script.pot +0 -0
  508. data/po/rbot-search.pot +0 -0
  509. data/po/rbot-seen.pot +0 -0
  510. data/po/rbot-shiritori.pot +103 -0
  511. data/po/rbot-shortenurls.pot +0 -0
  512. data/po/rbot-slashdot.pot +0 -0
  513. data/po/rbot-spell.pot +55 -0
  514. data/po/rbot-theyfightcrime.pot +0 -0
  515. data/po/rbot-threat.pot +0 -0
  516. data/po/rbot-time.pot +0 -0
  517. data/po/rbot-topic.pot +0 -0
  518. data/po/rbot-translator.pot +78 -0
  519. data/po/rbot-tube.pot +0 -0
  520. data/po/rbot-twitter.pot +25 -0
  521. data/po/rbot-uno.pot +513 -0
  522. data/po/rbot-urban.pot +0 -0
  523. data/po/rbot-url.pot +0 -0
  524. data/po/rbot-usermodes.pot +0 -0
  525. data/po/rbot-wall.pot +33 -0
  526. data/po/rbot-weather.pot +0 -0
  527. data/po/rbot-wheelfortune.pot +206 -0
  528. data/po/rbot-wow.pot +0 -0
  529. data/po/rbot-wserver.pot +0 -0
  530. data/po/rbot-youtube.pot +59 -0
  531. data/po/rbot.pot +1004 -0
  532. data/po/zh_CN/rbot-alias.po +82 -0
  533. data/po/zh_CN/rbot-autoop.po +0 -0
  534. data/po/zh_CN/rbot-autorejoin.po +0 -0
  535. data/po/zh_CN/rbot-azgame.po +186 -0
  536. data/po/zh_CN/rbot-bans.po +0 -0
  537. data/po/zh_CN/rbot-bash.po +0 -0
  538. data/po/zh_CN/rbot-botsnack.po +0 -0
  539. data/po/zh_CN/rbot-cal.po +3 -0
  540. data/po/zh_CN/rbot-chanserv.po +0 -0
  541. data/po/zh_CN/rbot-chucknorris.po +0 -0
  542. data/po/zh_CN/rbot-debugger.po +0 -0
  543. data/po/zh_CN/rbot-deepthoughts.po +0 -0
  544. data/po/zh_CN/rbot-delicious.po +0 -0
  545. data/po/zh_CN/rbot-dice.po +0 -0
  546. data/po/zh_CN/rbot-dict.po +0 -0
  547. data/po/zh_CN/rbot-dictclient.po +111 -0
  548. data/po/zh_CN/rbot-digg.po +0 -0
  549. data/po/zh_CN/rbot-eightball.po +0 -0
  550. data/po/zh_CN/rbot-excuse.po +0 -0
  551. data/po/zh_CN/rbot-factoids.po +107 -0
  552. data/po/zh_CN/rbot-figlet.po +36 -0
  553. data/po/zh_CN/rbot-fish.po +0 -0
  554. data/po/zh_CN/rbot-forecast.po +0 -0
  555. data/po/zh_CN/rbot-fortune.po +0 -0
  556. data/po/zh_CN/rbot-freshmeat.po +0 -0
  557. data/po/zh_CN/rbot-grouphug.po +18 -0
  558. data/po/zh_CN/rbot-hl2.po +0 -0
  559. data/po/zh_CN/rbot-host.po +3 -0
  560. data/po/zh_CN/rbot-imdb.po +0 -0
  561. data/po/zh_CN/rbot-insult.po +0 -0
  562. data/po/zh_CN/rbot-iplookup.po +0 -0
  563. data/po/zh_CN/rbot-karma.po +0 -0
  564. data/po/zh_CN/rbot-keywords.po +24 -0
  565. data/po/zh_CN/rbot-lart.po +0 -0
  566. data/po/zh_CN/rbot-lastfm.po +172 -0
  567. data/po/zh_CN/rbot-linkbot.po +0 -0
  568. data/po/zh_CN/rbot-markov.po +20 -0
  569. data/po/zh_CN/rbot-math.po +0 -0
  570. data/po/zh_CN/rbot-modes.po +0 -0
  571. data/po/zh_CN/rbot-nickrecover.po +36 -0
  572. data/po/zh_CN/rbot-nickserv.po +104 -0
  573. data/po/zh_CN/rbot-nslookup.po +0 -0
  574. data/po/zh_CN/rbot-quakeauth.po +0 -0
  575. data/po/zh_CN/rbot-quiz.po +0 -0
  576. data/po/zh_CN/rbot-quotes.po +108 -0
  577. data/po/zh_CN/rbot-reaction.po +0 -0
  578. data/po/zh_CN/rbot-remind.po +0 -0
  579. data/po/zh_CN/rbot-remotectl.po +0 -0
  580. data/po/zh_CN/rbot-ri.po +0 -0
  581. data/po/zh_CN/rbot-roshambo.po +0 -0
  582. data/po/zh_CN/rbot-rot13.po +0 -0
  583. data/po/zh_CN/rbot-roulette.po +0 -0
  584. data/po/zh_CN/rbot-rss.po +20 -0
  585. data/po/zh_CN/rbot-salut.po +0 -0
  586. data/po/zh_CN/rbot-script.po +0 -0
  587. data/po/zh_CN/rbot-search.po +0 -0
  588. data/po/zh_CN/rbot-seen.po +0 -0
  589. data/po/zh_CN/rbot-shiritori.po +102 -0
  590. data/po/zh_CN/rbot-shortenurls.po +0 -0
  591. data/po/zh_CN/rbot-slashdot.po +0 -0
  592. data/po/zh_CN/rbot-spell.po +54 -0
  593. data/po/zh_CN/rbot-theyfightcrime.po +0 -0
  594. data/po/zh_CN/rbot-threat.po +0 -0
  595. data/po/zh_CN/rbot-time.po +0 -0
  596. data/po/zh_CN/rbot-topic.po +0 -0
  597. data/po/zh_CN/rbot-translator.po +77 -0
  598. data/po/zh_CN/rbot-tube.po +0 -0
  599. data/po/zh_CN/rbot-twitter.po +24 -0
  600. data/po/zh_CN/rbot-uno.po +512 -0
  601. data/po/zh_CN/rbot-urban.po +0 -0
  602. data/po/zh_CN/rbot-url.po +0 -0
  603. data/po/zh_CN/rbot-usermodes.po +0 -0
  604. data/po/zh_CN/rbot-wall.po +33 -0
  605. data/po/zh_CN/rbot-weather.po +0 -0
  606. data/po/zh_CN/rbot-wheelfortune.po +205 -0
  607. data/po/zh_CN/rbot-wow.po +0 -0
  608. data/po/zh_CN/rbot-wserver.po +0 -0
  609. data/po/zh_CN/rbot-youtube.po +58 -0
  610. data/po/zh_CN/rbot.po +1006 -0
  611. data/po/zh_TW/rbot-alias.po +82 -0
  612. data/po/zh_TW/rbot-autoop.po +0 -0
  613. data/po/zh_TW/rbot-autorejoin.po +0 -0
  614. data/po/zh_TW/rbot-azgame.po +186 -0
  615. data/po/zh_TW/rbot-bans.po +0 -0
  616. data/po/zh_TW/rbot-bash.po +0 -0
  617. data/po/zh_TW/rbot-botsnack.po +0 -0
  618. data/po/zh_TW/rbot-cal.po +3 -0
  619. data/po/zh_TW/rbot-chanserv.po +0 -0
  620. data/po/zh_TW/rbot-chucknorris.po +0 -0
  621. data/po/zh_TW/rbot-debugger.po +0 -0
  622. data/po/zh_TW/rbot-deepthoughts.po +0 -0
  623. data/po/zh_TW/rbot-delicious.po +0 -0
  624. data/po/zh_TW/rbot-dice.po +0 -0
  625. data/po/zh_TW/rbot-dict.po +0 -0
  626. data/po/zh_TW/rbot-dictclient.po +111 -0
  627. data/po/zh_TW/rbot-digg.po +0 -0
  628. data/po/zh_TW/rbot-eightball.po +0 -0
  629. data/po/zh_TW/rbot-excuse.po +0 -0
  630. data/po/zh_TW/rbot-factoids.po +107 -0
  631. data/po/zh_TW/rbot-figlet.po +36 -0
  632. data/po/zh_TW/rbot-fish.po +0 -0
  633. data/po/zh_TW/rbot-forecast.po +0 -0
  634. data/po/zh_TW/rbot-fortune.po +0 -0
  635. data/po/zh_TW/rbot-freshmeat.po +0 -0
  636. data/po/zh_TW/rbot-grouphug.po +18 -0
  637. data/po/zh_TW/rbot-hl2.po +0 -0
  638. data/po/zh_TW/rbot-host.po +3 -0
  639. data/po/zh_TW/rbot-imdb.po +0 -0
  640. data/po/zh_TW/rbot-insult.po +0 -0
  641. data/po/zh_TW/rbot-iplookup.po +0 -0
  642. data/po/zh_TW/rbot-karma.po +0 -0
  643. data/po/zh_TW/rbot-keywords.po +24 -0
  644. data/po/zh_TW/rbot-lart.po +0 -0
  645. data/po/zh_TW/rbot-lastfm.po +172 -0
  646. data/po/zh_TW/rbot-linkbot.po +0 -0
  647. data/po/zh_TW/rbot-markov.po +20 -0
  648. data/po/zh_TW/rbot-math.po +0 -0
  649. data/po/zh_TW/rbot-modes.po +0 -0
  650. data/po/zh_TW/rbot-nickrecover.po +36 -0
  651. data/po/zh_TW/rbot-nickserv.po +104 -0
  652. data/po/zh_TW/rbot-nslookup.po +0 -0
  653. data/po/zh_TW/rbot-quakeauth.po +0 -0
  654. data/po/zh_TW/rbot-quiz.po +0 -0
  655. data/po/zh_TW/rbot-quotes.po +108 -0
  656. data/po/zh_TW/rbot-reaction.po +0 -0
  657. data/po/zh_TW/rbot-remind.po +0 -0
  658. data/po/zh_TW/rbot-remotectl.po +0 -0
  659. data/po/zh_TW/rbot-ri.po +0 -0
  660. data/po/zh_TW/rbot-roshambo.po +0 -0
  661. data/po/zh_TW/rbot-rot13.po +0 -0
  662. data/po/zh_TW/rbot-roulette.po +0 -0
  663. data/po/zh_TW/rbot-rss.po +20 -0
  664. data/po/zh_TW/rbot-salut.po +0 -0
  665. data/po/zh_TW/rbot-script.po +0 -0
  666. data/po/zh_TW/rbot-search.po +0 -0
  667. data/po/zh_TW/rbot-seen.po +0 -0
  668. data/po/zh_TW/rbot-shiritori.po +102 -0
  669. data/po/zh_TW/rbot-shortenurls.po +0 -0
  670. data/po/zh_TW/rbot-slashdot.po +0 -0
  671. data/po/zh_TW/rbot-spell.po +54 -0
  672. data/po/zh_TW/rbot-theyfightcrime.po +0 -0
  673. data/po/zh_TW/rbot-threat.po +0 -0
  674. data/po/zh_TW/rbot-time.po +0 -0
  675. data/po/zh_TW/rbot-topic.po +0 -0
  676. data/po/zh_TW/rbot-translator.po +77 -0
  677. data/po/zh_TW/rbot-tube.po +0 -0
  678. data/po/zh_TW/rbot-twitter.po +24 -0
  679. data/po/zh_TW/rbot-uno.po +512 -0
  680. data/po/zh_TW/rbot-urban.po +0 -0
  681. data/po/zh_TW/rbot-url.po +0 -0
  682. data/po/zh_TW/rbot-usermodes.po +0 -0
  683. data/po/zh_TW/rbot-wall.po +33 -0
  684. data/po/zh_TW/rbot-weather.po +0 -0
  685. data/po/zh_TW/rbot-wheelfortune.po +205 -0
  686. data/po/zh_TW/rbot-wow.po +0 -0
  687. data/po/zh_TW/rbot-wserver.po +0 -0
  688. data/po/zh_TW/rbot-youtube.po +58 -0
  689. data/po/zh_TW/rbot.po +1034 -0
  690. data/setup.rb +800 -574
  691. metadata +723 -108
  692. data/data/rbot/contrib/plugins/figlet.rb +0 -20
  693. data/data/rbot/contrib/plugins/ri.rb +0 -83
  694. data/data/rbot/plugins/demauro.rb +0 -95
  695. data/data/rbot/plugins/google.rb +0 -53
  696. data/data/rbot/plugins/opme.rb +0 -19
  697. data/data/rbot/plugins/roshambo.rb +0 -54
  698. data/data/rbot/plugins/rubyurl.rb +0 -39
  699. data/data/rbot/plugins/tinyurl.rb +0 -39
  700. data/data/rbot/plugins/xmlrpc.rb.disabled +0 -52
  701. data/data/rbot/templates/levels.rbot +0 -32
  702. data/data/rbot/templates/users.rbot +0 -1
  703. data/lib/rbot/auth.rb +0 -314
  704. data/lib/rbot/channel.rb +0 -54
  705. data/lib/rbot/httputil.rb +0 -309
  706. data/lib/rbot/utils.rb +0 -83
@@ -3,6 +3,7 @@ File.open("pkgconfig.rb", "w") {|f|
3
3
  f.puts "module Irc"
4
4
  f.puts " module PKGConfig"
5
5
  f.puts " DATADIR = '#{config('datadir')}/rbot'"
6
+ f.puts " COREDIR = '#{config('rbdir')}/rbot/core'"
6
7
  f.puts " end"
7
8
  f.puts "end"
8
9
  }
@@ -1,31 +1,44 @@
1
1
  module Irc
2
+ class Bot
2
3
  module Config
3
- @@datadir = nil
4
+ unless defined?(@@datadir)
5
+ @@datadir = nil
4
6
 
5
- # first try for the default path to the data dir
6
- defaultdir = File.expand_path(File.dirname($0) + '/../data')
7
+ defaultdatadir = File.expand_path(File.dirname($0) + '/../data/rbot')
7
8
 
8
- if File.directory? "#{defaultdir}/rbot"
9
- @@datadir = "#{defaultdir}/rbot"
9
+ if File.directory? defaultdatadir
10
+ @@datadir = defaultdatadir
11
+ end
12
+ end
13
+
14
+ unless defined?(@@coredir)
15
+ @@coredir = nil
16
+
17
+ defaultcoredir = File.expand_path(File.dirname($0) + '/../lib/rbot/core')
18
+
19
+ if File.directory? defaultcoredir
20
+ @@coredir = defaultcoredir
21
+ end
10
22
  end
11
-
23
+
12
24
  # setup pkg-based configuration - i.e. where were we installed to, where
13
25
  # are our data files, etc.
14
- if @@datadir.nil?
26
+ if @@datadir.nil? or @@coredir.nil?
15
27
  begin
16
28
  debug "trying to load rubygems"
17
29
  require 'rubygems'
18
- debug "loaded rubygems, looking for rbot-#$version"
19
- if $version =~ /(.*)-svn\Z/
30
+ if $version =~ /^(.*)-(?:git|rc\d)(?: .*)?$/
20
31
  version = $1
21
32
  else
22
33
  version = $version
23
34
  end
35
+ debug "loaded rubygems, looking for rbot version #{$version} (rbot-#{version})"
24
36
  gemname, gem = Gem.source_index.find{|name, spec| spec.name == 'rbot' && spec.version.version == version}
25
37
  debug "got gem #{gem}"
26
38
  if gem && path = gem.full_gem_path
27
39
  debug "installed via rubygems to #{path}"
28
40
  @@datadir = "#{path}/data/rbot"
41
+ @@coredir = "#{path}/lib/rbot/core"
29
42
  else
30
43
  debug "not installed via rubygems"
31
44
  end
@@ -34,18 +47,24 @@ module Irc
34
47
  end
35
48
  end
36
49
 
37
- if @@datadir.nil?
50
+ if @@datadir.nil? or @@coredir.nil?
38
51
  begin
39
52
  require 'rbot/pkgconfig'
40
53
  @@datadir = PKGConfig::DATADIR
54
+ @@coredir = PKGConfig::COREDIR
41
55
  rescue LoadError
42
- error "fatal - no way to determine data dir"
56
+ error "fatal - no way to determine data or core dir"
43
57
  exit 2
44
58
  end
45
59
  end
46
-
60
+
47
61
  def Config.datadir
48
62
  @@datadir
49
63
  end
64
+
65
+ def Config.coredir
66
+ @@coredir
67
+ end
50
68
  end
51
69
  end
70
+ end
@@ -1,10 +1,11 @@
1
1
  require 'rbot/dbhash'
2
2
 
3
3
  module Irc
4
+ class Bot
4
5
 
5
- # this class is now used purely for upgrading from prior versions of rbot
6
+ # This class is now used purely for upgrading from prior versions of rbot
6
7
  # the new registry is split into multiple DBHash objects, one per plugin
7
- class BotRegistry
8
+ class Registry
8
9
  def initialize(bot)
9
10
  @bot = bot
10
11
  upgrade_data
@@ -16,7 +17,7 @@ module Irc
16
17
  # work with is @bot.botclass.
17
18
  def upgrade_data
18
19
  if File.exist?("#{@bot.botclass}/registry.db")
19
- log "upgrading old-style (rbot 0.9.5 or earlier) plugin registry to new format"
20
+ log _("upgrading old-style (rbot 0.9.5 or earlier) plugin registry to new format")
20
21
  old = BDB::Hash.open("#{@bot.botclass}/registry.db", nil,
21
22
  "r+", 0600)
22
23
  new = BDB::CIBtree.open("#{@bot.botclass}/plugin_registry.db", nil,
@@ -34,9 +35,9 @@ module Irc
34
35
  def upgrade_data2
35
36
  if File.exist?("#{@bot.botclass}/plugin_registry.db")
36
37
  Dir.mkdir("#{@bot.botclass}/registry") unless File.exist?("#{@bot.botclass}/registry")
37
- env = BDB::Env.open("#{@bot.botclass}", BDB::INIT_TRANSACTION | BDB::CREATE | BDB::RECOVER )
38
+ env = BDB::Env.open("#{@bot.botclass}", BDB::INIT_TRANSACTION | BDB::CREATE | BDB::RECOVER)# | BDB::TXN_NOSYNC)
38
39
  dbs = Hash.new
39
- log "upgrading previous (rbot 0.9.9 or earlier) plugin registry to new split format"
40
+ log _("upgrading previous (rbot 0.9.9 or earlier) plugin registry to new split format")
40
41
  old = BDB::CIBtree.open("#{@bot.botclass}/plugin_registry.db", nil,
41
42
  "r+", 0600, "env" => env)
42
43
  old.each {|k,v|
@@ -49,13 +50,13 @@ module Irc
49
50
  dirs.length.times { |i|
50
51
  dir = dirs[0,i+1].join("/")+"/"
51
52
  unless File.exist?(dir)
52
- log "creating subregistry directory #{dir}"
53
- Dir.mkdir(dir)
53
+ log _("creating subregistry directory #{dir}")
54
+ Dir.mkdir(dir)
54
55
  end
55
56
  }
56
57
  end
57
58
  unless dbs.has_key?(prefix)
58
- log "creating db #{@bot.botclass}/registry/#{prefix}.db"
59
+ log _("creating db #{@bot.botclass}/registry/#{prefix}.db")
59
60
  dbs[prefix] = BDB::CIBtree.open("#{@bot.botclass}/registry/#{prefix}.db",
60
61
  nil, BDB::CREATE | BDB::EXCL,
61
62
  0600, "env" => env)
@@ -65,13 +66,12 @@ module Irc
65
66
  old.close
66
67
  File.rename("#{@bot.botclass}/plugin_registry.db", "#{@bot.botclass}/plugin_registry.db.old")
67
68
  dbs.each {|k,v|
68
- log "closing db #{k}"
69
+ log _("closing db #{k}")
69
70
  v.close
70
71
  }
71
72
  env.close
72
73
  end
73
74
  end
74
- end
75
75
 
76
76
 
77
77
  # This class provides persistent storage for plugins via a hash interface.
@@ -94,7 +94,7 @@ module Irc
94
94
  # in object store mode, don't make the mistake of treating it like a live
95
95
  # object, e.g. (using the example above)
96
96
  # @registry[:blah][:foo] = "flump"
97
- # will NOT modify the object in the registry - remember that BotRegistry#[]
97
+ # will NOT modify the object in the registry - remember that Registry#[]
98
98
  # returns a Marshal.restore'd object, the object you just modified in place
99
99
  # will disappear. You would need to:
100
100
  # blah = @registry[:blah]
@@ -117,32 +117,46 @@ module Irc
117
117
  # Your plugins section of the registry is private, it has its own namespace
118
118
  # (derived from the plugin's class name, so change it and lose your data).
119
119
  # Calls to registry.each etc, will only iterate over your namespace.
120
- class BotRegistryAccessor
121
- # plugins don't call this - a BotRegistryAccessor is created for them and
120
+ class Accessor
121
+
122
+ attr_accessor :recovery
123
+
124
+ # plugins don't call this - a Registry::Accessor is created for them and
122
125
  # is accessible via @registry.
123
126
  def initialize(bot, name)
124
127
  @bot = bot
125
128
  @name = name.downcase
126
- dirs = File.dirname("#{@bot.botclass}/registry/#{@name}").split("/")
129
+ @filename = "#{@bot.botclass}/registry/#{@name}"
130
+ dirs = File.dirname(@filename).split("/")
127
131
  dirs.length.times { |i|
128
132
  dir = dirs[0,i+1].join("/")+"/"
129
133
  unless File.exist?(dir)
130
134
  debug "creating subregistry directory #{dir}"
131
- Dir.mkdir(dir)
135
+ Dir.mkdir(dir)
132
136
  end
133
137
  }
134
- @registry = DBTree.new bot, "registry/#{@name}"
138
+ @filename << ".db"
139
+ @registry = nil
135
140
  @default = nil
141
+ @recovery = nil
136
142
  # debug "initializing registry accessor with name #{@name}"
137
143
  end
138
144
 
145
+ def registry
146
+ @registry ||= DBTree.new @bot, "registry/#{@name}"
147
+ end
148
+
139
149
  def flush
140
- @registry.flush
141
- @registry.sync
150
+ # debug "fushing registry #{registry}"
151
+ return if !@registry
152
+ registry.flush
153
+ registry.sync
142
154
  end
143
155
 
144
156
  def close
145
- @registry.close
157
+ # debug "closing registry #{registry}"
158
+ return if !@registry
159
+ registry.close
146
160
  end
147
161
 
148
162
  # convert value to string form for storing in the registry
@@ -167,84 +181,93 @@ module Irc
167
181
  begin
168
182
  Marshal.restore(val)
169
183
  rescue Exception => e
170
- warning "failed to restore marshal data for #{val.inspect}, falling back to default"
171
- debug e.inspect
172
- debug e.backtrace.join("\n")
173
- if @default != nil
184
+ error _("failed to restore marshal data for #{val.inspect}, attempting recovery or fallback to default")
185
+ debug e
186
+ if defined? @recovery and @recovery
174
187
  begin
175
- return Marshal.restore(@default)
176
- rescue
177
- return nil
188
+ return @recovery.call(val)
189
+ rescue Exception => ee
190
+ error _("marshal recovery failed, trying default")
191
+ debug ee
178
192
  end
179
- else
180
- return nil
181
193
  end
194
+ return default
182
195
  end
183
196
  end
184
197
 
185
198
  # lookup a key in the registry
186
199
  def [](key)
187
- if @registry.has_key?(key)
188
- return restore(@registry[key])
189
- elsif @default != nil
190
- return restore(@default)
200
+ if File.exist?(@filename) && registry.has_key?(key)
201
+ return restore(registry[key])
191
202
  else
192
- return nil
203
+ return default
193
204
  end
194
205
  end
195
206
 
196
207
  # set a key in the registry
197
208
  def []=(key,value)
198
- @registry[key] = store(value)
209
+ registry[key] = store(value)
199
210
  end
200
211
 
201
212
  # set the default value for registry lookups, if the key sought is not
202
213
  # found, the default will be returned. The default default (har) is nil.
203
214
  def set_default (default)
204
- @default = store(default)
215
+ @default = default
216
+ end
217
+
218
+ def default
219
+ @default && (@default.dup rescue @default)
205
220
  end
206
221
 
207
222
  # just like Hash#each
208
223
  def each(&block)
209
- @registry.each {|key,value|
224
+ return nil unless File.exist?(@filename)
225
+ registry.each {|key,value|
210
226
  block.call(key, restore(value))
211
227
  }
212
228
  end
213
229
 
214
230
  # just like Hash#each_key
215
231
  def each_key(&block)
216
- @registry.each {|key, value|
232
+ return nil unless File.exist?(@filename)
233
+ registry.each {|key, value|
217
234
  block.call(key)
218
235
  }
219
236
  end
220
237
 
221
238
  # just like Hash#each_value
222
239
  def each_value(&block)
223
- @registry.each {|key, value|
240
+ return nil unless File.exist?(@filename)
241
+ registry.each {|key, value|
224
242
  block.call(restore(value))
225
243
  }
226
244
  end
227
245
 
228
246
  # just like Hash#has_key?
229
247
  def has_key?(key)
230
- return @registry.has_key?(key)
248
+ return false unless File.exist?(@filename)
249
+ return registry.has_key?(key)
231
250
  end
232
251
  alias include? has_key?
233
252
  alias member? has_key?
253
+ alias key? has_key?
234
254
 
235
255
  # just like Hash#has_both?
236
256
  def has_both?(key, value)
237
- return @registry.has_both?(key, store(value))
257
+ return false unless File.exist?(@filename)
258
+ return registry.has_both?(key, store(value))
238
259
  end
239
260
 
240
261
  # just like Hash#has_value?
241
262
  def has_value?(value)
242
- return @registry.has_value?(store(value))
263
+ return false unless File.exist?(@filename)
264
+ return registry.has_value?(store(value))
243
265
  end
244
266
 
245
267
  # just like Hash#index?
246
268
  def index(value)
247
- ind = @registry.index(store(value))
269
+ return nil unless File.exist?(@filename)
270
+ ind = registry.index(store(value))
248
271
  if ind
249
272
  return ind
250
273
  else
@@ -254,18 +277,21 @@ module Irc
254
277
 
255
278
  # delete a key from the registry
256
279
  def delete(key)
257
- return @registry.delete(key)
280
+ return default unless File.exist?(@filename)
281
+ return registry.delete(key)
258
282
  end
259
283
 
260
284
  # returns a list of your keys
261
285
  def keys
262
- return @registry.keys
286
+ return [] unless File.exist?(@filename)
287
+ return registry.keys
263
288
  end
264
289
 
265
290
  # Return an array of all associations [key, value] in your namespace
266
291
  def to_a
292
+ return [] unless File.exist?(@filename)
267
293
  ret = Array.new
268
- @registry.each {|key, value|
294
+ registry.each {|key, value|
269
295
  ret << [key, restore(value)]
270
296
  }
271
297
  return ret
@@ -273,8 +299,9 @@ module Irc
273
299
 
274
300
  # Return an hash of all associations {key => value} in your namespace
275
301
  def to_hash
302
+ return {} unless File.exist?(@filename)
276
303
  ret = Hash.new
277
- @registry.each {|key, value|
304
+ registry.each {|key, value|
278
305
  ret[key] = restore(value)
279
306
  }
280
307
  return ret
@@ -282,12 +309,14 @@ module Irc
282
309
 
283
310
  # empties the registry (restricted to your namespace)
284
311
  def clear
285
- @registry.clear
312
+ return true unless File.exist?(@filename)
313
+ registry.clear
286
314
  end
287
315
  alias truncate clear
288
316
 
289
317
  # returns an array of the values in your namespace of the registry
290
318
  def values
319
+ return [] unless File.exist?(@filename)
291
320
  ret = Array.new
292
321
  self.each {|k,v|
293
322
  ret << restore(v)
@@ -296,7 +325,7 @@ module Irc
296
325
  end
297
326
 
298
327
  def sub_registry(prefix)
299
- return BotRegistryAccessor.new(@bot, @name + "/" + prefix)
328
+ return Accessor.new(@bot, @name + "/" + prefix.to_s)
300
329
  end
301
330
 
302
331
  # returns the number of keys in your registry namespace
@@ -307,4 +336,6 @@ module Irc
307
336
 
308
337
  end
309
338
 
339
+ end
340
+ end
310
341
  end
@@ -1,35 +1,50 @@
1
+ #-- vim:sw=2:et
2
+ #++
3
+ #
4
+ # :title: RFC 2821 Client Protocol module
5
+ #
6
+ # This module defines the Irc::Client class, a class that can handle and
7
+ # dispatch messages based on RFC 2821 (Internet Relay Chat: Client Protocol)
8
+
1
9
  module Irc
2
- # RFC 2812 Internet Relay Chat: Client Protocol
3
- #
4
- RPL_WELCOME=001
10
+ # - The server sends Replies 001 to 004 to a user upon
11
+ # successful registration.
12
+
5
13
  # "Welcome to the Internet Relay Network
6
14
  # <nick>!<user>@<host>"
7
- RPL_YOURHOST=002
15
+ #
16
+ RPL_WELCOME=001
17
+
8
18
  # "Your host is <servername>, running version <ver>"
9
- RPL_CREATED=003
19
+ RPL_YOURHOST=002
20
+
10
21
  # "This server was created <date>"
22
+ RPL_CREATED=003
23
+
24
+ # "<servername> <version> <available user modes> <available channel modes>"
11
25
  RPL_MYINFO=004
12
- # "<servername> <version> <available user modes>
13
- # <available channel modes>"
26
+
27
+ # "005 nick PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
14
28
  #
15
- # - The server sends Replies 001 to 004 to a user upon
16
- # successful registration.
29
+ # defines the capabilities supported by the server.
17
30
  #
18
- # RPL_BOUNCE=005
19
- # # "Try server <server name>, port <port number>"
20
- RPL_ISUPPORT=005
21
- # "005 nick PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
31
+ # Previous RFCs defined message 005 as follows:
22
32
  #
23
33
  # - Sent by the server to a user to suggest an alternative
24
- # server. This is often used when the connection is
25
- # refused because the server is already full.
34
+ # server. This is often used when the connection is
35
+ # refused because the server is already full.
26
36
  #
27
- RPL_USERHOST=302
37
+ # # "Try server <server name>, port <port number>"
38
+ #
39
+ # RPL_BOUNCE=005
40
+ #
41
+ RPL_ISUPPORT=005
42
+
28
43
  # ":*1<reply> *( " " <reply> )"
29
44
  #
30
45
  # - Reply format used by USERHOST to list replies to
31
- # the query list. The reply string is composed as
32
- # follows:
46
+ # the query list. The reply string is composed as
47
+ # follows:
33
48
  #
34
49
  # reply = nickname [ "*" ] "=" ( "+" / "-" ) hostname
35
50
  #
@@ -38,138 +53,158 @@ module Irc
38
53
  # whether the client has set an AWAY message or not
39
54
  # respectively.
40
55
  #
41
- RPL_ISON=303
56
+ RPL_USERHOST=302
57
+
42
58
  # ":*1<nick> *( " " <nick> )"
43
59
  #
44
60
  # - Reply format used by ISON to list replies to the
45
- # query list.
61
+ # query list.
46
62
  #
47
- RPL_AWAY=301
63
+ RPL_ISON=303
64
+
65
+ # - These replies are used with the AWAY command (if
66
+ # allowed). RPL_AWAY is sent to any client sending a
67
+ # PRIVMSG to a client which is away. RPL_AWAY is only
68
+ # sent by the server to which the client is connected.
69
+ # Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
70
+ # client removes and sets an AWAY message.
71
+
48
72
  # "<nick> :<away message>"
49
- RPL_UNAWAY=305
73
+ RPL_AWAY=301
74
+
50
75
  # ":You are no longer marked as being away"
51
- RPL_NOWAWAY=306
76
+ RPL_UNAWAY=305
77
+
52
78
  # ":You have been marked as being away"
53
- #
54
- # - These replies are used with the AWAY command (if
55
- # allowed). RPL_AWAY is sent to any client sending a
56
- # PRIVMSG to a client which is away. RPL_AWAY is only
57
- # sent by the server to which the client is connected.
58
- # Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
59
- # client removes and sets an AWAY message.
60
- #
61
- RPL_WHOISUSER=311
79
+ RPL_NOWAWAY=306
80
+
81
+ # - Replies 311 - 313, 317 - 319 are all replies
82
+ # generated in response to a WHOIS message. Given that
83
+ # there are enough parameters present, the answering
84
+ # server MUST either formulate a reply out of the above
85
+ # numerics (if the query nick is found) or return an
86
+ # error reply. The '*' in RPL_WHOISUSER is there as
87
+ # the literal character and not as a wild card. For
88
+ # each reply set, only RPL_WHOISCHANNELS may appear
89
+ # more than once (for long lists of channel names).
90
+ # The '@' and '+' characters next to the channel name
91
+ # indicate whether a client is a channel operator or
92
+ # has been granted permission to speak on a moderated
93
+ # channel. The RPL_ENDOFWHOIS reply is used to mark
94
+ # the end of processing a WHOIS message.
95
+
62
96
  # "<nick> <user> <host> * :<real name>"
63
- RPL_WHOISSERVER=312
97
+ RPL_WHOISUSER=311
98
+
64
99
  # "<nick> <server> :<server info>"
65
- RPL_WHOISOPERATOR=313
100
+ RPL_WHOISSERVER=312
101
+
66
102
  # "<nick> :is an IRC operator"
67
- RPL_WHOISIDLE=317
103
+ RPL_WHOISOPERATOR=313
104
+
68
105
  # "<nick> <integer> :seconds idle"
69
- RPL_ENDOFWHOIS=318
106
+ RPL_WHOISIDLE=317
107
+
70
108
  # "<nick> :End of WHOIS list"
71
- RPL_WHOISCHANNELS=319
109
+ RPL_ENDOFWHOIS=318
110
+
72
111
  # "<nick> :*( ( "@" / "+" ) <channel> " " )"
73
- #
74
- # - Replies 311 - 313, 317 - 319 are all replies
75
- # generated in response to a WHOIS message. Given that
76
- # there are enough parameters present, the answering
77
- # server MUST either formulate a reply out of the above
78
- # numerics (if the query nick is found) or return an
79
- # error reply. The '*' in RPL_WHOISUSER is there as
80
- # the literal character and not as a wild card. For
81
- # each reply set, only RPL_WHOISCHANNELS may appear
82
- # more than once (for long lists of channel names).
83
- # The '@' and '+' characters next to the channel name
84
- # indicate whether a client is a channel operator or
85
- # has been granted permission to speak on a moderated
86
- # channel. The RPL_ENDOFWHOIS reply is used to mark
87
- # the end of processing a WHOIS message.
88
- #
89
- RPL_WHOWASUSER=314
112
+ RPL_WHOISCHANNELS=319
113
+
114
+ # - When replying to a WHOWAS message, a server MUST use
115
+ # the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
116
+ # ERR_WASNOSUCHNICK for each nickname in the presented
117
+ # list. At the end of all reply batches, there MUST
118
+ # be RPL_ENDOFWHOWAS (even if there was only one reply
119
+ # and it was an error).
120
+
90
121
  # "<nick> <user> <host> * :<real name>"
91
- RPL_ENDOFWHOWAS=369
122
+ RPL_WHOWASUSER=314
123
+
92
124
  # "<nick> :End of WHOWAS"
93
- #
94
- # - When replying to a WHOWAS message, a server MUST use
95
- # the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
96
- # ERR_WASNOSUCHNICK for each nickname in the presented
97
- # list. At the end of all reply batches, there MUST
98
- # be RPL_ENDOFWHOWAS (even if there was only one reply
99
- # and it was an error).
100
- #
101
- RPL_LISTSTART=321
125
+ RPL_ENDOFWHOWAS=369
126
+
127
+ # - Replies RPL_LIST, RPL_LISTEND mark the actual replies
128
+ # with data and end of the server's response to a LIST
129
+ # command. If there are no channels available to return,
130
+ # only the end reply MUST be sent.
131
+
102
132
  # Obsolete. Not used.
103
- #
104
- RPL_LIST=322
133
+ RPL_LISTSTART=321
134
+
105
135
  # "<channel> <# visible> :<topic>"
106
- RPL_LISTEND=323
136
+ RPL_LIST=322
137
+
107
138
  # ":End of LIST"
108
- #
109
- # - Replies RPL_LIST, RPL_LISTEND mark the actual replies
110
- # with data and end of the server's response to a LIST
111
- # command. If there are no channels available to return,
112
- # only the end reply MUST be sent.
113
- #
114
- RPL_UNIQOPIS=325
139
+ RPL_LISTEND=323
140
+
115
141
  # "<channel> <nickname>"
116
- #
117
- RPL_CHANNELMODEIS=324
142
+ RPL_UNIQOPIS=325
143
+
118
144
  # "<channel> <mode> <mode params>"
119
- #
120
- RPL_NOTOPIC=331
145
+ RPL_CHANNELMODEIS=324
146
+
121
147
  # "<channel> :No topic is set"
122
- RPL_TOPIC=332
123
- # "<channel> :<topic>"
124
- #
148
+ RPL_NOTOPIC=331
149
+
125
150
  # - When sending a TOPIC message to determine the
126
- # channel topic, one of two replies is sent. If
127
- # the topic is set, RPL_TOPIC is sent back else
128
- # RPL_NOTOPIC.
129
- #
130
- RPL_TOPIC_INFO=333
151
+ # channel topic, one of two replies is sent. If
152
+ # the topic is set, RPL_TOPIC is sent back else
153
+ # RPL_NOTOPIC.
154
+
155
+ # "<channel> :<topic>"
156
+ RPL_TOPIC=332
157
+
131
158
  # <channel> <set by> <unixtime>
132
- RPL_INVITING=341
159
+ RPL_TOPIC_INFO=333
160
+
133
161
  # "<channel> <nick>"
134
162
  #
135
163
  # - Returned by the server to indicate that the
136
- # attempted INVITE message was successful and is
137
- # being passed onto the end client.
164
+ # attempted INVITE message was successful and is
165
+ # being passed onto the end client.
138
166
  #
139
- RPL_SUMMONING=342
167
+ RPL_INVITING=341
168
+
140
169
  # "<user> :Summoning user to IRC"
141
170
  #
142
171
  # - Returned by a server answering a SUMMON message to
143
- # indicate that it is summoning that user.
172
+ # indicate that it is summoning that user.
144
173
  #
145
- RPL_INVITELIST=346
174
+ RPL_SUMMONING=342
175
+
146
176
  # "<channel> <invitemask>"
147
- RPL_ENDOFINVITELIST=347
177
+ RPL_INVITELIST=346
178
+
148
179
  # "<channel> :End of channel invite list"
149
180
  #
150
181
  # - When listing the 'invitations masks' for a given channel,
151
- # a server is required to send the list back using the
152
- # RPL_INVITELIST and RPL_ENDOFINVITELIST messages. A
153
- # separate RPL_INVITELIST is sent for each active mask.
154
- # After the masks have been listed (or if none present) a
155
- # RPL_ENDOFINVITELIST MUST be sent.
182
+ # a server is required to send the list back using the
183
+ # RPL_INVITELIST and RPL_ENDOFINVITELIST messages. A
184
+ # separate RPL_INVITELIST is sent for each active mask.
185
+ # After the masks have been listed (or if none present) a
186
+ # RPL_ENDOFINVITELIST MUST be sent.
156
187
  #
157
- RPL_EXCEPTLIST=348
188
+ RPL_ENDOFINVITELIST=347
189
+
158
190
  # "<channel> <exceptionmask>"
159
- RPL_ENDOFEXCEPTLIST=349
191
+ RPL_EXCEPTLIST=348
192
+
160
193
  # "<channel> :End of channel exception list"
161
194
  #
162
195
  # - When listing the 'exception masks' for a given channel,
163
- # a server is required to send the list back using the
164
- # RPL_EXCEPTLIST and RPL_ENDOFEXCEPTLIST messages. A
165
- # separate RPL_EXCEPTLIST is sent for each active mask.
166
- # After the masks have been listed (or if none present)
167
- # a RPL_ENDOFEXCEPTLIST MUST be sent.
196
+ # a server is required to send the list back using the
197
+ # RPL_EXCEPTLIST and RPL_ENDOFEXCEPTLIST messages. A
198
+ # separate RPL_EXCEPTLIST is sent for each active mask.
199
+ # After the masks have been listed (or if none present)
200
+ # a RPL_ENDOFEXCEPTLIST MUST be sent.
168
201
  #
169
- RPL_VERSION=351
202
+ RPL_ENDOFEXCEPTLIST=349
203
+
170
204
  # "<version>.<debuglevel> <server> :<comments>"
171
205
  #
172
206
  # - Reply by the server showing its version details.
207
+ #
173
208
  # The <version> is the version of the software being
174
209
  # used (including any patchlevel revisions) and the
175
210
  # <debuglevel> is used to indicate if the server is
@@ -178,276 +213,307 @@ module Irc
178
213
  # The "comments" field may contain any comments about
179
214
  # the version or further version details.
180
215
  #
181
- RPL_WHOREPLY=352
216
+ RPL_VERSION=351
217
+
218
+ # - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
219
+ # to answer a WHO message. The RPL_WHOREPLY is only
220
+ # sent if there is an appropriate match to the WHO
221
+ # query. If there is a list of parameters supplied
222
+ # with a WHO message, a RPL_ENDOFWHO MUST be sent
223
+ # after processing each list item with <name> being
224
+ # the item.
225
+
182
226
  # "<channel> <user> <host> <server> <nick>
183
227
  # ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
184
228
  # :<hopcount> <real name>"
185
229
  #
186
- RPL_ENDOFWHO=315
230
+ RPL_WHOREPLY=352
231
+
187
232
  # "<name> :End of WHO list"
188
- #
189
- # - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
190
- # to answer a WHO message. The RPL_WHOREPLY is only
191
- # sent if there is an appropriate match to the WHO
192
- # query. If there is a list of parameters supplied
193
- # with a WHO message, a RPL_ENDOFWHO MUST be sent
194
- # after processing each list item with <name> being
195
- # the item.
196
- #
197
- RPL_NAMREPLY=353
233
+ RPL_ENDOFWHO=315
234
+
235
+ # - To reply to a NAMES message, a reply pair consisting
236
+ # of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
237
+ # server back to the client. If there is no channel
238
+ # found as in the query, then only RPL_ENDOFNAMES is
239
+ # returned. The exception to this is when a NAMES
240
+ # message is sent with no parameters and all visible
241
+ # channels and contents are sent back in a series of
242
+ # RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
243
+ # the end.
244
+
198
245
  # "( "=" / "*" / "@" ) <channel>
199
246
  # :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
200
247
  # - "@" is used for secret channels, "*" for private
201
248
  # channels, and "=" for others (public channels).
202
249
  #
203
- RPL_ENDOFNAMES=366
250
+ RPL_NAMREPLY=353
251
+
204
252
  # "<channel> :End of NAMES list"
205
- #
206
- # - To reply to a NAMES message, a reply pair consisting
207
- # of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
208
- # server back to the client. If there is no channel
209
- # found as in the query, then only RPL_ENDOFNAMES is
210
- # returned. The exception to this is when a NAMES
211
- # message is sent with no parameters and all visible
212
- # channels and contents are sent back in a series of
213
- # RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
214
- # the end.
215
- #
216
- RPL_LINKS=364
253
+ RPL_ENDOFNAMES=366
254
+
255
+ # - In replying to the LINKS message, a server MUST send
256
+ # replies back using the RPL_LINKS numeric and mark the
257
+ # end of the list using an RPL_ENDOFLINKS reply.
258
+
217
259
  # "<mask> <server> :<hopcount> <server info>"
218
- RPL_ENDOFLINKS=365
260
+ RPL_LINKS=364
261
+
219
262
  # "<mask> :End of LINKS list"
220
- #
221
- # - In replying to the LINKS message, a server MUST send
222
- # replies back using the RPL_LINKS numeric and mark the
223
- # end of the list using an RPL_ENDOFLINKS reply.
224
- #
225
- RPL_BANLIST=367
263
+ RPL_ENDOFLINKS=365
264
+
265
+ # - When listing the active 'bans' for a given channel,
266
+ # a server is required to send the list back using the
267
+ # RPL_BANLIST and RPL_ENDOFBANLIST messages. A separate
268
+ # RPL_BANLIST is sent for each active banmask. After the
269
+ # banmasks have been listed (or if none present) a
270
+ # RPL_ENDOFBANLIST MUST be sent.
271
+
226
272
  # "<channel> <banmask>"
227
- RPL_ENDOFBANLIST=368
273
+ RPL_BANLIST=367
274
+
228
275
  # "<channel> :End of channel ban list"
229
- #
230
- # - When listing the active 'bans' for a given channel,
231
- # a server is required to send the list back using the
232
- # RPL_BANLIST and RPL_ENDOFBANLIST messages. A separate
233
- # RPL_BANLIST is sent for each active banmask. After the
234
- # banmasks have been listed (or if none present) a
235
- # RPL_ENDOFBANLIST MUST be sent.
236
- #
237
- RPL_INFO=371
276
+ RPL_ENDOFBANLIST=368
277
+
278
+ # - A server responding to an INFO message is required to
279
+ # send all its 'info' in a series of RPL_INFO messages
280
+ # with a RPL_ENDOFINFO reply to indicate the end of the
281
+ # replies.
282
+
238
283
  # ":<string>"
239
- RPL_ENDOFINFO=374
284
+ RPL_INFO=371
285
+
240
286
  # ":End of INFO list"
241
- #
242
- # - A server responding to an INFO message is required to
243
- # send all its 'info' in a series of RPL_INFO messages
244
- # with a RPL_ENDOFINFO reply to indicate the end of the
245
- # replies.
246
- #
247
- RPL_MOTDSTART=375
248
- # ":- <server> Message of the day - "
249
- RPL_MOTD=372
250
- # ":- <text>"
251
- RPL_ENDOFMOTD=376
252
- # ":End of MOTD command"
253
- #
287
+ RPL_ENDOFINFO=374
288
+
254
289
  # - When responding to the MOTD message and the MOTD file
255
290
  # is found, the file is displayed line by line, with
256
291
  # each line no longer than 80 characters, using
257
292
  # RPL_MOTD format replies. These MUST be surrounded
258
293
  # by a RPL_MOTDSTART (before the RPL_MOTDs) and an
259
294
  # RPL_ENDOFMOTD (after).
260
- #
261
- RPL_YOUREOPER=381
295
+
296
+ # ":- <server> Message of the day - "
297
+ RPL_MOTDSTART=375
298
+
299
+ # ":- <text>"
300
+ RPL_MOTD=372
301
+
302
+ # ":End of MOTD command"
303
+ RPL_ENDOFMOTD=376
304
+
262
305
  # ":You are now an IRC operator"
263
306
  #
264
307
  # - RPL_YOUREOPER is sent back to a client which has
265
- # just successfully issued an OPER message and gained
266
- # operator status.
308
+ # just successfully issued an OPER message and gained
309
+ # operator status.
267
310
  #
268
- RPL_REHASHING=382
311
+ RPL_YOUREOPER=381
312
+
269
313
  # "<config file> :Rehashing"
270
314
  #
271
315
  # - If the REHASH option is used and an operator sends
272
- # a REHASH message, an RPL_REHASHING is sent back to
273
- # the operator.
316
+ # a REHASH message, an RPL_REHASHING is sent back to
317
+ # the operator.
274
318
  #
275
- RPL_YOURESERVICE=383
319
+ RPL_REHASHING=382
320
+
276
321
  # "You are service <servicename>"
277
322
  #
278
323
  # - Sent by the server to a service upon successful
279
- # registration.
324
+ # registration.
280
325
  #
281
- RPL_TIME=391
326
+ RPL_YOURESERVICE=383
327
+
282
328
  # "<server> :<string showing server's local time>"
283
329
  #
284
330
  # - When replying to the TIME message, a server MUST send
285
- # the reply using the RPL_TIME format above. The string
286
- # showing the time need only contain the correct day and
287
- # time there. There is no further requirement for the
288
- # time string.
331
+ # the reply using the RPL_TIME format above. The string
332
+ # showing the time need only contain the correct day and
333
+ # time there. There is no further requirement for the
334
+ # time string.
289
335
  #
290
- RPL_USERSSTART=392
336
+ RPL_TIME=391
337
+
338
+ # - If the USERS message is handled by a server, the
339
+ # replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
340
+ # RPL_NOUSERS are used. RPL_USERSSTART MUST be sent
341
+ # first, following by either a sequence of RPL_USERS
342
+ # or a single RPL_NOUSER. Following this is
343
+ # RPL_ENDOFUSERS.
344
+
291
345
  # ":UserID Terminal Host"
292
- RPL_USERS=393
346
+ RPL_USERSSTART=392
347
+
293
348
  # ":<username> <ttyline> <hostname>"
294
- RPL_ENDOFUSERS=394
349
+ RPL_USERS=393
350
+
295
351
  # ":End of users"
296
- RPL_NOUSERS=395
352
+ RPL_ENDOFUSERS=394
353
+
297
354
  # ":Nobody logged in"
355
+ RPL_NOUSERS=395
356
+
357
+ # - The RPL_TRACE* are all returned by the server in
358
+ # response to the TRACE message. How many are
359
+ # returned is dependent on the TRACE message and
360
+ # whether it was sent by an operator or not. There
361
+ # is no predefined order for which occurs first.
362
+ # Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
363
+ # RPL_TRACEHANDSHAKE are all used for connections
364
+ # which have not been fully established and are either
365
+ # unknown, still attempting to connect or in the
366
+ # process of completing the 'server handshake'.
367
+ # RPL_TRACELINK is sent by any server which handles
368
+ # a TRACE message and has to pass it on to another
369
+ # server. The list of RPL_TRACELINKs sent in
370
+ # response to a TRACE command traversing the IRC
371
+ # network should reflect the actual connectivity of
372
+ # the servers themselves along that path.
298
373
  #
299
- # - If the USERS message is handled by a server, the
300
- # replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
301
- # RPL_NOUSERS are used. RPL_USERSSTART MUST be sent
302
- # first, following by either a sequence of RPL_USERS
303
- # or a single RPL_NOUSER. Following this is
304
- # RPL_ENDOFUSERS.
305
- #
306
- RPL_TRACELINK=200
374
+ # RPL_TRACENEWTYPE is to be used for any connection
375
+ # which does not fit in the other categories but is
376
+ # being displayed anyway.
377
+ # RPL_TRACEEND is sent to indicate the end of the list.
378
+
307
379
  # "Link <version & debug level> <destination>
308
380
  # <next server> V<protocol version>
309
381
  # <link uptime in seconds> <backstream sendq>
310
382
  # <upstream sendq>"
311
- RPL_TRACECONNECTING=201
383
+ RPL_TRACELINK=200
384
+
312
385
  # "Try. <class> <server>"
313
- RPL_TRACEHANDSHAKE=202
386
+ RPL_TRACECONNECTING=201
387
+
314
388
  # "H.S. <class> <server>"
315
- RPL_TRACEUNKNOWN=203
389
+ RPL_TRACEHANDSHAKE=202
390
+
316
391
  # "???? <class> [<client IP address in dot form>]"
317
- RPL_TRACEOPERATOR=204
392
+ RPL_TRACEUNKNOWN=203
393
+
318
394
  # "Oper <class> <nick>"
319
- RPL_TRACEUSER=205
395
+ RPL_TRACEOPERATOR=204
396
+
320
397
  # "User <class> <nick>"
321
- RPL_TRACESERVER=206
398
+ RPL_TRACEUSER=205
399
+
322
400
  # "Serv <class> <int>S <int>C <server>
323
401
  # <nick!user|*!*>@<host|server> V<protocol version>"
324
- RPL_TRACESERVICE=207
402
+ RPL_TRACESERVER=206
403
+
325
404
  # "Service <class> <name> <type> <active type>"
326
- RPL_TRACENEWTYPE=208
405
+ RPL_TRACESERVICE=207
406
+
327
407
  # "<newtype> 0 <client name>"
328
- RPL_TRACECLASS=209
408
+ RPL_TRACENEWTYPE=208
409
+
329
410
  # "Class <class> <count>"
330
- RPL_TRACERECONNECT=210
411
+ RPL_TRACECLASS=209
412
+
331
413
  # Unused.
332
- RPL_TRACELOG=261
414
+ RPL_TRACERECONNECT=210
415
+
333
416
  # "File <logfile> <debug level>"
334
- RPL_TRACEEND=262
417
+ RPL_TRACELOG=261
418
+
335
419
  # "<server name> <version & debug level> :End of TRACE"
336
- #
337
- # - The RPL_TRACE* are all returned by the server in
338
- # response to the TRACE message. How many are
339
- # returned is dependent on the TRACE message and
340
- # whether it was sent by an operator or not. There
341
- # is no predefined order for which occurs first.
342
- # Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
343
- # RPL_TRACEHANDSHAKE are all used for connections
344
- # which have not been fully established and are either
345
- # unknown, still attempting to connect or in the
346
- # process of completing the 'server handshake'.
347
- # RPL_TRACELINK is sent by any server which handles
348
- # a TRACE message and has to pass it on to another
349
- # server. The list of RPL_TRACELINKs sent in
350
- # response to a TRACE command traversing the IRC
351
- # network should reflect the actual connectivity of
352
- # the servers themselves along that path.
353
- #
354
- # RPL_TRACENEWTYPE is to be used for any connection
355
- # which does not fit in the other categories but is
356
- # being displayed anyway.
357
- # RPL_TRACEEND is sent to indicate the end of the list.
358
- #
359
- RPL_LOCALUSERS=265
420
+ RPL_TRACEEND=262
421
+
360
422
  # ":Current local users: 3 Max: 4"
361
- RPL_GLOBALUSERS=266
423
+ RPL_LOCALUSERS=265
424
+
362
425
  # ":Current global users: 3 Max: 4"
363
- RPL_STATSCONN=250
426
+ RPL_GLOBALUSERS=266
427
+
364
428
  # "::Highest connection count: 4 (4 clients) (251 since server was
365
429
  # (re)started)"
366
- RPL_STATSLINKINFO=211
430
+ RPL_STATSCONN=250
431
+
367
432
  # "<linkname> <sendq> <sent messages>
368
433
  # <sent Kbytes> <received messages>
369
434
  # <received Kbytes> <time open>"
370
435
  #
371
436
  # - reports statistics on a connection. <linkname>
372
- # identifies the particular connection, <sendq> is
373
- # the amount of data that is queued and waiting to be
374
- # sent <sent messages> the number of messages sent,
375
- # and <sent Kbytes> the amount of data sent, in
376
- # Kbytes. <received messages> and <received Kbytes>
377
- # are the equivalent of <sent messages> and <sent
378
- # Kbytes> for received data, respectively. <time
379
- # open> indicates how long ago the connection was
380
- # opened, in seconds.
437
+ # identifies the particular connection, <sendq> is
438
+ # the amount of data that is queued and waiting to be
439
+ # sent <sent messages> the number of messages sent,
440
+ # and <sent Kbytes> the amount of data sent, in
441
+ # Kbytes. <received messages> and <received Kbytes>
442
+ # are the equivalent of <sent messages> and <sent
443
+ # Kbytes> for received data, respectively. <time
444
+ # open> indicates how long ago the connection was
445
+ # opened, in seconds.
381
446
  #
382
- RPL_STATSCOMMANDS=212
447
+ RPL_STATSLINKINFO=211
448
+
383
449
  # "<command> <count> <byte count> <remote count>"
384
450
  #
385
451
  # - reports statistics on commands usage.
386
452
  #
387
- RPL_ENDOFSTATS=219
453
+ RPL_STATSCOMMANDS=212
454
+
388
455
  # "<stats letter> :End of STATS report"
389
456
  #
390
- RPL_STATSUPTIME=242
457
+ RPL_ENDOFSTATS=219
458
+
391
459
  # ":Server Up %d days %d:%02d:%02d"
392
460
  #
393
461
  # - reports the server uptime.
394
462
  #
395
- RPL_STATSOLINE=243
463
+ RPL_STATSUPTIME=242
464
+
396
465
  # "O <hostmask> * <name>"
397
466
  #
398
467
  # - reports the allowed hosts from where user may become IRC
399
- # operators.
468
+ # operators.
400
469
  #
401
- RPL_UMODEIS=221
470
+ RPL_STATSOLINE=243
471
+
402
472
  # "<user mode string>"
403
473
  #
404
474
  # - To answer a query about a client's own mode,
405
- # RPL_UMODEIS is sent back.
475
+ # RPL_UMODEIS is sent back.
406
476
  #
407
- RPL_SERVLIST=234
477
+ RPL_UMODEIS=221
478
+
479
+ # - When listing services in reply to a SERVLIST message,
480
+ # a server is required to send the list back using the
481
+ # RPL_SERVLIST and RPL_SERVLISTEND messages. A separate
482
+ # RPL_SERVLIST is sent for each service. After the
483
+ # services have been listed (or if none present) a
484
+ # RPL_SERVLISTEND MUST be sent.
485
+
408
486
  # "<name> <server> <mask> <type> <hopcount> <info>"
409
- #
410
- RPL_SERVLISTEND=235
487
+ RPL_SERVLIST=234
488
+
411
489
  # "<mask> <type> :End of service listing"
412
- #
413
- # - When listing services in reply to a SERVLIST message,
414
- # a server is required to send the list back using the
415
- # RPL_SERVLIST and RPL_SERVLISTEND messages. A separate
416
- # RPL_SERVLIST is sent for each service. After the
417
- # services have been listed (or if none present) a
418
- # RPL_SERVLISTEND MUST be sent.
419
- #
420
- RPL_LUSERCLIENT=251
490
+ RPL_SERVLISTEND=235
491
+
492
+ # - In processing an LUSERS message, the server
493
+ # sends a set of replies from RPL_LUSERCLIENT,
494
+ # RPL_LUSEROP, RPL_USERUNKNOWN,
495
+ # RPL_LUSERCHANNELS and RPL_LUSERME. When
496
+ # replying, a server MUST send back
497
+ # RPL_LUSERCLIENT and RPL_LUSERME. The other
498
+ # replies are only sent back if a non-zero count
499
+ # is found for them.
500
+
421
501
  # ":There are <integer> users and <integer>
422
502
  # services on <integer> servers"
423
- RPL_LUSEROP=252
503
+ RPL_LUSERCLIENT=251
504
+
424
505
  # "<integer> :operator(s) online"
425
- RPL_LUSERUNKNOWN=253
506
+ RPL_LUSEROP=252
507
+
426
508
  # "<integer> :unknown connection(s)"
427
- RPL_LUSERCHANNELS=254
509
+ RPL_LUSERUNKNOWN=253
510
+
428
511
  # "<integer> :channels formed"
512
+ RPL_LUSERCHANNELS=254
513
+
514
+ # ":I have <integer> clients and <integer> servers"
429
515
  RPL_LUSERME=255
430
- # ":I have <integer> clients and <integer>
431
- # servers"
432
- #
433
- # - In processing an LUSERS message, the server
434
- # sends a set of replies from RPL_LUSERCLIENT,
435
- # RPL_LUSEROP, RPL_USERUNKNOWN,
436
- # RPL_LUSERCHANNELS and RPL_LUSERME. When
437
- # replying, a server MUST send back
438
- # RPL_LUSERCLIENT and RPL_LUSERME. The other
439
- # replies are only sent back if a non-zero count
440
- # is found for them.
441
- #
442
- RPL_ADMINME=256
443
- # "<server> :Administrative info"
444
- RPL_ADMINLOC1=257
445
- # ":<admin info>"
446
- RPL_ADMINLOC2=258
447
- # ":<admin info>"
448
- RPL_ADMINEMAIL=259
449
- # ":<admin info>"
450
- #
516
+
451
517
  # - When replying to an ADMIN message, a server
452
518
  # is expected to use replies RPL_ADMINME
453
519
  # through to RPL_ADMINEMAIL and provide a text
@@ -458,323 +524,385 @@ module Irc
458
524
  # and finally the administrative contact for the
459
525
  # server (an email address here is REQUIRED)
460
526
  # in RPL_ADMINEMAIL.
461
- #
462
- RPL_TRYAGAIN=263
527
+
528
+ # "<server> :Administrative info"
529
+ RPL_ADMINME=256
530
+
531
+ # ":<admin info>"
532
+ RPL_ADMINLOC1=257
533
+
534
+ # ":<admin info>"
535
+ RPL_ADMINLOC2=258
536
+
537
+ # ":<admin info>"
538
+ RPL_ADMINEMAIL=259
539
+
463
540
  # "<command> :Please wait a while and try again."
464
541
  #
465
542
  # - When a server drops a command without processing it,
466
- # it MUST use the reply RPL_TRYAGAIN to inform the
467
- # originating client.
468
- #
543
+ # it MUST use the reply RPL_TRYAGAIN to inform the
544
+ # originating client.
545
+ RPL_TRYAGAIN=263
546
+
469
547
  # 5.2 Error Replies
470
548
  #
471
549
  # Error replies are found in the range from 400 to 599.
472
- #
473
- ERR_NOSUCHNICK=401
550
+
474
551
  # "<nickname> :No such nick/channel"
475
552
  #
476
553
  # - Used to indicate the nickname parameter supplied to a
477
- # command is currently unused.
554
+ # command is currently unused.
478
555
  #
479
- ERR_NOSUCHSERVER=402
556
+ ERR_NOSUCHNICK=401
557
+
480
558
  # "<server name> :No such server"
481
559
  #
482
560
  # - Used to indicate the server name given currently
483
- # does not exist.
561
+ # does not exist.
484
562
  #
485
- ERR_NOSUCHCHANNEL=403
563
+ ERR_NOSUCHSERVER=402
564
+
486
565
  # "<channel name> :No such channel"
487
566
  #
488
567
  # - Used to indicate the given channel name is invalid.
489
568
  #
490
- ERR_CANNOTSENDTOCHAN=404
569
+ ERR_NOSUCHCHANNEL=403
570
+
491
571
  # "<channel name> :Cannot send to channel"
492
572
  #
493
573
  # - Sent to a user who is either (a) not on a channel
494
- # which is mode +n or (b) not a chanop (or mode +v) on
495
- # a channel which has mode +m set or where the user is
496
- # banned and is trying to send a PRIVMSG message to
497
- # that channel.
574
+ # which is mode +n or (b) not a chanop (or mode +v) on
575
+ # a channel which has mode +m set or where the user is
576
+ # banned and is trying to send a PRIVMSG message to
577
+ # that channel.
498
578
  #
499
- ERR_TOOMANYCHANNELS=405
579
+ ERR_CANNOTSENDTOCHAN=404
580
+
500
581
  # "<channel name> :You have joined too many channels"
501
582
  #
502
583
  # - Sent to a user when they have joined the maximum
503
- # number of allowed channels and they try to join
504
- # another channel.
584
+ # number of allowed channels and they try to join
585
+ # another channel.
505
586
  #
506
- ERR_WASNOSUCHNICK=406
587
+ ERR_TOOMANYCHANNELS=405
588
+
507
589
  # "<nickname> :There was no such nickname"
508
590
  #
509
591
  # - Returned by WHOWAS to indicate there is no history
510
- # information for that nickname.
592
+ # information for that nickname.
511
593
  #
512
- ERR_TOOMANYTARGETS=407
594
+ ERR_WASNOSUCHNICK=406
595
+
513
596
  # "<target> :<error code> recipients. <abort message>"
514
597
  #
515
598
  # - Returned to a client which is attempting to send a
516
- # PRIVMSG/NOTICE using the user@host destination format
517
- # and for a user@host which has several occurrences.
599
+ # PRIVMSG/NOTICE using the user@host destination format
600
+ # and for a user@host which has several occurrences.
518
601
  #
519
602
  # - Returned to a client which trying to send a
520
- # PRIVMSG/NOTICE to too many recipients.
603
+ # PRIVMSG/NOTICE to too many recipients.
521
604
  #
522
605
  # - Returned to a client which is attempting to JOIN a safe
523
- # channel using the shortname when there are more than one
524
- # such channel.
606
+ # channel using the shortname when there are more than one
607
+ # such channel.
525
608
  #
526
- ERR_NOSUCHSERVICE=408
609
+ ERR_TOOMANYTARGETS=407
610
+
527
611
  # "<service name> :No such service"
528
612
  #
529
613
  # - Returned to a client which is attempting to send a SQUERY
530
- # to a service which does not exist.
614
+ # to a service which does not exist.
531
615
  #
532
- ERR_NOORIGIN=409
616
+ ERR_NOSUCHSERVICE=408
617
+
533
618
  # ":No origin specified"
534
619
  #
535
620
  # - PING or PONG message missing the originator parameter.
536
621
  #
537
- ERR_NORECIPIENT=411
622
+ ERR_NOORIGIN=409
623
+
538
624
  # ":No recipient given (<command>)"
539
- ERR_NOTEXTTOSEND=412
625
+ ERR_NORECIPIENT=411
626
+
627
+ # - 412 - 415 are returned by PRIVMSG to indicate that
628
+ # the message wasn't delivered for some reason.
629
+ # ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
630
+ # are returned when an invalid use of
631
+ # "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
632
+
540
633
  # ":No text to send"
541
- ERR_NOTOPLEVEL=413
634
+ ERR_NOTEXTTOSEND=412
635
+
542
636
  # "<mask> :No toplevel domain specified"
543
- ERR_WILDTOPLEVEL=414
637
+ ERR_NOTOPLEVEL=413
638
+
544
639
  # "<mask> :Wildcard in toplevel domain"
545
- ERR_BADMASK=415
640
+ ERR_WILDTOPLEVEL=414
641
+
546
642
  # "<mask> :Bad Server/host mask"
547
- #
548
- # - 412 - 415 are returned by PRIVMSG to indicate that
549
- # the message wasn't delivered for some reason.
550
- # ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
551
- # are returned when an invalid use of
552
- # "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
553
- #
554
- ERR_UNKNOWNCOMMAND=421
643
+ ERR_BADMASK=415
644
+
555
645
  # "<command> :Unknown command"
556
646
  #
557
647
  # - Returned to a registered client to indicate that the
558
- # command sent is unknown by the server.
648
+ # command sent is unknown by the server.
559
649
  #
560
- ERR_NOMOTD=422
650
+ ERR_UNKNOWNCOMMAND=421
651
+
561
652
  # ":MOTD File is missing"
562
653
  #
563
654
  # - Server's MOTD file could not be opened by the server.
564
655
  #
565
- ERR_NOADMININFO=423
656
+ ERR_NOMOTD=422
657
+
566
658
  # "<server> :No administrative info available"
567
659
  #
568
660
  # - Returned by a server in response to an ADMIN message
569
- # when there is an error in finding the appropriate
570
- # information.
661
+ # when there is an error in finding the appropriate
662
+ # information.
571
663
  #
572
- ERR_FILEERROR=424
664
+ ERR_NOADMININFO=423
665
+
573
666
  # ":File error doing <file op> on <file>"
574
667
  #
575
668
  # - Generic error message used to report a failed file
576
- # operation during the processing of a message.
669
+ # operation during the processing of a message.
577
670
  #
578
- ERR_NONICKNAMEGIVEN=431
671
+ ERR_FILEERROR=424
672
+
579
673
  # ":No nickname given"
580
674
  #
581
675
  # - Returned when a nickname parameter expected for a
582
- # command and isn't found.
676
+ # command and isn't found.
583
677
  #
584
- ERR_ERRONEUSNICKNAME=432
678
+ ERR_NONICKNAMEGIVEN=431
679
+
585
680
  # "<nick> :Erroneous nickname"
586
681
  #
587
682
  # - Returned after receiving a NICK message which contains
588
- # characters which do not fall in the defined set. See
589
- # section 2.3.1 for details on valid nicknames.
683
+ # characters which do not fall in the defined set. See
684
+ # section 2.3.1 for details on valid nicknames.
590
685
  #
591
- ERR_NICKNAMEINUSE=433
686
+ ERR_ERRONEUSNICKNAME=432
687
+
592
688
  # "<nick> :Nickname is already in use"
593
689
  #
594
690
  # - Returned when a NICK message is processed that results
595
- # in an attempt to change to a currently existing
596
- # nickname.
691
+ # in an attempt to change to a currently existing
692
+ # nickname.
597
693
  #
598
- ERR_NICKCOLLISION=436
694
+ ERR_NICKNAMEINUSE=433
695
+
599
696
  # "<nick> :Nickname collision KILL from <user>@<host>"
600
697
  #
601
698
  # - Returned by a server to a client when it detects a
602
- # nickname collision (registered of a NICK that
603
- # already exists by another server).
699
+ # nickname collision (registered of a NICK that
700
+ # already exists by another server).
604
701
  #
605
- ERR_UNAVAILRESOURCE=437
702
+ ERR_NICKCOLLISION=436
703
+
606
704
  # "<nick/channel> :Nick/channel is temporarily unavailable"
607
705
  #
608
706
  # - Returned by a server to a user trying to join a channel
609
- # currently blocked by the channel delay mechanism.
707
+ # currently blocked by the channel delay mechanism.
610
708
  #
611
709
  # - Returned by a server to a user trying to change nickname
612
- # when the desired nickname is blocked by the nick delay
613
- # mechanism.
710
+ # when the desired nickname is blocked by the nick delay
711
+ # mechanism.
614
712
  #
615
- ERR_USERNOTINCHANNEL=441
713
+ ERR_UNAVAILRESOURCE=437
714
+
616
715
  # "<nick> <channel> :They aren't on that channel"
617
716
  #
618
717
  # - Returned by the server to indicate that the target
619
- # user of the command is not on the given channel.
718
+ # user of the command is not on the given channel.
620
719
  #
621
- ERR_NOTONCHANNEL=442
720
+ ERR_USERNOTINCHANNEL=441
721
+
622
722
  # "<channel> :You're not on that channel"
623
723
  #
624
724
  # - Returned by the server whenever a client tries to
625
- # perform a channel affecting command for which the
626
- # client isn't a member.
725
+ # perform a channel affecting command for which the
726
+ # client isn't a member.
627
727
  #
628
- ERR_USERONCHANNEL=443
728
+ ERR_NOTONCHANNEL=442
729
+
629
730
  # "<user> <channel> :is already on channel"
630
731
  #
631
732
  # - Returned when a client tries to invite a user to a
632
- # channel they are already on.
733
+ # channel they are already on.
633
734
  #
634
- ERR_NOLOGIN=444
735
+ ERR_USERONCHANNEL=443
736
+
635
737
  # "<user> :User not logged in"
636
738
  #
637
739
  # - Returned by the summon after a SUMMON command for a
638
- # user was unable to be performed since they were not
639
- # logged in.
740
+ # user was unable to be performed since they were not
741
+ # logged in.
640
742
  #
641
- #
642
- ERR_SUMMONDISABLED=445
743
+ ERR_NOLOGIN=444
744
+
643
745
  # ":SUMMON has been disabled"
644
746
  #
645
747
  # - Returned as a response to the SUMMON command. MUST be
646
- # returned by any server which doesn't implement it.
748
+ # returned by any server which doesn't implement it.
647
749
  #
648
- ERR_USERSDISABLED=446
750
+ ERR_SUMMONDISABLED=445
751
+
649
752
  # ":USERS has been disabled"
650
753
  #
651
754
  # - Returned as a response to the USERS command. MUST be
652
- # returned by any server which does not implement it.
755
+ # returned by any server which does not implement it.
653
756
  #
654
- ERR_NOTREGISTERED=451
757
+ ERR_USERSDISABLED=446
758
+
655
759
  # ":You have not registered"
656
760
  #
657
761
  # - Returned by the server to indicate that the client
658
- # MUST be registered before the server will allow it
659
- # to be parsed in detail.
762
+ # MUST be registered before the server will allow it
763
+ # to be parsed in detail.
660
764
  #
661
- ERR_NEEDMOREPARAMS=461
765
+ ERR_NOTREGISTERED=451
766
+
662
767
  # "<command> :Not enough parameters"
663
768
  #
664
769
  # - Returned by the server by numerous commands to
665
- # indicate to the client that it didn't supply enough
666
- # parameters.
770
+ # indicate to the client that it didn't supply enough
771
+ # parameters.
667
772
  #
668
- ERR_ALREADYREGISTRED=462
773
+ ERR_NEEDMOREPARAMS=461
774
+
669
775
  # ":Unauthorized command (already registered)"
670
776
  #
671
777
  # - Returned by the server to any link which tries to
672
- # change part of the registered details (such as
673
- # password or user details from second USER message).
778
+ # change part of the registered details (such as
779
+ # password or user details from second USER message).
674
780
  #
675
- ERR_NOPERMFORHOST=463
781
+ ERR_ALREADYREGISTRED=462
782
+
676
783
  # ":Your host isn't among the privileged"
677
784
  #
678
785
  # - Returned to a client which attempts to register with
679
- # a server which does not been setup to allow
680
- # connections from the host the attempted connection
681
- # is tried.
786
+ # a server which does not been setup to allow
787
+ # connections from the host the attempted connection
788
+ # is tried.
682
789
  #
683
- ERR_PASSWDMISMATCH=464
790
+ ERR_NOPERMFORHOST=463
791
+
684
792
  # ":Password incorrect"
685
793
  #
686
794
  # - Returned to indicate a failed attempt at registering
687
- # a connection for which a password was required and
688
- # was either not given or incorrect.
795
+ # a connection for which a password was required and
796
+ # was either not given or incorrect.
689
797
  #
690
- ERR_YOUREBANNEDCREEP=465
798
+ ERR_PASSWDMISMATCH=464
799
+
691
800
  # ":You are banned from this server"
692
801
  #
693
802
  # - Returned after an attempt to connect and register
694
- # yourself with a server which has been setup to
695
- # explicitly deny connections to you.
696
- #
697
- ERR_YOUWILLBEBANNED=466
803
+ # yourself with a server which has been setup to
804
+ # explicitly deny connections to you.
698
805
  #
806
+ ERR_YOUREBANNEDCREEP=465
807
+
699
808
  # - Sent by a server to a user to inform that access to the
700
- # server will soon be denied.
809
+ # server will soon be denied.
701
810
  #
702
- ERR_KEYSET=467
811
+ ERR_YOUWILLBEBANNED=466
812
+
703
813
  # "<channel> :Channel key already set"
704
- ERR_CHANNELISFULL=471
814
+ ERR_KEYSET=467
815
+
705
816
  # "<channel> :Cannot join channel (+l)"
706
- ERR_UNKNOWNMODE=472
817
+ ERR_CHANNELISFULL=471
818
+
707
819
  # "<char> :is unknown mode char to me for <channel>"
708
- ERR_INVITEONLYCHAN=473
820
+ ERR_UNKNOWNMODE=472
821
+
709
822
  # "<channel> :Cannot join channel (+i)"
710
- ERR_BANNEDFROMCHAN=474
823
+ ERR_INVITEONLYCHAN=473
824
+
711
825
  # "<channel> :Cannot join channel (+b)"
712
- ERR_BADCHANNELKEY=475
826
+ ERR_BANNEDFROMCHAN=474
827
+
713
828
  # "<channel> :Cannot join channel (+k)"
714
- ERR_BADCHANMASK=476
829
+ ERR_BADCHANNELKEY=475
830
+
715
831
  # "<channel> :Bad Channel Mask"
716
- ERR_NOCHANMODES=477
832
+ ERR_BADCHANMASK=476
833
+
717
834
  # "<channel> :Channel doesn't support modes"
718
- ERR_BANLISTFULL=478
835
+ ERR_NOCHANMODES=477
836
+
719
837
  # "<channel> <char> :Channel list is full"
720
838
  #
721
- ERR_NOPRIVILEGES=481
839
+ ERR_BANLISTFULL=478
840
+
722
841
  # ":Permission Denied- You're not an IRC operator"
723
842
  #
724
843
  # - Any command requiring operator privileges to operate
725
- # MUST return this error to indicate the attempt was
726
- # unsuccessful.
844
+ # MUST return this error to indicate the attempt was
845
+ # unsuccessful.
727
846
  #
728
- ERR_CHANOPRIVSNEEDED=482
847
+ ERR_NOPRIVILEGES=481
848
+
729
849
  # "<channel> :You're not channel operator"
730
850
  #
731
851
  # - Any command requiring 'chanop' privileges (such as
732
- # MODE messages) MUST return this error if the client
733
- # making the attempt is not a chanop on the specified
734
- # channel.
852
+ # MODE messages) MUST return this error if the client
853
+ # making the attempt is not a chanop on the specified
854
+ # channel.
735
855
  #
736
856
  #
737
- ERR_CANTKILLSERVER=483
857
+ ERR_CHANOPRIVSNEEDED=482
858
+
738
859
  # ":You can't kill a server!"
739
860
  #
740
861
  # - Any attempts to use the KILL command on a server
741
- # are to be refused and this error returned directly
742
- # to the client.
862
+ # are to be refused and this error returned directly
863
+ # to the client.
743
864
  #
744
- ERR_RESTRICTED=484
865
+ ERR_CANTKILLSERVER=483
866
+
745
867
  # ":Your connection is restricted!"
746
868
  #
747
869
  # - Sent by the server to a user upon connection to indicate
748
- # the restricted nature of the connection (user mode "+r").
870
+ # the restricted nature of the connection (user mode "+r").
749
871
  #
750
- ERR_UNIQOPPRIVSNEEDED=485
872
+ ERR_RESTRICTED=484
873
+
751
874
  # ":You're not the original channel operator"
752
875
  #
753
876
  # - Any MODE requiring "channel creator" privileges MUST
754
- # return this error if the client making the attempt is not
755
- # a chanop on the specified channel.
877
+ # return this error if the client making the attempt is not
878
+ # a chanop on the specified channel.
756
879
  #
757
- ERR_NOOPERHOST=491
880
+ ERR_UNIQOPPRIVSNEEDED=485
881
+
758
882
  # ":No O-lines for your host"
759
883
  #
760
884
  # - If a client sends an OPER message and the server has
761
- # not been configured to allow connections from the
762
- # client's host as an operator, this error MUST be
763
- # returned.
885
+ # not been configured to allow connections from the
886
+ # client's host as an operator, this error MUST be
887
+ # returned.
764
888
  #
765
- ERR_UMODEUNKNOWNFLAG=501
889
+ ERR_NOOPERHOST=491
890
+
766
891
  # ":Unknown MODE flag"
767
892
  #
768
893
  # - Returned by the server to indicate that a MODE
769
- # message was sent with a nickname parameter and that
770
- # the a mode flag sent was not recognized.
894
+ # message was sent with a nickname parameter and that
895
+ # the a mode flag sent was not recognized.
771
896
  #
772
- ERR_USERSDONTMATCH=502
897
+ ERR_UMODEUNKNOWNFLAG=501
898
+
773
899
  # ":Cannot change mode for other users"
774
900
  #
775
901
  # - Error sent to any user trying to view or change the
776
- # user mode for a user other than themselves.
902
+ # user mode for a user other than themselves.
777
903
  #
904
+ ERR_USERSDONTMATCH=502
905
+
778
906
  # 5.3 Reserved numerics
779
907
  #
780
908
  # These numerics are not described above since they fall into one of
@@ -785,7 +913,8 @@ module Irc
785
913
  # 2. reserved for future planned use;
786
914
  #
787
915
  # 3. in current use but are part of a non-generic 'feature' of
788
- # the current IRC server.
916
+ # the current IRC server.
917
+ #
789
918
  RPL_SERVICEINFO=231
790
919
  RPL_ENDOFSERVICES=232
791
920
  RPL_SERVICE=233
@@ -811,14 +940,33 @@ module Irc
811
940
  ERR_NOSERVICEHOST=492
812
941
  RPL_DATASTR=290
813
942
 
814
- # implements RFC 2812 and prior IRC RFCs.
815
- # clients register handler proc{}s for different server events and IrcClient
816
- # handles dispatch
817
- class IrcClient
818
- # create a new IrcClient instance
943
+ # Implements RFC 2812 and prior IRC RFCs.
944
+ #
945
+ # Clients should register Proc{}s to handle the various server events, and
946
+ # the Client class will handle dispatch.
947
+ class Client
948
+
949
+ # the Server we're connected to
950
+ attr_reader :server
951
+ # the User representing us on that server
952
+ attr_reader :user
953
+
954
+ # Create a new Client instance
819
955
  def initialize
956
+ @server = Server.new # The Server
957
+ @user = @server.user("*!*@*") # The User representing the client on this Server
958
+
820
959
  @handlers = Hash.new
821
- @users = Array.new
960
+
961
+ # This is used by some messages to build lists of users that
962
+ # will be delegated when the ENDOF... message is received
963
+ @tmpusers = []
964
+ end
965
+
966
+ # Clear the server and reset the user
967
+ def reset
968
+ @server.clear
969
+ @user = @server.user("*!*@*")
822
970
  end
823
971
 
824
972
  # key:: server event to handle
@@ -827,8 +975,13 @@ module Irc
827
975
  #
828
976
  # ==server events currently supported:
829
977
  #
830
- # created:: when the server was started
978
+ # TODO handle errors ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL
979
+ # TODO handle errors ERR_CHANOPRIVSNEEDED, ERR_CANNOTSENDTOCHAN
980
+ #
981
+ # welcome:: server welcome message on connect
831
982
  # yourhost:: your host details (on connection)
983
+ # created:: when the server was started
984
+ # isupport:: information about what this server supports
832
985
  # ping:: server pings you (default handler returns a pong)
833
986
  # nicktaken:: you tried to change nick to one that's in use
834
987
  # badnick:: you tried to change nick to one that's invalid
@@ -836,7 +989,6 @@ module Irc
836
989
  # topicinfo:: on joining a channel or asking for the topic, tells you
837
990
  # who set it and when
838
991
  # names:: server sends list of channel members when you join
839
- # welcome:: server welcome message on connect
840
992
  # motd:: server message of the day
841
993
  # privmsg:: privmsg, the core of IRC, a message to you from someone
842
994
  # public:: optionally instead of getting privmsg you can hook to only
@@ -869,17 +1021,35 @@ module Irc
869
1021
  data = Hash.new
870
1022
  data[:serverstring] = serverstring
871
1023
 
872
- unless serverstring =~ /^(:(\S+)\s)?(\S+)(\s(.*))?/
873
- raise "Unparseable Server Message!!!: #{serverstring}"
1024
+ unless serverstring.chomp =~ /^(:(\S+)\s)?(\S+)(\s(.*))?$/
1025
+ raise "Unparseable Server Message!!!: #{serverstring.inspect}"
874
1026
  end
875
1027
 
876
1028
  prefix, command, params = $2, $3, $5
877
1029
 
878
1030
  if prefix != nil
879
- data[:source] = prefix
880
- if prefix =~ /^(\S+)!(\S+)$/
881
- data[:sourcenick] = $1
882
- data[:sourceaddress] = $2
1031
+ # Most servers will send a full nick!user@host prefix for
1032
+ # messages from users. Therefore, when the prefix doesn't match this
1033
+ # syntax it's usually the server hostname.
1034
+ #
1035
+ # This is not always true, though, since some servers do not send a
1036
+ # full hostmask for user messages.
1037
+ #
1038
+ if prefix =~ /^#{Regexp::Irc::BANG_AT}$/
1039
+ data[:source] = @server.user(prefix)
1040
+ else
1041
+ if @server.hostname
1042
+ if @server.hostname != prefix
1043
+ # TODO do we want to be able to differentiate messages that are passed on to us from /other/ servers?
1044
+ debug "Origin #{prefix} for message\n\t#{serverstring.inspect}\nis neither a user hostmask nor the server hostname\nI'll pretend that it's from the server anyway"
1045
+ data[:source] = @server
1046
+ else
1047
+ data[:source] = @server
1048
+ end
1049
+ else
1050
+ @server.instance_variable_set(:@hostname, prefix)
1051
+ data[:source] = @server
1052
+ end
883
1053
  end
884
1054
  end
885
1055
 
@@ -887,19 +1057,36 @@ module Irc
887
1057
  argv = []
888
1058
  params.scan(/(?!:)(\S+)|:(.*)/) { argv << ($1 || $2) } if params
889
1059
 
890
- case command
891
- when 'PING'
892
- data[:pingid] = argv[0]
893
- handle(:ping, data)
894
- when 'PONG'
895
- data[:pingid] = argv[0]
896
- handle(:pong, data)
897
- when /^(\d+)$/ # numeric server message
1060
+ if command =~ /^(\d+)$/ # Numeric replies
1061
+ data[:target] = argv[0]
1062
+ # A numeric reply /should/ be directed at the client, except when we're connecting with a used nick, in which case
1063
+ # it's directed at '*'
1064
+ not_us = !([@user.nick, '*'].include?(data[:target]))
1065
+ if not_us
1066
+ warning "Server reply #{serverstring.inspect} directed at #{data[:target]} instead of client (#{@user.nick})"
1067
+ end
1068
+
898
1069
  num=command.to_i
899
1070
  case num
1071
+ when RPL_WELCOME
1072
+ data[:message] = argv[1]
1073
+ # "Welcome to the Internet Relay Network
1074
+ # <nick>!<user>@<host>"
1075
+ if not_us
1076
+ warning "Server thinks client (#{@user.inspect}) has a different nick"
1077
+ @user.nick = data[:target]
1078
+ end
1079
+ if data[:message] =~ /([^@!\s]+)(?:!([^@!\s]+?))?@(\S+)/
1080
+ nick = $1
1081
+ user = $2
1082
+ host = $3
1083
+ warning "Welcome message nick mismatch (#{nick} vs #{data[:target]})" if nick != data[:target]
1084
+ @user.user = user if user
1085
+ @user.host = host if host
1086
+ end
1087
+ handle(:welcome, data)
900
1088
  when RPL_YOURHOST
901
1089
  # "Your host is <servername>, running version <ver>"
902
- # TODO how standard is this "version <ver>? should i parse it?
903
1090
  data[:message] = argv[1]
904
1091
  handle(:yourhost, data)
905
1092
  when RPL_CREATED
@@ -909,10 +1096,21 @@ module Irc
909
1096
  when RPL_MYINFO
910
1097
  # "<servername> <version> <available user modes>
911
1098
  # <available channel modes>"
912
- data[:servername] = argv[1]
913
- data[:version] = argv[2]
914
- data[:usermodes] = argv[3]
915
- data[:chanmodes] = argv[4]
1099
+ @server.parse_my_info(params.split(' ', 2).last)
1100
+ data[:servername] = @server.hostname
1101
+ data[:version] = @server.version
1102
+ data[:usermodes] = @server.usermodes
1103
+ data[:chanmodes] = @server.chanmodes
1104
+ handle(:myinfo, data)
1105
+ when RPL_ISUPPORT
1106
+ # "PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
1107
+ # "MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63
1108
+ # TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=#
1109
+ # PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer :are available
1110
+ # on this server"
1111
+ #
1112
+ @server.parse_isupport(argv[1..-2].join(' '))
1113
+ handle(:isupport, data)
916
1114
  when ERR_NICKNAMEINUSE
917
1115
  # "* <nick> :Nickname is already in use"
918
1116
  data[:nick] = argv[1]
@@ -924,49 +1122,65 @@ module Irc
924
1122
  data[:message] = argv[2]
925
1123
  handle(:badnick, data)
926
1124
  when RPL_TOPIC
927
- data[:channel] = argv[1]
1125
+ data[:channel] = @server.channel(argv[1])
928
1126
  data[:topic] = argv[2]
1127
+ data[:channel].topic.text = data[:topic]
1128
+
929
1129
  handle(:topic, data)
930
1130
  when RPL_TOPIC_INFO
931
- data[:nick] = argv[0]
932
- data[:channel] = argv[1]
933
- data[:source] = argv[2]
934
- data[:unixtime] = argv[3]
1131
+ data[:nick] = @server.user(argv[0])
1132
+ data[:channel] = @server.channel(argv[1])
1133
+
1134
+ # This must not be an IRC::User because it might not be an actual User,
1135
+ # and we risk overwriting valid User data
1136
+ data[:source] = argv[2].to_irc_netmask(:server => @server)
1137
+
1138
+ data[:time] = Time.at(argv[3].to_i)
1139
+
1140
+ data[:channel].topic.set_by = data[:source]
1141
+ data[:channel].topic.set_on = data[:time]
1142
+
935
1143
  handle(:topicinfo, data)
936
1144
  when RPL_NAMREPLY
937
1145
  # "( "=" / "*" / "@" ) <channel>
938
1146
  # :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
939
1147
  # - "@" is used for secret channels, "*" for private
940
1148
  # channels, and "=" for others (public channels).
1149
+ data[:channeltype] = argv[1]
1150
+ data[:channel] = argv[2]
1151
+
1152
+ chan = @server.get_channel(data[:channel])
1153
+ unless chan
1154
+ warning "Received names #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
1155
+ return
1156
+ end
1157
+
1158
+ users = []
941
1159
  argv[3].scan(/\S+/).each { |u|
942
- if(u =~ /^([@+])?(.*)$/)
943
- umode = $1 || ""
1160
+ # FIXME beware of servers that allow multiple prefixes
1161
+ if(u =~ /^([#{@server.supports[:prefix][:prefixes].join}])?(.*)$/)
1162
+ umode = $1
944
1163
  user = $2
945
- @users << [user, umode]
1164
+ users << [user, umode]
946
1165
  end
947
1166
  }
1167
+
1168
+ users.each { |ar|
1169
+ u = @server.user(ar[0])
1170
+ chan.add_user(u, :silent => true)
1171
+ debug "Adding user #{u}"
1172
+ if ar[1]
1173
+ ms = @server.mode_for_prefix(ar[1].to_sym)
1174
+ debug "\twith mode #{ar[1]} (#{ms})"
1175
+ chan.mode[ms].set(u)
1176
+ end
1177
+ }
1178
+ @tmpusers += users
948
1179
  when RPL_ENDOFNAMES
949
1180
  data[:channel] = argv[1]
950
- data[:users] = @users
1181
+ data[:users] = @tmpusers
951
1182
  handle(:names, data)
952
- @users = Array.new
953
- when RPL_ISUPPORT
954
- # "PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
955
- # "MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63
956
- # TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=#
957
- # PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer :are available
958
- # on this server"
959
- #
960
- argv[0,argv.length-1].each {|a|
961
- if a =~ /^(.*)=(.*)$/
962
- data[$1.downcase.to_sym] = $2
963
- debug "server's #{$1.downcase.to_sym} is #{$2}"
964
- else
965
- data[a.downcase.to_sym] = true
966
- debug "server supports #{a.downcase.to_sym}"
967
- end
968
- }
969
- handle(:isupport, data)
1183
+ @tmpusers = Array.new
970
1184
  when RPL_LUSERCLIENT
971
1185
  # ":There are <integer> users and <integer>
972
1186
  # services on <integer> servers"
@@ -1005,28 +1219,14 @@ module Irc
1005
1219
  # (re)started)"
1006
1220
  data[:message] = argv[1]
1007
1221
  handle(:statsconn, data)
1008
- when RPL_WELCOME
1009
- # "Welcome to the Internet Relay Network
1010
- # <nick>!<user>@<host>"
1011
- case argv[1]
1012
- when /((\S+)!(\S+))/
1013
- data[:netmask] = $1
1014
- data[:nick] = $2
1015
- data[:address] = $3
1016
- when /Welcome to the Internet Relay Network\s(\S+)/
1017
- data[:nick] = $1
1018
- when /Welcome.*\s+(\S+)$/
1019
- data[:nick] = $1
1020
- when /^(\S+)$/
1021
- data[:nick] = $1
1022
- end
1023
- handle(:welcome, data)
1024
1222
  when RPL_MOTDSTART
1025
1223
  # "<nick> :- <server> Message of the Day -"
1026
1224
  if argv[1] =~ /^-\s+(\S+)\s/
1027
1225
  server = $1
1028
- @motd = ""
1226
+ else
1227
+ warning "Server doesn't have an RFC compliant MOTD start."
1029
1228
  end
1229
+ @motd = ""
1030
1230
  when RPL_MOTD
1031
1231
  if(argv[1] =~ /^-\s+(.*)$/)
1032
1232
  @motd << $1
@@ -1038,65 +1238,168 @@ module Irc
1038
1238
  when RPL_DATASTR
1039
1239
  data[:text] = argv[1]
1040
1240
  handle(:datastr, data)
1241
+ when RPL_WHOREPLY
1242
+ data[:channel] = argv[1]
1243
+ data[:user] = argv[2]
1244
+ data[:host] = argv[3]
1245
+ data[:userserver] = argv[4]
1246
+ data[:nick] = argv[5]
1247
+ if argv[6] =~ /^(H|G)(\*)?(.*)?$/
1248
+ data[:away] = ($1 == 'G')
1249
+ data[:ircop] = $2
1250
+ data[:modes] = $3.scan(/./).map { |mode|
1251
+ m = @server.supports[:prefix][:prefixes].index(mode.to_sym)
1252
+ @server.supports[:prefix][:modes][m]
1253
+ } rescue []
1254
+ else
1255
+ warning "Strange WHO reply: #{serverstring.inspect}"
1256
+ end
1257
+ data[:hopcount], data[:real_name] = argv[7].split(" ", 2)
1258
+
1259
+ user = @server.get_user(data[:nick])
1260
+
1261
+ user.user = data[:user]
1262
+ user.host = data[:host]
1263
+ user.away = data[:away] # FIXME doesn't provide the actual message
1264
+ # TODO ircop status
1265
+ # TODO userserver
1266
+ # TODO hopcount
1267
+ user.real_name = data[:real_name]
1268
+
1269
+ channel = @server.get_channel(data[:channel])
1270
+
1271
+ channel.add_user(user, :silent=>true)
1272
+ data[:modes].map { |mode|
1273
+ channel.mode[mode].set(user)
1274
+ }
1275
+
1276
+ handle(:who, data)
1277
+ when RPL_ENDOFWHO
1278
+ handle(:eowho, data)
1279
+ when RPL_CHANNELMODEIS
1280
+ parse_mode(serverstring, argv[1..-1], data)
1281
+ handle(:mode, data)
1041
1282
  else
1283
+ warning "Unknown message #{serverstring.inspect}"
1042
1284
  handle(:unknown, data)
1043
1285
  end
1044
- # end of numeric replies
1045
- when 'PRIVMSG'
1286
+ return # We've processed the numeric reply
1287
+ end
1288
+
1289
+ # Otherwise, the command should be a single word
1290
+ case command.to_sym
1291
+ when :PING
1292
+ data[:pingid] = argv[0]
1293
+ handle(:ping, data)
1294
+ when :PONG
1295
+ data[:pingid] = argv[0]
1296
+ handle(:pong, data)
1297
+ when :PRIVMSG
1046
1298
  # you can either bind to 'PRIVMSG', to get every one and
1047
1299
  # parse it yourself, or you can bind to 'MSG', 'PUBLIC',
1048
1300
  # etc and get it all nicely split up for you.
1049
- data[:target] = argv[0]
1301
+
1302
+ begin
1303
+ data[:target] = @server.user_or_channel(argv[0])
1304
+ rescue
1305
+ # The previous may fail e.g. when the target is a server or something
1306
+ # like that (e.g. $<mask>). In any of these cases, we just use the
1307
+ # String as a target
1308
+ # FIXME we probably want to explicitly check for the #<mask> $<mask>
1309
+ data[:target] = argv[0]
1310
+ end
1050
1311
  data[:message] = argv[1]
1051
1312
  handle(:privmsg, data)
1052
1313
 
1053
1314
  # Now we split it
1054
- if(data[:target] =~ /^[#&!+].*/)
1315
+ if data[:target].kind_of?(Channel)
1055
1316
  handle(:public, data)
1056
1317
  else
1057
1318
  handle(:msg, data)
1058
1319
  end
1059
- when 'KICK'
1060
- data[:channel] = argv[0]
1061
- data[:target] = argv[1]
1320
+ when :NOTICE
1321
+ begin
1322
+ data[:target] = @server.user_or_channel(argv[0])
1323
+ rescue
1324
+ # The previous may fail e.g. when the target is a server or something
1325
+ # like that (e.g. $<mask>). In any of these cases, we just use the
1326
+ # String as a target
1327
+ # FIXME we probably want to explicitly check for the #<mask> $<mask>
1328
+ data[:target] = argv[0]
1329
+ end
1330
+ data[:message] = argv[1]
1331
+ case data[:source]
1332
+ when User
1333
+ handle(:notice, data)
1334
+ else
1335
+ # "server notice" (not from user, noone to reply to)
1336
+ handle(:snotice, data)
1337
+ end
1338
+ when :KICK
1339
+ data[:channel] = @server.channel(argv[0])
1340
+ data[:target] = @server.user(argv[1])
1062
1341
  data[:message] = argv[2]
1342
+
1343
+ @server.delete_user_from_channel(data[:target], data[:channel])
1344
+ if data[:target] == @user
1345
+ @server.delete_channel(data[:channel])
1346
+ end
1347
+
1063
1348
  handle(:kick, data)
1064
- when 'PART'
1065
- data[:channel] = argv[0]
1349
+ when :PART
1350
+ data[:channel] = @server.channel(argv[0])
1066
1351
  data[:message] = argv[1]
1352
+
1353
+ @server.delete_user_from_channel(data[:source], data[:channel])
1354
+ if data[:source] == @user
1355
+ @server.delete_channel(data[:channel])
1356
+ end
1357
+
1067
1358
  handle(:part, data)
1068
- when 'QUIT'
1359
+ when :QUIT
1069
1360
  data[:message] = argv[0]
1361
+ data[:was_on] = @server.channels.inject(ChannelList.new) { |list, ch|
1362
+ list << ch if ch.has_user?(data[:source])
1363
+ list
1364
+ }
1365
+
1366
+ @server.delete_user(data[:source])
1367
+
1070
1368
  handle(:quit, data)
1071
- when 'JOIN'
1072
- data[:channel] = argv[0]
1369
+ when :JOIN
1370
+ data[:channel] = @server.channel(argv[0])
1371
+ data[:channel].add_user(data[:source])
1372
+
1073
1373
  handle(:join, data)
1074
- when 'TOPIC'
1075
- data[:channel] = argv[0]
1076
- data[:topic] = argv[1]
1374
+ when :TOPIC
1375
+ data[:channel] = @server.channel(argv[0])
1376
+ data[:topic] = Channel::Topic.new(argv[1], data[:source], Time.new)
1377
+ data[:channel].topic.replace(data[:topic])
1378
+
1077
1379
  handle(:changetopic, data)
1078
- when 'INVITE'
1079
- data[:target] = argv[0]
1080
- data[:channel] = argv[1]
1380
+ when :INVITE
1381
+ data[:target] = @server.user(argv[0])
1382
+ data[:channel] = @server.channel(argv[1])
1383
+
1081
1384
  handle(:invite, data)
1082
- when 'NICK'
1083
- data[:nick] = argv[0]
1385
+ when :NICK
1386
+ data[:is_on] = @server.channels.inject(ChannelList.new) { |list, ch|
1387
+ list << ch if ch.has_user?(data[:source])
1388
+ list
1389
+ }
1390
+
1391
+ data[:newnick] = argv[0]
1392
+ data[:oldnick] = data[:source].nick.dup
1393
+ data[:source].nick = data[:newnick]
1394
+
1395
+ debug "#{data[:oldnick]} (now #{data[:newnick]}) was on #{data[:is_on].join(', ')}"
1396
+
1084
1397
  handle(:nick, data)
1085
- when 'MODE'
1086
- data[:channel] = argv[0]
1087
- data[:modestring] = argv[1]
1088
- data[:targets] = argv[2]
1398
+ when :MODE
1399
+ parse_mode(serverstring, argv, data)
1089
1400
  handle(:mode, data)
1090
- when 'NOTICE'
1091
- data[:target] = argv[0]
1092
- data[:message] = argv[1]
1093
- if data[:sourcenick]
1094
- handle(:notice, data)
1095
- else
1096
- # "server notice" (not from user, noone to reply to
1097
- handle(:snotice, data)
1098
- end
1099
1401
  else
1402
+ warning "Unknown message #{serverstring.inspect}"
1100
1403
  handle(:unknown, data)
1101
1404
  end
1102
1405
  end
@@ -1111,5 +1414,110 @@ module Irc
1111
1414
  @handlers[key].call(data)
1112
1415
  end
1113
1416
  end
1417
+
1418
+ # RPL_CHANNELMODEIS
1419
+ # MODE ([+-]<modes> (<params>)*)*
1420
+ # When a MODE message is received by a server,
1421
+ # Type C will have parameters too, so we must
1422
+ # be able to consume parameters for all
1423
+ # but Type D modes
1424
+ def parse_mode(serverstring, argv, data)
1425
+ data[:target] = @server.user_or_channel(argv[0])
1426
+ data[:modestring] = argv[1..-1].join(" ")
1427
+ # data[:modes] is an array where each element
1428
+ # is an array with two elements, the first of which
1429
+ # is either :set or :reset, and the second symbol
1430
+ # is the mode letter. An optional third element
1431
+ # is present e.g. for channel modes that need
1432
+ # a parameter
1433
+ data[:modes] = []
1434
+ case data[:target]
1435
+ when User
1436
+ # User modes aren't currently handled internally,
1437
+ # but we still parse them and delegate to the client
1438
+ warning "Unhandled user mode message '#{serverstring}'"
1439
+ argv[1..-1].each { |arg|
1440
+ setting = arg[0].chr
1441
+ if "+-".include?(setting)
1442
+ setting = setting == "+" ? :set : :reset
1443
+ arg[1..-1].each_byte { |b|
1444
+ m = b.chr.intern
1445
+ data[:modes] << [setting, m]
1446
+ }
1447
+ else
1448
+ # Although typically User modes don't take an argument,
1449
+ # this is not true for all modes on all servers. Since
1450
+ # we have no knowledge of which modes take parameters
1451
+ # and which don't we just assign it to the last
1452
+ # mode. This is not going to do strange things often,
1453
+ # as usually User modes are only set one at a time
1454
+ warning "Unhandled user mode parameter #{arg} found"
1455
+ data[:modes].last << arg
1456
+ end
1457
+ }
1458
+ else
1459
+ # array of indices in data[:modes] where parameters
1460
+ # are needed
1461
+ who_wants_params = []
1462
+
1463
+ modes = argv[1..-1].dup
1464
+ debug modes
1465
+ getting_args = false
1466
+ while arg = modes.shift
1467
+ debug arg
1468
+ if getting_args
1469
+ # getting args for previously set modes
1470
+ idx = who_wants_params.shift
1471
+ if idx.nil?
1472
+ warning "Oops, problems parsing #{serverstring.inspect}"
1473
+ break
1474
+ end
1475
+ data[:modes][idx] << arg
1476
+ getting_args = false if who_wants_params.empty?
1477
+ else
1478
+ debug @server.supports[:chanmodes]
1479
+ setting = :set
1480
+ arg.each_byte do |c|
1481
+ m = c.chr.intern
1482
+ case m
1483
+ when :+
1484
+ setting = :set
1485
+ when :-
1486
+ setting = :reset
1487
+ else
1488
+ data[:modes] << [setting, m]
1489
+ case m
1490
+ when *@server.supports[:chanmodes][:typea]
1491
+ who_wants_params << data[:modes].length - 1
1492
+ when *@server.supports[:chanmodes][:typeb]
1493
+ who_wants_params << data[:modes].length - 1
1494
+ when *@server.supports[:chanmodes][:typec]
1495
+ if setting == :set
1496
+ who_wants_params << data[:modes].length - 1
1497
+ end
1498
+ when *@server.supports[:chanmodes][:typed]
1499
+ # Nothing to do
1500
+ when *@server.supports[:prefix][:modes]
1501
+ who_wants_params << data[:modes].length - 1
1502
+ else
1503
+ warning "Ignoring unknown mode #{m} in #{serverstring.inspect}"
1504
+ data[:modes].pop
1505
+ end
1506
+ end
1507
+ end
1508
+ getting_args = true unless who_wants_params.empty?
1509
+ end
1510
+ end
1511
+
1512
+ data[:modes].each { |mode|
1513
+ set, key, val = mode
1514
+ if val
1515
+ data[:target].mode[key].send(set, val)
1516
+ else
1517
+ data[:target].mode[key].send(set)
1518
+ end
1519
+ }
1520
+ end
1521
+ end
1114
1522
  end
1115
1523
  end