spox-mod_spox 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. data/CHANGELOG +174 -0
  2. data/INSTALL +15 -0
  3. data/LICENSE +674 -0
  4. data/README.rdoc +73 -0
  5. data/bin/mod_spox +112 -0
  6. data/data/mod_spox/extras/AOLSpeak.rb +257 -0
  7. data/data/mod_spox/extras/AutoKick.rb +152 -0
  8. data/data/mod_spox/extras/AutoMode.rb +122 -0
  9. data/data/mod_spox/extras/AutoRejoin.rb +37 -0
  10. data/data/mod_spox/extras/Bash.rb +55 -0
  11. data/data/mod_spox/extras/Bouncer.rb +220 -0
  12. data/data/mod_spox/extras/Bullshit.rb +19 -0
  13. data/data/mod_spox/extras/Bytes.rb +11 -0
  14. data/data/mod_spox/extras/Confess.rb +244 -0
  15. data/data/mod_spox/extras/DCC.rb +182 -0
  16. data/data/mod_spox/extras/DevWatch.rb +153 -0
  17. data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
  18. data/data/mod_spox/extras/EightBall.rb +33 -0
  19. data/data/mod_spox/extras/FML.rb +35 -0
  20. data/data/mod_spox/extras/FloodKicker.rb +129 -0
  21. data/data/mod_spox/extras/Fortune.rb +76 -0
  22. data/data/mod_spox/extras/GoogleIt.rb +13 -0
  23. data/data/mod_spox/extras/Headers.rb +59 -0
  24. data/data/mod_spox/extras/Karma.rb +302 -0
  25. data/data/mod_spox/extras/Locator.rb +44 -0
  26. data/data/mod_spox/extras/Logger.rb +182 -0
  27. data/data/mod_spox/extras/LolSpeak.rb +21 -0
  28. data/data/mod_spox/extras/NickServ.rb +84 -0
  29. data/data/mod_spox/extras/PhpCli.rb +308 -0
  30. data/data/mod_spox/extras/PhpFuncLookup.rb +297 -0
  31. data/data/mod_spox/extras/Pinger.rb +11 -0
  32. data/data/mod_spox/extras/Quotes.rb +79 -0
  33. data/data/mod_spox/extras/RegexTracker.rb +158 -0
  34. data/data/mod_spox/extras/Roulette.rb +267 -0
  35. data/data/mod_spox/extras/RubyCli.rb +93 -0
  36. data/data/mod_spox/extras/Search.rb +49 -0
  37. data/data/mod_spox/extras/Seen.rb +150 -0
  38. data/data/mod_spox/extras/Slashdot.rb +35 -0
  39. data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
  40. data/data/mod_spox/extras/Talk.rb +32 -0
  41. data/data/mod_spox/extras/Topten.rb +103 -0
  42. data/data/mod_spox/extras/TracTicket.rb +66 -0
  43. data/data/mod_spox/extras/Translate.rb +132 -0
  44. data/data/mod_spox/extras/Twitter.rb +458 -0
  45. data/data/mod_spox/extras/UrbanDictionary.rb +55 -0
  46. data/data/mod_spox/extras/Weather.rb +55 -0
  47. data/data/mod_spox/plugins/Authenticator.rb +289 -0
  48. data/data/mod_spox/plugins/Banner.rb +585 -0
  49. data/data/mod_spox/plugins/BotNick.rb +18 -0
  50. data/data/mod_spox/plugins/Helper.rb +49 -0
  51. data/data/mod_spox/plugins/Initializer.rb +35 -0
  52. data/data/mod_spox/plugins/Joiner.rb +23 -0
  53. data/data/mod_spox/plugins/Nicker.rb +14 -0
  54. data/data/mod_spox/plugins/Parter.rb +23 -0
  55. data/data/mod_spox/plugins/Permissions.rb +60 -0
  56. data/data/mod_spox/plugins/PluginLoader.rb +180 -0
  57. data/data/mod_spox/plugins/Ponger.rb +70 -0
  58. data/data/mod_spox/plugins/PoolConfig.rb +52 -0
  59. data/data/mod_spox/plugins/Quitter.rb +15 -0
  60. data/data/mod_spox/plugins/Servers.rb +57 -0
  61. data/data/mod_spox/plugins/Status.rb +31 -0
  62. data/data/mod_spox/plugins/Triggers.rb +85 -0
  63. data/lib/mod_spox/BaseConfig.rb +51 -0
  64. data/lib/mod_spox/Bot.rb +604 -0
  65. data/lib/mod_spox/BotConfig.rb +65 -0
  66. data/lib/mod_spox/ConfigurationWizard.rb +180 -0
  67. data/lib/mod_spox/Database.rb +51 -0
  68. data/lib/mod_spox/Exceptions.rb +84 -0
  69. data/lib/mod_spox/Helpers.rb +122 -0
  70. data/lib/mod_spox/Loader.rb +60 -0
  71. data/lib/mod_spox/Logger.rb +37 -0
  72. data/lib/mod_spox/MessageFactory.rb +112 -0
  73. data/lib/mod_spox/Pipeline.rb +207 -0
  74. data/lib/mod_spox/Plugin.rb +97 -0
  75. data/lib/mod_spox/PluginHolder.rb +22 -0
  76. data/lib/mod_spox/PluginManager.rb +257 -0
  77. data/lib/mod_spox/PriorityQueue.rb +69 -0
  78. data/lib/mod_spox/Socket.rb +201 -0
  79. data/lib/mod_spox/Sockets.rb +226 -0
  80. data/lib/mod_spox/Timer.rb +60 -0
  81. data/lib/mod_spox/Version.rb +14 -0
  82. data/lib/mod_spox/handlers/BadNick.rb +19 -0
  83. data/lib/mod_spox/handlers/Bounce.rb +24 -0
  84. data/lib/mod_spox/handlers/Created.rb +27 -0
  85. data/lib/mod_spox/handlers/Handler.rb +39 -0
  86. data/lib/mod_spox/handlers/Invite.rb +28 -0
  87. data/lib/mod_spox/handlers/Join.rb +38 -0
  88. data/lib/mod_spox/handlers/Kick.rb +36 -0
  89. data/lib/mod_spox/handlers/LuserChannels.rb +19 -0
  90. data/lib/mod_spox/handlers/LuserClient.rb +18 -0
  91. data/lib/mod_spox/handlers/LuserMe.rb +16 -0
  92. data/lib/mod_spox/handlers/LuserOp.rb +19 -0
  93. data/lib/mod_spox/handlers/LuserUnknown.rb +19 -0
  94. data/lib/mod_spox/handlers/Mode.rb +62 -0
  95. data/lib/mod_spox/handlers/Motd.rb +38 -0
  96. data/lib/mod_spox/handlers/MyInfo.rb +24 -0
  97. data/lib/mod_spox/handlers/Names.rb +86 -0
  98. data/lib/mod_spox/handlers/Nick.rb +50 -0
  99. data/lib/mod_spox/handlers/NickInUse.rb +19 -0
  100. data/lib/mod_spox/handlers/Notice.rb +35 -0
  101. data/lib/mod_spox/handlers/Part.rb +39 -0
  102. data/lib/mod_spox/handlers/Ping.rb +25 -0
  103. data/lib/mod_spox/handlers/Pong.rb +23 -0
  104. data/lib/mod_spox/handlers/Privmsg.rb +39 -0
  105. data/lib/mod_spox/handlers/Quit.rb +29 -0
  106. data/lib/mod_spox/handlers/Topic.rb +38 -0
  107. data/lib/mod_spox/handlers/Welcome.rb +30 -0
  108. data/lib/mod_spox/handlers/Who.rb +83 -0
  109. data/lib/mod_spox/handlers/Whois.rb +117 -0
  110. data/lib/mod_spox/handlers/YourHost.rb +20 -0
  111. data/lib/mod_spox/messages/Messages.rb +6 -0
  112. data/lib/mod_spox/messages/incoming/BadNick.rb +16 -0
  113. data/lib/mod_spox/messages/incoming/Bounce.rb +18 -0
  114. data/lib/mod_spox/messages/incoming/Created.rb +15 -0
  115. data/lib/mod_spox/messages/incoming/Invite.rb +21 -0
  116. data/lib/mod_spox/messages/incoming/Join.rb +19 -0
  117. data/lib/mod_spox/messages/incoming/Kick.rb +26 -0
  118. data/lib/mod_spox/messages/incoming/LuserChannels.rb +15 -0
  119. data/lib/mod_spox/messages/incoming/LuserClient.rb +24 -0
  120. data/lib/mod_spox/messages/incoming/LuserMe.rb +18 -0
  121. data/lib/mod_spox/messages/incoming/LuserOp.rb +15 -0
  122. data/lib/mod_spox/messages/incoming/LuserUnknown.rb +15 -0
  123. data/lib/mod_spox/messages/incoming/Message.rb +22 -0
  124. data/lib/mod_spox/messages/incoming/Mode.rb +42 -0
  125. data/lib/mod_spox/messages/incoming/Motd.rb +18 -0
  126. data/lib/mod_spox/messages/incoming/MyInfo.rb +24 -0
  127. data/lib/mod_spox/messages/incoming/Names.rb +24 -0
  128. data/lib/mod_spox/messages/incoming/Nick.rb +26 -0
  129. data/lib/mod_spox/messages/incoming/NickInUse.rb +15 -0
  130. data/lib/mod_spox/messages/incoming/Notice.rb +9 -0
  131. data/lib/mod_spox/messages/incoming/Part.rb +21 -0
  132. data/lib/mod_spox/messages/incoming/Ping.rb +18 -0
  133. data/lib/mod_spox/messages/incoming/Pong.rb +9 -0
  134. data/lib/mod_spox/messages/incoming/Privmsg.rb +90 -0
  135. data/lib/mod_spox/messages/incoming/Quit.rb +18 -0
  136. data/lib/mod_spox/messages/incoming/Topic.rb +21 -0
  137. data/lib/mod_spox/messages/incoming/TopicInfo.rb +21 -0
  138. data/lib/mod_spox/messages/incoming/Welcome.rb +27 -0
  139. data/lib/mod_spox/messages/incoming/Who.rb +18 -0
  140. data/lib/mod_spox/messages/incoming/Whois.rb +49 -0
  141. data/lib/mod_spox/messages/incoming/YourHost.rb +18 -0
  142. data/lib/mod_spox/messages/internal/BotInitialized.rb +11 -0
  143. data/lib/mod_spox/messages/internal/ChangeNick.rb +15 -0
  144. data/lib/mod_spox/messages/internal/Connected.rb +20 -0
  145. data/lib/mod_spox/messages/internal/ConnectionFailed.rb +23 -0
  146. data/lib/mod_spox/messages/internal/DCCListener.rb +12 -0
  147. data/lib/mod_spox/messages/internal/DCCRequest.rb +12 -0
  148. data/lib/mod_spox/messages/internal/DCCSocket.rb +19 -0
  149. data/lib/mod_spox/messages/internal/Disconnected.rb +8 -0
  150. data/lib/mod_spox/messages/internal/Disconnecting.rb +8 -0
  151. data/lib/mod_spox/messages/internal/EstablishConnection.rb +22 -0
  152. data/lib/mod_spox/messages/internal/HaltBot.rb +8 -0
  153. data/lib/mod_spox/messages/internal/NickRequest.rb +9 -0
  154. data/lib/mod_spox/messages/internal/NickResponse.rb +15 -0
  155. data/lib/mod_spox/messages/internal/PluginLoadRequest.rb +21 -0
  156. data/lib/mod_spox/messages/internal/PluginLoadResponse.rb +17 -0
  157. data/lib/mod_spox/messages/internal/PluginModuleRequest.rb +14 -0
  158. data/lib/mod_spox/messages/internal/PluginModuleResponse.rb +18 -0
  159. data/lib/mod_spox/messages/internal/PluginReload.rb +18 -0
  160. data/lib/mod_spox/messages/internal/PluginRequest.rb +18 -0
  161. data/lib/mod_spox/messages/internal/PluginResponse.rb +21 -0
  162. data/lib/mod_spox/messages/internal/PluginUnloadRequest.rb +9 -0
  163. data/lib/mod_spox/messages/internal/PluginUnloadResponse.rb +9 -0
  164. data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
  165. data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
  166. data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
  167. data/lib/mod_spox/messages/internal/Request.rb +15 -0
  168. data/lib/mod_spox/messages/internal/Response.rb +15 -0
  169. data/lib/mod_spox/messages/internal/Shutdown.rb +8 -0
  170. data/lib/mod_spox/messages/internal/SignaturesUpdate.rb +8 -0
  171. data/lib/mod_spox/messages/internal/StatusRequest.rb +10 -0
  172. data/lib/mod_spox/messages/internal/StatusResponse.rb +18 -0
  173. data/lib/mod_spox/messages/internal/TimerAdd.rb +36 -0
  174. data/lib/mod_spox/messages/internal/TimerClear.rb +16 -0
  175. data/lib/mod_spox/messages/internal/TimerRemove.rb +23 -0
  176. data/lib/mod_spox/messages/internal/TimerResponse.rb +34 -0
  177. data/lib/mod_spox/messages/internal/TriggersUpdate.rb +8 -0
  178. data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
  179. data/lib/mod_spox/messages/outgoing/Admin.rb +15 -0
  180. data/lib/mod_spox/messages/outgoing/Away.rb +11 -0
  181. data/lib/mod_spox/messages/outgoing/ChannelMode.rb +25 -0
  182. data/lib/mod_spox/messages/outgoing/Connect.rb +24 -0
  183. data/lib/mod_spox/messages/outgoing/Die.rb +9 -0
  184. data/lib/mod_spox/messages/outgoing/Info.rb +15 -0
  185. data/lib/mod_spox/messages/outgoing/Invite.rb +19 -0
  186. data/lib/mod_spox/messages/outgoing/Ison.rb +15 -0
  187. data/lib/mod_spox/messages/outgoing/Join.rb +19 -0
  188. data/lib/mod_spox/messages/outgoing/Kick.rb +23 -0
  189. data/lib/mod_spox/messages/outgoing/Kill.rb +19 -0
  190. data/lib/mod_spox/messages/outgoing/Links.rb +19 -0
  191. data/lib/mod_spox/messages/outgoing/List.rb +19 -0
  192. data/lib/mod_spox/messages/outgoing/Lusers.rb +19 -0
  193. data/lib/mod_spox/messages/outgoing/Motd.rb +16 -0
  194. data/lib/mod_spox/messages/outgoing/Names.rb +20 -0
  195. data/lib/mod_spox/messages/outgoing/Nick.rb +16 -0
  196. data/lib/mod_spox/messages/outgoing/Notice.rb +12 -0
  197. data/lib/mod_spox/messages/outgoing/Oper.rb +19 -0
  198. data/lib/mod_spox/messages/outgoing/Part.rb +19 -0
  199. data/lib/mod_spox/messages/outgoing/Pass.rb +16 -0
  200. data/lib/mod_spox/messages/outgoing/Ping.rb +11 -0
  201. data/lib/mod_spox/messages/outgoing/Pong.rb +17 -0
  202. data/lib/mod_spox/messages/outgoing/Privmsg.rb +43 -0
  203. data/lib/mod_spox/messages/outgoing/Quit.rb +11 -0
  204. data/lib/mod_spox/messages/outgoing/Raw.rb +16 -0
  205. data/lib/mod_spox/messages/outgoing/Rehash.rb +9 -0
  206. data/lib/mod_spox/messages/outgoing/Restart.rb +9 -0
  207. data/lib/mod_spox/messages/outgoing/ServList.rb +19 -0
  208. data/lib/mod_spox/messages/outgoing/Simple.rb +12 -0
  209. data/lib/mod_spox/messages/outgoing/Squery.rb +19 -0
  210. data/lib/mod_spox/messages/outgoing/Squit.rb +19 -0
  211. data/lib/mod_spox/messages/outgoing/Stats.rb +18 -0
  212. data/lib/mod_spox/messages/outgoing/Summon.rb +23 -0
  213. data/lib/mod_spox/messages/outgoing/Time.rb +15 -0
  214. data/lib/mod_spox/messages/outgoing/Topic.rb +19 -0
  215. data/lib/mod_spox/messages/outgoing/Trace.rb +15 -0
  216. data/lib/mod_spox/messages/outgoing/Unaway.rb +9 -0
  217. data/lib/mod_spox/messages/outgoing/User.rb +23 -0
  218. data/lib/mod_spox/messages/outgoing/UserHost.rb +15 -0
  219. data/lib/mod_spox/messages/outgoing/UserMode.rb +19 -0
  220. data/lib/mod_spox/messages/outgoing/Users.rb +15 -0
  221. data/lib/mod_spox/messages/outgoing/Version.rb +16 -0
  222. data/lib/mod_spox/messages/outgoing/Who.rb +23 -0
  223. data/lib/mod_spox/messages/outgoing/WhoWas.rb +23 -0
  224. data/lib/mod_spox/messages/outgoing/Whois.rb +19 -0
  225. data/lib/mod_spox/migrations/001_initialize_models.rb +115 -0
  226. data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
  227. data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
  228. data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
  229. data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
  230. data/lib/mod_spox/models/Auth.rb +65 -0
  231. data/lib/mod_spox/models/AuthMask.rb +13 -0
  232. data/lib/mod_spox/models/Channel.rb +89 -0
  233. data/lib/mod_spox/models/Config.rb +30 -0
  234. data/lib/mod_spox/models/Group.rb +30 -0
  235. data/lib/mod_spox/models/Models.rb +4 -0
  236. data/lib/mod_spox/models/Nick.rb +195 -0
  237. data/lib/mod_spox/models/NickMode.rb +32 -0
  238. data/lib/mod_spox/models/Server.rb +27 -0
  239. data/lib/mod_spox/models/Setting.rb +52 -0
  240. data/lib/mod_spox/models/Signature.rb +52 -0
  241. data/lib/mod_spox/models/Trigger.rb +9 -0
  242. data/lib/mod_spox/rfc2812.rb +49 -0
  243. data/populate_gemspec.rb +15 -0
  244. data/tests/BotHolder.rb +24 -0
  245. data/tests/handlers/tc_BadNick.rb +21 -0
  246. data/tests/handlers/tc_Created.rb +24 -0
  247. data/tests/handlers/tc_Invite.rb +50 -0
  248. data/tests/handlers/tc_Join.rb +33 -0
  249. data/tests/handlers/tc_Kick.rb +32 -0
  250. data/tests/handlers/tc_Mode.rb +85 -0
  251. data/tests/handlers/tc_Names.rb +35 -0
  252. data/tests/handlers/tc_Nick.rb +55 -0
  253. data/tests/handlers/tc_Part.rb +44 -0
  254. data/tests/handlers/tc_Ping.rb +40 -0
  255. data/tests/handlers/tc_Pong.rb +28 -0
  256. data/tests/handlers/tc_Privmsg.rb +85 -0
  257. data/tests/handlers/tc_Quit.rb +40 -0
  258. data/tests/handlers/tc_Who.rb +50 -0
  259. data/tests/handlers/tc_Whois.rb +61 -0
  260. data/tests/models/tc_Auth.rb +39 -0
  261. data/tests/models/tc_Channel.rb +52 -0
  262. data/tests/models/tc_Config.rb +19 -0
  263. data/tests/models/tc_Nick.rb +144 -0
  264. data/tests/models/tc_NickMode.rb +40 -0
  265. data/tests/models/tc_Setting.rb +21 -0
  266. data/tests/models/tc_Signature.rb +14 -0
  267. data/tests/run_tests.rb +6 -0
  268. metadata +362 -0
@@ -0,0 +1,66 @@
1
+ require 'net/http'
2
+
3
+ class TracTicket < ModSpox::Plugin
4
+
5
+ def initialize(pipeline)
6
+ super
7
+ admin = Group.find_or_create(:name => 'admin')
8
+ add_sig(:sig => 'ticket (defect|enhancement|task) (.+?)( # (.+))?', :method => :add_ticket,
9
+ :desc => 'Add new ticket to trac ticket tracker', :params => [:type, :short, :trash, :long])
10
+ add_sig(:sig => 'ticket trac( (\S+))?', :method => :trac_location, :group => admin,
11
+ :desc => 'Show/set trac site', :params => [:trash, :site])
12
+ add_sig(:sig => 'ticket site', :method => :trac_location, :desc => 'Show trac site')
13
+ @site = Config.val(:trac)
14
+ end
15
+
16
+ def trac_location(message, params)
17
+ if(params[:site])
18
+ site = Config.set(:trac, params[:site])
19
+ @site = params[:site]
20
+ reply message.replyto, "\2Trac Update:\2 Location of trac system has been updated: #{params[:site]}"
21
+ else
22
+ output = "\2Error:\2 Trac site has not yet been set"
23
+ unless(@site.nil?)
24
+ output = "\2Trac location:\2 #{@site}"
25
+ end
26
+ reply message.replyto, output
27
+ end
28
+ end
29
+
30
+ def add_ticket(message, params)
31
+ if(@site =~ /(http:\/\/)?([^\/:]+)(:\d+)?(.+)$/)
32
+ addr = $2
33
+ port = $3
34
+ path = $4
35
+ port = port.nil? ? 80 : port.gsub(/:/, '').to_i
36
+ con = Net::HTTP.new(addr, port)
37
+ begin
38
+ cookie, fid = get_form_info(con, path)
39
+ long = params[:long] ? params[:long] : params[:short]
40
+ headers = {
41
+ 'Cookie' => cookie,
42
+ 'Referer' => @site,
43
+ 'Content-Type' => 'application/x-www-form-urlencoded'
44
+ }
45
+ data = "field_reporter=#{URI.escape(message.source.nick)}&field_summary=#{URI.escape(params[:short])}&field_description=#{URI.escape(long)}&field_type=#{URI.escape(params[:type])}&field_status=new&submit=Create%20ticket&field_priority=minor&__FORM_TOKEN=#{URI.escape(fid)}"
46
+ resp, data = con.post(path, data, headers)
47
+ reply message.replyto, 'Ticket was successfully added to tracker'
48
+ rescue Object => boom
49
+ reply message.replyto, "\2Error:\2 Encountered unexpected error while submitting ticket: #{boom}"
50
+ end
51
+ else
52
+ reply message.replyto, "\2Error:\2 Trac location has not been set"
53
+ end
54
+ end
55
+
56
+ def get_form_info(con, path)
57
+ res, content = con.get(path, {})
58
+ cookie = res['set-cookie']
59
+ if(content =~ /name="__FORM_TOKEN" value="(.+?)"/i)
60
+ return cookie, $1
61
+ else
62
+ raise 'Failed to locate proper identification'
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,132 @@
1
+ class Translate < ModSpox::Plugin
2
+
3
+ include Models
4
+
5
+ def initialize(pipeline)
6
+ super(pipeline)
7
+ add_sig(:sig => 'translate ([a-z]{2}\|[a-z]{2}) (.+)', :method => :translate, :desc => 'Translate text', :params => [:lang, :text])
8
+ add_sig(:sig => 'autotranslate add ([a-z]{2}) (\S+)', :method => :auto_add, :desc => 'Add a nick to the autotranslate service', :params => [:lang, :nick])
9
+ add_sig(:sig => 'autotranslate remove (\S+)', :method => :auto_remove, :desc => 'Remove a nick from the autotranslate service', :params => [:nick])
10
+ add_sig(:sig => 'translate languages', :method => :langs, :desc => 'Show available languages')
11
+ @pipeline.hook(self, :listener, :Incoming_Privmsg)
12
+ @watchers = {}
13
+ @cache = {}
14
+ @allowed = {'zh'=>'Chinese-simplified','zt'=>'Chinese-traditional','en'=>'English','nl'=>'Dutch',
15
+ 'fr'=>'French','de'=>'German','el'=>'Greek','it'=>'Italian','ja'=>'Japanese',
16
+ 'ko'=>'Korean','pt'=>'Portuguese','ru'=>'Russian','es'=>'Spanish'}
17
+ @allowed_trans = ['zh_en','zh_zt', 'zt_en', 'zt_zh', 'en_zh', 'en_zt', 'en_nl', 'en_fr', 'en_de',
18
+ 'en_el', 'en_it', 'en_ja', 'en_ko', 'en_pt', 'en_ru', 'en_es', 'nl_en', 'nl_fr',
19
+ 'fr_nl', 'fr_en', 'fr_de', 'fr_el', 'fr_it', 'fr_pt', 'fr_es', 'de_en', 'de_fr',
20
+ 'el_en', 'el_fr', 'it_en', 'it_fr', 'ja_en', 'ko_en', 'pt_en', 'pt_fr', 'ru_en',
21
+ 'es_en', 'es_fr']
22
+ end
23
+
24
+ def langs(m, params)
25
+ output = ['Available languages for translate:']
26
+ s = []
27
+ @allowed.each_pair{|k,v| s << "#{v} (\2#{k}\2)"}
28
+ output << s.join(', ')
29
+ reply m.replyto, output
30
+ end
31
+
32
+ def auto_add(message, params)
33
+ return unless message.is_public?
34
+ if(@allowed_trans.include?("en_#{params[:lang]}") && @allowed_trans.include?("#{params[:lang]}_en"))
35
+ nick = Helpers.find_model(params[:nick], false)
36
+ if(nick && nick.channels.include?(message.target))
37
+ @watchers[message.target.pk] = {} unless @watchers.has_key?(message.target.pk)
38
+ @watchers[message.target.pk][nick.pk] = params[:lang] unless @watchers[message.target.pk].has_key?(nick.pk)
39
+ reply message.replyto, "#{params[:nick]} is now being tracked for auto translation"
40
+ else
41
+ reply message.replyto, "\2Error:\2 Failed to locate #{params[:nick]}"
42
+ end
43
+ else
44
+ reply message.replyt, "\2Error:\2 Unsupported bi-directional translation"
45
+ end
46
+ end
47
+
48
+ def auto_remove(message, params)
49
+ return unless message.is_public?
50
+ nick = Models::Nick.locate(params[:nick], false)
51
+ if(nick)
52
+ if(@watchers.has_key?(message.target.pk))
53
+ @watchers[message.target.pk].delete(nick.pk) if @watchers[message.target.pk].has_key?(nick.pk)
54
+ @watchers.delete(message.target.pk) if @watchers[message.target.pk].empty?
55
+ reply message.replyto, "#{params[:nick]} is no longer being tracked for auto translation"
56
+ else
57
+ reply message.replyto, "No one is currently being tracked"
58
+ end
59
+ else
60
+ reply message.replyto, "\2Error:\2 Failed to locate #{params[:nick]}"
61
+ end
62
+ end
63
+
64
+ def translate(message, params)
65
+ begin
66
+ reply message.replyto, "\2Translation:\2 #{do_translation(params[:lang], params[:text])}"
67
+ rescue Object => boom
68
+ reply message.replyto, "\2Error:\2 #{boom}"
69
+ end
70
+ end
71
+
72
+ def listener(message)
73
+ if(message.is_public? && @watchers.has_key?(message.target.pk))
74
+ if(@watchers[message.target.pk].has_key?(message.source.pk))
75
+ trans_message = do_translation("#{@watchers[message.target.pk][message.source.pk]}|en", message.message)
76
+ reply message.replyto, "\2Translation (#{message.source.nick}):\2 #{trans_message}" unless trans_message == message.message
77
+ elsif(message.message =~ /^(\S+[:, ])/)
78
+ message.message.slice!(0..$1.size)
79
+ Logger.info("Translate matched a followed nick: #{$1}")
80
+ nick = Helpers.find_model($1, false)
81
+ return unless nick.is_a?(Models::Nick)
82
+ if(@watchers[message.target.pk].has_key?(nick.pk))
83
+ reply message.replyto, "\2(#{do_translation("en|#{@watchers[message.target.pk][nick.pk]}", 'translation')})\2 #{do_translation("en|#{@watchers[message.target.pk][nick.pk]}", message.message)}"
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def do_translation(langs, text)
92
+ raise 'Unsupported language combination for translation' unless @allowed_trans.include?(langs.gsub(/\|/, '_'))
93
+ if(@cache.has_key?(langs) && @cache[langs].has_key?(text))
94
+ return @cache[langs][text]
95
+ end
96
+ headers = {'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'}
97
+ url = URI.parse('http://babelfish.yahoo.com/translate_txt')
98
+ post = Net::HTTP::Post.new(url.path, headers)
99
+ post.set_form_data({
100
+ 'ei' => 'UTF-8',
101
+ 'doit' => 'done',
102
+ 'fr' => 'bf-res',
103
+ 'intl' => '1',
104
+ 'tt' => 'urltext',
105
+ 'trtext' => text,
106
+ 'lp' => langs.gsub(/\|/, '_'),
107
+ 'btnTrTxt' => 'Translate'
108
+ })
109
+ result = Net::HTTP.new(url.host, url.port).start do |http|
110
+ http.request(post)
111
+ end
112
+ if(result.is_a?(Net::HTTPSuccess))
113
+ content = result.body
114
+ if(content =~ /<div id="result">(.+?)<input/im)
115
+ tr = $1
116
+ tr.gsub!(/<.+?>/, '')
117
+ tr.gsub!(/[\r\n]/, ' ')
118
+ tr.gsub!(/\s+/, ' ')
119
+ if(text.length < 15)
120
+ @cache[langs] = {} unless @cache.has_key?(langs)
121
+ @cache[langs][text] = tr
122
+ end
123
+ return Helpers.convert_entities(tr).strip
124
+ else
125
+ raise 'Failed to locate translation'
126
+ end
127
+ else
128
+ raise "Failed to receive result from server"
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,458 @@
1
+ require 'open-uri'
2
+ require 'uri'
3
+ require 'mod_spox/messages/internal/TimerAdd'
4
+ require 'mod_spox/messages/internal/TimerRemove'
5
+ class Twitter < ModSpox::Plugin
6
+
7
+ def initialize(pipeline)
8
+ super
9
+ begin
10
+ require 'htmlentities'
11
+ rescue Object => boom
12
+ Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
13
+ raise Exceptions::BotException.new("Missing required HTMLEntities library")
14
+ end
15
+ begin
16
+ require 'twitter'
17
+ require 'json'
18
+ c = %q{
19
+ class ModClient < Object::Twitter::Client
20
+ def login
21
+ return @login
22
+ end
23
+ def login=(l)
24
+ @login = l
25
+ end
26
+ def password
27
+ return @password
28
+ end
29
+ def password=(p)
30
+ @password = p
31
+ end
32
+ end
33
+ }
34
+ Twitter.class_eval(c)
35
+ ModClient.configure do |conf|
36
+ conf.user_agent = 'mod_spox twitter for twits'
37
+ conf.application_name = 'mod_spox IRC bot'
38
+ conf.application_version = "#{ModSpox.botversion} (#{ModSpox.botcodename})"
39
+ conf.application_url = 'http://rubyforge.org/projects/mod_spox'
40
+ conf.source = 'modspoxircbot'
41
+ end
42
+ rescue Object => boom
43
+ Logger.warn("Failed to load Twitter4R. Install gem to use Twitter plugin. (#{boom})")
44
+ raise Exceptions::BotException.new('Failed to locate required gem: Twitter4R')
45
+ end
46
+ twitter = Models::Group.find_or_create(:name => 'twitter')
47
+ admin = Models::Group.find_or_create(:name => 'admin')
48
+ add_sig(:sig => 'tweet (.+)', :method => :tweet, :group => twitter, :desc => 'Send a tweet', :params => [:message])
49
+ add_sig(:sig => 'twitter auth( (\S+) (\S+))?', :method => :auth, :group => admin, :desc => 'Set/view authentication information',
50
+ :params => [:info, :username, :password], :req => 'private')
51
+ add_sig(:sig => 'twitter search (.+)', :method => :search, :desc => 'Basic twitter search', :params => [:term])
52
+ add_sig(:sig => 'twitter asearch (.+)', :method => :advanced_search, :desc => 'Advanced search (http://apiwiki.twitter.com/Search-API-Documentation#Search)',
53
+ :params => [:term])
54
+ add_sig(:sig => 'twitter followers( \S+)?', :method => :followers, :desc => 'Show followers', :params => [:twit])
55
+ add_sig(:sig => 'twitter friends( \S+)?', :method => :friends, :desc => 'Show friends', :params => [:twit])
56
+ add_sig(:sig => 'twitter friend (\S+)', :method => :add_friend, :desc => 'Add a friend', :params => [:twit], :group => admin)
57
+ add_sig(:sig => 'twitter unfriend (\S+)', :method => :remove_friend, :desc => 'Remove a friend', :params => [:twit], :group => admin)
58
+ add_sig(:sig => 'twitter info', :method => :info, :desc => 'Show twitter info')
59
+ add_sig(:sig => 'twit (\S+) (.+)', :method => :twat, :group => twitter, :desc => 'Send a direct tweet to twit', :params => [:twit, :message])
60
+ add_sig(:sig => 'twit inbox', :method => :inbox, :group => twitter, :desc => 'Show inbox contents')
61
+ add_sig(:sig => 'twitter del (\d+)', :method => :inbox_del, :group => twitter, :desc => 'Delete direct message from twitter', :params => [:m_id])
62
+ add_sig(:sig => 'tweets del (\d+)', :method => :tweets_del, :group => twitter, :desc => 'Delete a status message from twitter', :params => [:m_id])
63
+ add_sig(:sig => 'tweets (\d+)', :method => :tweets, :desc => 'Get a given message or the current message', :params => [:m_id])
64
+ add_sig(:sig => 'autotweets ?(on|off)?', :method => :auto_tweets, :desc => 'Turn on/off auto tweet for a channel', :params => [:action],
65
+ :group => admin, :req => 'public')
66
+ add_sig(:sig => 'autotweets interval( \d+)?', :method => :auto_tweets_interval, :desc => 'Set/show interval for auto tweet checks',
67
+ :group => admin, :params => [:interval])
68
+ add_sig(:sig => 'autotweets burst( \d+)?', :method => :auto_tweets_burst, :desc => 'Set/show maximum number of tweets to display at once',
69
+ :group => admin, :params => [:burst])
70
+ add_sig(:sig => 'twitter alias (\S+) (\S+)', :method => :alias_user, :desc => 'Set alias for twitter account', :group => twitter, :params => [:twit, :irc])
71
+ add_sig(:sig => 'twitter aliases (\S+)', :method => :show_aliases, :desc => 'Show alias for twit', :params => [:twit])
72
+ add_sig(:sig => 'twitter dealias (\S+)', :method => :remove_alias, :desc => 'Remove alias for twit', :params => [:twit], :group => twitter)
73
+ @pipeline.hook(self, :get_timer, :Internal_TimerResponse)
74
+ @auth_info = Models::Setting.find_or_create(:name => 'twitter').value
75
+ @twitter = ModClient.new
76
+ @search_url = 'http://search.twitter.com/search.json'
77
+ @aliases = Models::Setting.find_or_create(:name => 'twitter_aliases').value
78
+ @aliases = {} if @aliases.nil?
79
+ @burst = Models::Setting.find_or_create(:name => 'twitter_burst').value
80
+ @burst = @burst.nil? ? 5 : @burst.to_i
81
+ unless(@auth_info.is_a?(Hash))
82
+ @auth_info = {:username => nil, :password => nil, :interval => 0, :channels => []}
83
+ else
84
+ connect if @twitter.authenticate?(@auth_info[:username], @auth_info[:password])
85
+ end
86
+ @last_check = Time.now
87
+ @lock = Mutex.new
88
+ @running = false
89
+ @timer = {:action => nil, :id => nil}
90
+ @friends = []
91
+ populate_friends
92
+ start_auto
93
+ end
94
+
95
+ def auto_tweets_burst(m, params)
96
+ if(params[:burst])
97
+ params[:burst] = params[:burst].to_i
98
+ if(params[:burst] == 0)
99
+ error m.replyto, 'Invalid value. Must supply a positive integer.'
100
+ else
101
+ @burst = params[:burst]
102
+ information m.replyto, "Updated maximum autotweet burst to: #{@burst}"
103
+ end
104
+ else
105
+ information m.replyto, "Maximum number of tweets to auto report: #{@burst}"
106
+ end
107
+ end
108
+
109
+ def alias_user(m, params)
110
+ begin
111
+ raise "twit #{params[:twit]} is not in my friends list" unless @friends.include?(params[:twit])
112
+ raise "twit is already aliased to #{Models::Nick[@aliases[params[:twit].to_sym]].nick}" if @aliases.has_key?(params[:twit].to_sym)
113
+ nick = Helpers.find_model(params[:irc])
114
+ raise "failed to find nick #{params[:irc]}. is this a new user?" if nick.nil?
115
+ @aliases[params[:twit].to_sym] = nick.pk
116
+ save_aliases
117
+ information m.replyto, "Nick #{params[:irc]} is now aliased to twit #{params[:twit]}"
118
+ rescue Object => boom
119
+ error m.replyto, "Failed to alias user: #{boom}"
120
+ end
121
+ end
122
+
123
+ def save_aliases
124
+ t = Models::Setting.find_or_create(:name => 'twitter_aliases')
125
+ t.value = @aliases
126
+ t.save
127
+ end
128
+
129
+ def show_aliases(m, params)
130
+ begin
131
+ raise "twit #{params[:twit]} has no alias" unless @aliases.has_key?(params[:twit].to_sym)
132
+ information m.replyto, "Twit #{params[:twit]} is aliased to: #{Models::Nick[@aliases[params[:twit].to_sym]].nick}"
133
+ rescue Object => boom
134
+ error m.replyto, "Failed to find alias. Reason: #{boom}"
135
+ end
136
+ end
137
+
138
+ def remove_alias(m, params)
139
+ begin
140
+ raise "twit #{params[:twit]} has no alias" unless @aliases.has_key?(params[:twit].to_sym)
141
+ @aliases.delete(params[:twit].to_sym)
142
+ save_aliases
143
+ information m.replyto, "Twit #{params[:twit]} is no longer aliased"
144
+ rescue Object => boom
145
+ error m.replyto, "Failed to remove alias: #{boom}"
146
+ end
147
+ end
148
+
149
+ def search(m, params)
150
+ url = URI.escape("#{@search_url}?rpp=1&q=#{params[:term]}")
151
+ reply m.replyto, do_search(url, params[:term])
152
+ end
153
+
154
+ def advanced_search(m, params)
155
+ opt = {:lang => nil, :rpp => 1, :page => 1, :since_id => nil}
156
+ term = params[:term]
157
+ opt.keys.each do |sym|
158
+ if(term =~ /\b#{sym.to_s}:(\S+)\b/)
159
+ opt[sym] = $1
160
+ term.sub!(/#{sym.to_s}:\S+/, '')
161
+ end
162
+ end
163
+ opt[:rpp] = 5 if opt[:rpp].to_i > 5
164
+ opt[:rpp] = 1 if opt[:rpp].to_i < 1
165
+ term.gsub!(/\s{2,}/, ' ')
166
+ url = URI.escape("#{@search_url}?q=#{term}&#{opt.to_a.map{|a| "#{a[0]}=#{a[1]}"}.join('&')}")
167
+ reply m.replyto, do_search(url, term)
168
+ end
169
+
170
+ def do_search(url, term)
171
+ begin
172
+ buf = open(url, 'UserAgent' => 'mod_spox IRC bot').read
173
+ result = JSON.parse(buf)
174
+ output = ["Twitter match for: \2#{term}:\2"]
175
+ result['results'].each do |item|
176
+ t = Time.parse(item['created_at'])
177
+ output << "[#{t.strftime("%Y/%m/%d-%H:%M:%S")}] <#{item['from_user']}> #{Helpers.convert_entities(item['text'])}"
178
+ end
179
+ if(output.size < 2)
180
+ output = "\2Error:\2 No results found for term: #{term}"
181
+ end
182
+ return output
183
+ rescue Object => boom
184
+ return "\2Error:\2 Failed to receive search results (over quota?)"
185
+ end
186
+ end
187
+
188
+ def inbox(m, params)
189
+ msgs = @twitter.messages(:received)
190
+ reply m.replyto, "\2Twitter INBOX\2 Messages in inbox: #{msgs.size} (only last 5 displayed)"
191
+ msgs.slice(0..5).each do | msg |
192
+ reply m.replyto, "\2#{msg.sender.screen_name}:\2 [#{msg.id}] #{Helpers.convert_entities(msg.text)}"
193
+ end
194
+ end
195
+
196
+ def inbox_del(m, params)
197
+ begin
198
+ @twitter.message(:delete, params[:m_id])
199
+ information m.replyto, "message with ID: #{params[:m_id]} has been deleted"
200
+ rescue Object => boom
201
+ warning m.replyto, "failed to delete message with ID: #{params[:m_id]}"
202
+ end
203
+ end
204
+
205
+ def tweets_del(m, params)
206
+ begin
207
+ @twitter.status(:delete, params[:m_id])
208
+ information m.replyto, "message with ID: #{params[:m_id]} has been deleted"
209
+ rescue Object => boom
210
+ warning m.replyto, "failed to delete status message with ID: #{params[:m_id]}"
211
+ end
212
+ end
213
+
214
+ def info(m, params)
215
+ unless(@auth_info[:username].nil?)
216
+ information m.replyto, "http://twitter.com/#{@auth_info[:username]}"
217
+ else
218
+ warning m.replyto, 'currently not configured'
219
+ end
220
+ end
221
+
222
+ def auto_tweets_interval(m, params)
223
+ if(params[:interval])
224
+ int = params[:interval].strip.to_i
225
+ @auth_info[:interval] = int
226
+ save_info
227
+ update_auto
228
+ information m.replyto, "auto tweet interval updated to: #{int > 0 ? int : 'stopped'}"
229
+ else
230
+ information m.replyto, "auto tweet interval is: #{@auth_info[:interval] > 0 ? "#{@auth_info[:interval]} seconds" : 'stopped'}"
231
+ end
232
+ end
233
+
234
+ def auto_tweets(m, params)
235
+ if(params[:action])
236
+ on = @auth_info[:channels].include?(m.target.id)
237
+ if(params[:action] == 'on')
238
+ if(on)
239
+ warning m.replyto, 'this channel is already enabled for auto tweets'
240
+ else
241
+ @auth_info[:channels] << m.target.id
242
+ save_info
243
+ update_auto
244
+ information m.replyto, 'auto tweets are now enabled for this channel'
245
+ end
246
+ else
247
+ if(on)
248
+ @auth_info[:channels].delete(m.target.id)
249
+ save_info
250
+ update_auto
251
+ information m.replyto, 'auto tweets are now disabled for this channel'
252
+ else
253
+ warning m.replyto, 'this channel is not currently enabled for auto tweets'
254
+ end
255
+ end
256
+ else
257
+ information m.replyto, "auto tweets currently enabled in: #{@auth_info[:channels].size > 0 ? @auth_info[:channels].map{|i| Models::Channel[i].name}.join(', ') : 'not enabled'}"
258
+ end
259
+ end
260
+
261
+ def auth(m, params)
262
+ if(params[:info])
263
+ begin
264
+ @auth_info[:username] = params[:username]
265
+ @auth_info[:password] = params[:password]
266
+ @twitter.authenticate?(params[:username], params[:password])
267
+ save_info
268
+ information m.replyto, 'Authentication information has been updated'
269
+ rescue Object => boom
270
+ error m.replyto, "Failed to save authentication information: #{boom}"
271
+ end
272
+ else
273
+ information m.replyto, "username -> #{@auth_info[:username].nil? ? 'unset' : @auth_info[:username]} password -> #{@auth_info[:password].nil? ? 'unset' : @auth_info[:password]}"
274
+ end
275
+ end
276
+
277
+ def tweet(m, params)
278
+ begin
279
+ @twitter.status(:post, params[:message])
280
+ information m.replyto, 'tweet has been sent'
281
+ rescue Object => boom
282
+ error m.replyto, "failed to send tweet. (#{boom})"
283
+ end
284
+ end
285
+
286
+ def twat(m, params)
287
+ begin
288
+ user = @twitter.user(params[:twit])
289
+ @twitter.message(:post, params[:message], user)
290
+ information m.replyto, 'tweet has been sent'
291
+ rescue Object => boom
292
+ error m.replyto, "failed to send tweet. (#{boom})"
293
+ end
294
+ end
295
+
296
+ def followers(m, params)
297
+ begin
298
+ fs = @twitter.my(:followers)
299
+ if(fs.size > 0)
300
+ reply m.replyto, "\2Followers:\2 #{fs.map{|u| u.screen_name}.join(', ')}"
301
+ else
302
+ warning m.replyto, 'no followers found'
303
+ end
304
+ rescue Object => boom
305
+ error m.replyto, "failed to locate followers list. (#{boom})"
306
+ end
307
+ end
308
+
309
+ def friends(m, params)
310
+ if(@friends.size > 0)
311
+ reply m.replyto, "\2Friends:\2 #{@friends.join(', ')}"
312
+ else
313
+ warning m.replyto, 'no friends found'
314
+ end
315
+ end
316
+
317
+ def add_friend(m, params)
318
+ begin
319
+ user = @twitter.user(params[:twit])
320
+ unless(@twitter.my(:friends).include?(user))
321
+ @twitter.friend(:add, user)
322
+ information m.replyto, "added new friend: #{params[:twit]}"
323
+ @friends << params[:twit]
324
+ else
325
+ warning m.replyto, "#{params[:twit]} is already in friend list"
326
+ end
327
+ rescue Object => boom
328
+ error m.replyto, "failed to add friend #{params[:twit]}. (#{boom})"
329
+ end
330
+ end
331
+
332
+ def remove_friend(m, params)
333
+ begin
334
+ user = @twitter.user(params[:twit])
335
+ if(@twitter.my(:friends).map{|u|u.screen_name}.include?(user.screen_name))
336
+ @twitter.friend(:remove, user)
337
+ information m.replyto, "removed user from friend list: #{params[:twit]}"
338
+ @friends.delete(params[:twit])
339
+ else
340
+ warning m.replyto, "#{params[:twit]} is not in friend list"
341
+ end
342
+ rescue Object => boom
343
+ error m.replyto, "failed to remove friend #{params[:twit]}. (#{boom})"
344
+ end
345
+ end
346
+
347
+ def tweets(m, params)
348
+ begin
349
+ msg = @twitter.status(:get, params[:m_id])
350
+ if(msg)
351
+ reply m.replyto, "\2Tweet:\2 [#{msg.created_at.strftime("%Y/%m/%d-%H:%M:%S")}] <#{screen_name(msg.user.screen_name)}> #{Helpers.convert_entities(msg.text)}"
352
+ else
353
+ warning m.replyto, "failed to find message with ID: #{params[:m_id].strip}"
354
+ end
355
+ rescue Object => boom
356
+ error m.replyto, "error encountered while attempting to fetch message. (#{boom})"
357
+ end
358
+ end
359
+
360
+ private
361
+
362
+ def populate_friends
363
+ return unless @lock.try_lock
364
+ begin
365
+ fs = @twitter.my(:friends)
366
+ @friends = []
367
+ if(fs.size > 0)
368
+ @friends = fs.map{|u| u.screen_name}
369
+ end
370
+ rescue Object => boom
371
+ Logger.info("Failed to populate friends: #{boom}")
372
+ @pipeline << Messages::Internal::TimerAdd.new(self, 200, nil, true){ populate_friends }
373
+ ensure
374
+ @lock.unlock
375
+ end
376
+ end
377
+
378
+ def screen_name(n)
379
+ return @aliases.has_key?(n.to_sym) ? Models::Nick[@aliases[n.to_sym]].nick : n
380
+ end
381
+
382
+ def replace_names(s)
383
+ s.scan(/@\S+/).each do |n|
384
+ n.slice!(0)
385
+ s.gsub!("@#{n}", "@#{screen_name(n)}")
386
+ end
387
+ return s
388
+ end
389
+
390
+ def check_timeline
391
+ if(@auth_info[:channels].size < 1 || @auth_info[:interval].to_i < 1)
392
+ Logger.warn('Twitter has no channels to send information to')
393
+ else
394
+ begin
395
+ things = []
396
+ @twitter.my(:friends).each do |f|
397
+ @twitter.timeline_for(:friend, :id => f.screen_name, :since => @last_check) do |status|
398
+ next if status.created_at < @last_check
399
+ if(Helpers.convert_entities(status.text) =~ /^@(\S+)/)
400
+ next unless @twitter.my(:friends).map{|f|f.screen_name}.include?($1) || $1 == @twitter.login
401
+ end
402
+ things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{screen_name(status.user.screen_name)}> #{Helpers.convert_entities(replace_names(status.text))}"
403
+ end
404
+ end
405
+ @twitter.timeline_for(:me, :since => @last_check) do |status|
406
+ next if status.created_at < @last_check
407
+ things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{screen_name(status.user.screen_name)}> #{Helpers.convert_entities(replace_names(status.text))}"
408
+ end
409
+ unless(things.empty?)
410
+ things.uniq!
411
+ things.sort!
412
+ things = things[-@burst,@burst] if things.size > @burst
413
+ things.each do |status|
414
+ @auth_info[:channels].each{|i| reply Models::Channel[i], "\2AutoTweet:\2 #{status}"}
415
+ end
416
+ end
417
+ @last_check = Time.now
418
+ rescue Object => boom
419
+ Logger.warn("Twitter encountered an error during autotweets check: #{boom}")
420
+ end
421
+ end
422
+ end
423
+
424
+ def save_info
425
+ i = Models::Setting.find_or_create(:name => 'twitter')
426
+ i.value = @auth_info
427
+ i.save
428
+ end
429
+
430
+ def connect
431
+ @twitter.login = @auth_info[:username]
432
+ @twitter.password = @auth_info[:password]
433
+ end
434
+
435
+ def get_timer(m)
436
+ if(m.id == @timer[:id])
437
+ @timer[:action] = m.action_added? ? m.action : nil
438
+ end
439
+ end
440
+
441
+ def update_auto
442
+ if(@auth_info[:interval] > 0 && !@auth_info[:channels].empty?)
443
+ @pipeline << Messages::Internal::TimerRemove.new(@timer[:action]) if @timer[:action].nil?
444
+ start_auto
445
+ else
446
+ @pipeline << Messages::Internal::TimerRemove.new(@timer[:action]) unless @timer[:action].nil?
447
+ end
448
+ end
449
+
450
+ def start_auto
451
+ if(@auth_info[:interval] > 0 && @timer[:action].nil?)
452
+ m = Messages::Internal::TimerAdd.new(self, @auth_info[:interval].to_i){ check_timeline }
453
+ @timer[:id] = m.id
454
+ @pipeline << m
455
+ end
456
+ end
457
+
458
+ end