mod_spox 0.2.0 → 0.3.0

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 (145) hide show
  1. data/CHANGELOG +31 -1
  2. data/LICENSE +674 -0
  3. data/README.rdoc +73 -0
  4. data/bin/mod_spox +28 -28
  5. data/data/mod_spox/extras/AOLSpeak.rb +2 -3
  6. data/data/mod_spox/extras/AutoKick.rb +10 -23
  7. data/data/mod_spox/extras/AutoMode.rb +12 -23
  8. data/data/mod_spox/extras/Bash.rb +55 -0
  9. data/data/mod_spox/extras/Bouncer.rb +85 -57
  10. data/data/mod_spox/extras/Bullshit.rb +1 -1
  11. data/data/mod_spox/extras/Bytes.rb +1 -2
  12. data/data/mod_spox/extras/Confess.rb +27 -29
  13. data/data/mod_spox/extras/DCC.rb +11 -20
  14. data/data/mod_spox/extras/DevWatch.rb +21 -23
  15. data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
  16. data/data/mod_spox/extras/EightBall.rb +1 -1
  17. data/data/mod_spox/extras/FML.rb +35 -0
  18. data/data/mod_spox/extras/Headers.rb +31 -50
  19. data/data/mod_spox/extras/Karma.rb +81 -29
  20. data/data/mod_spox/extras/Logger.rb +2 -2
  21. data/data/mod_spox/extras/LolSpeak.rb +1 -2
  22. data/data/mod_spox/extras/PhpCli.rb +138 -8
  23. data/data/mod_spox/extras/PhpFuncLookup.rb +20 -23
  24. data/data/mod_spox/extras/Pinger.rb +1 -1
  25. data/data/mod_spox/extras/Quotes.rb +8 -10
  26. data/data/mod_spox/extras/RegexTracker.rb +2 -4
  27. data/data/mod_spox/extras/Roulette.rb +20 -27
  28. data/data/mod_spox/extras/RubyCli.rb +93 -0
  29. data/data/mod_spox/extras/Search.rb +17 -3
  30. data/data/mod_spox/extras/Seen.rb +150 -0
  31. data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
  32. data/data/mod_spox/extras/Talk.rb +2 -4
  33. data/data/mod_spox/extras/Topten.rb +10 -12
  34. data/data/mod_spox/extras/TracTicket.rb +3 -5
  35. data/data/mod_spox/extras/Translate.rb +20 -22
  36. data/data/mod_spox/extras/Twitter.rb +118 -33
  37. data/data/mod_spox/extras/UrbanDictionary.rb +8 -17
  38. data/data/mod_spox/extras/Weather.rb +1 -2
  39. data/data/mod_spox/plugins/Authenticator.rb +93 -98
  40. data/data/mod_spox/plugins/Banner.rb +26 -56
  41. data/data/mod_spox/plugins/Helper.rb +5 -6
  42. data/data/mod_spox/plugins/Initializer.rb +4 -14
  43. data/data/mod_spox/plugins/Joiner.rb +1 -1
  44. data/data/mod_spox/plugins/Nicker.rb +13 -0
  45. data/data/mod_spox/plugins/Parter.rb +2 -2
  46. data/data/mod_spox/plugins/Permissions.rb +60 -0
  47. data/data/mod_spox/plugins/PluginLoader.rb +7 -12
  48. data/data/mod_spox/plugins/Ponger.rb +51 -0
  49. data/data/mod_spox/plugins/Quitter.rb +1 -2
  50. data/data/mod_spox/plugins/Servers.rb +57 -0
  51. data/data/mod_spox/plugins/Status.rb +3 -2
  52. data/data/mod_spox/plugins/Triggers.rb +9 -9
  53. data/lib/mod_spox/Bot.rb +109 -33
  54. data/lib/mod_spox/BotConfig.rb +2 -2
  55. data/lib/mod_spox/ConfigurationWizard.rb +12 -12
  56. data/lib/mod_spox/Database.rb +1 -4
  57. data/lib/mod_spox/Exceptions.rb +26 -0
  58. data/lib/mod_spox/Helpers.rb +29 -68
  59. data/lib/mod_spox/Loader.rb +23 -24
  60. data/lib/mod_spox/Logger.rb +19 -17
  61. data/lib/mod_spox/MessageFactory.rb +50 -24
  62. data/lib/mod_spox/Pipeline.rb +21 -7
  63. data/lib/mod_spox/Plugin.rb +27 -3
  64. data/lib/mod_spox/PluginManager.rb +28 -15
  65. data/lib/mod_spox/PriorityQueue.rb +69 -0
  66. data/lib/mod_spox/Socket.rb +93 -51
  67. data/lib/mod_spox/Sockets.rb +76 -63
  68. data/lib/mod_spox/Timer.rb +21 -141
  69. data/lib/mod_spox/Version.rb +14 -0
  70. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  71. data/lib/mod_spox/handlers/Bounce.rb +5 -5
  72. data/lib/mod_spox/handlers/Created.rb +13 -5
  73. data/lib/mod_spox/handlers/Handler.rb +12 -3
  74. data/lib/mod_spox/handlers/Invite.rb +14 -8
  75. data/lib/mod_spox/handlers/Join.rb +24 -20
  76. data/lib/mod_spox/handlers/Kick.rb +22 -13
  77. data/lib/mod_spox/handlers/Mode.rb +42 -36
  78. data/lib/mod_spox/handlers/Motd.rb +4 -0
  79. data/lib/mod_spox/handlers/Names.rb +66 -39
  80. data/lib/mod_spox/handlers/Nick.rb +20 -14
  81. data/lib/mod_spox/handlers/Part.rb +25 -8
  82. data/lib/mod_spox/handlers/Ping.rb +11 -5
  83. data/lib/mod_spox/handlers/Pong.rb +9 -5
  84. data/lib/mod_spox/handlers/Privmsg.rb +25 -17
  85. data/lib/mod_spox/handlers/Quit.rb +13 -8
  86. data/lib/mod_spox/handlers/Topic.rb +4 -0
  87. data/lib/mod_spox/handlers/Welcome.rb +16 -24
  88. data/lib/mod_spox/handlers/Who.rb +64 -48
  89. data/lib/mod_spox/handlers/Whois.rb +92 -60
  90. data/lib/mod_spox/messages/incoming/Nick.rb +2 -2
  91. data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -1
  92. data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
  93. data/lib/mod_spox/messages/internal/EstablishConnection.rb +1 -1
  94. data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
  95. data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
  96. data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
  97. data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
  98. data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
  99. data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
  100. data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
  101. data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
  102. data/lib/mod_spox/models/Auth.rb +16 -46
  103. data/lib/mod_spox/models/AuthMask.rb +13 -0
  104. data/lib/mod_spox/models/Channel.rb +46 -27
  105. data/lib/mod_spox/models/Config.rb +10 -19
  106. data/lib/mod_spox/models/Group.rb +20 -8
  107. data/lib/mod_spox/models/Models.rb +1 -1
  108. data/lib/mod_spox/models/Nick.rb +105 -113
  109. data/lib/mod_spox/models/NickMode.rb +23 -9
  110. data/lib/mod_spox/models/Server.rb +12 -1
  111. data/lib/mod_spox/models/Setting.rb +12 -16
  112. data/lib/mod_spox/models/Signature.rb +28 -8
  113. data/tests/BotHolder.rb +24 -0
  114. data/tests/handlers/tc_BadNick.rb +21 -0
  115. data/tests/handlers/tc_Created.rb +24 -0
  116. data/tests/handlers/tc_Invite.rb +50 -0
  117. data/tests/handlers/tc_Join.rb +33 -0
  118. data/tests/handlers/tc_Kick.rb +32 -0
  119. data/tests/handlers/tc_Mode.rb +85 -0
  120. data/tests/handlers/tc_Names.rb +35 -0
  121. data/tests/handlers/tc_Nick.rb +55 -0
  122. data/tests/handlers/tc_Part.rb +44 -0
  123. data/tests/handlers/tc_Ping.rb +40 -0
  124. data/tests/handlers/tc_Pong.rb +28 -0
  125. data/tests/handlers/tc_Privmsg.rb +85 -0
  126. data/tests/handlers/tc_Quit.rb +40 -0
  127. data/tests/handlers/tc_Who.rb +50 -0
  128. data/tests/handlers/tc_Whois.rb +61 -0
  129. data/tests/models/tc_Auth.rb +34 -0
  130. data/tests/models/tc_Channel.rb +52 -0
  131. data/tests/models/tc_Config.rb +19 -0
  132. data/tests/models/tc_Nick.rb +142 -0
  133. data/tests/models/tc_NickMode.rb +40 -0
  134. data/tests/models/tc_Setting.rb +21 -0
  135. data/tests/models/tc_Signature.rb +14 -0
  136. data/tests/run_tests.rb +4 -0
  137. metadata +284 -212
  138. data/README +0 -36
  139. data/lib/mod_spox/Cache.rb +0 -57
  140. data/lib/mod_spox/Monitors.rb +0 -84
  141. data/lib/mod_spox/Pool.rb +0 -164
  142. data/lib/mod_spox/models/AuthGroup.rb +0 -16
  143. data/lib/mod_spox/models/ChannelMode.rb +0 -14
  144. data/lib/mod_spox/models/NickChannel.rb +0 -45
  145. data/lib/mod_spox/models/NickGroup.rb +0 -16
@@ -5,10 +5,8 @@ class Talk < ModSpox::Plugin
5
5
  def initialize(pipeline)
6
6
  super
7
7
  group = Group.find_or_create(:name => 'talk')
8
- Signature.find_or_create(:signature => 'say (\S+) (.+)', :plugin => name, :method => 'talk', :group_id => group.pk,
9
- :description => 'Make bot speak given text to target', :requirement => 'private').params = [:target, :text]
10
- Signature.find_or_create(:signature => 'action (\S+) (.+)', :plugin => name, :method => 'action', :group_id => group.pk,
11
- :description => 'Make bot perform action for target', :requirement => 'private').params = [:target, :text]
8
+ add_sig(:sig => 'say (\S+) (.+)', :method => :talk, :group => group, :desc => 'Make bot speak given text to target', :req => 'private', :params => [:target, :text])
9
+ add_sig(:sig => 'action (\S+) (.+)', :method => :action, :group => group, :desc => 'Make bot perform action for target', :req => 'private', :params => [:target, :text])
12
10
  end
13
11
 
14
12
  def talk(message, params)
@@ -5,20 +5,16 @@ class Topten < ModSpox::Plugin
5
5
  def initialize(pipeline)
6
6
  super
7
7
  ChatStat.create_table unless ChatStat.table_exists?
8
- Signature.find_or_create(:signature => 'topten', :plugin => name, :method => 'topten',
9
- :requirement => 'public', :description => 'Show topten users since midnight')
10
- Signature.find_or_create(:signature => 'topten ([0-9]{4}\/[0-9]{2}\/[0-9]{2})', :plugin => name, :method => 'archive',
11
- :description => 'Show topten from given date', :requirement => 'public').params = [:date]
12
- Signature.find_or_create(:signature => 'stats ?(\S+)?', :plugin => name, :method => 'stats', :description => 'Show stats on nick',
13
- :requirement => 'public').params = [:nick]
14
- Signature.find_or_create(:signature => 'stats lifetime (\S+)?', :plugin => name, :method => 'life_stats',
15
- :description => 'Show stat totals for given nick', :requirement => 'public').params = [:nick]
8
+ add_sig(:sig => 'topten', :method => :topten, :req => 'public', :desc => 'Show topten users since midnight')
9
+ add_sig(:sig => 'topten ([0-9]{4}\/[0-9]{2}\/[0-9]{2})', :method => :archive, :desc => 'Show topten from given date', :req => 'public', :params => [:date])
10
+ add_sig(:sig => 'stats ?(\S+)?', :method => :stats, :desc => 'Show stats on nick', :req => 'public', :params => [:nick])
11
+ add_sig(:sig => 'stats lifetime (\S+)?', :method => :life_stats, :desc => 'Show stat totals for given nick', :req => 'public', :params => [:nick])
16
12
  @pipeline.hook(self, :log_stats, :Incoming_Privmsg)
17
13
  end
18
14
 
19
15
  def topten(m, p)
20
16
  stats = ChatStat.filter(:channel_id => m.target.pk, :daykey => construct_daykey).reverse_order(:bytes).limit(10)
21
- if(stats.size > 0)
17
+ if(stats.count > 0)
22
18
  users = []
23
19
  stats.each do |stat|
24
20
  bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
@@ -32,7 +28,7 @@ class Topten < ModSpox::Plugin
32
28
 
33
29
  def archive(m, p)
34
30
  stats = ChatStat.filter(:channel_id => m.target.pk, :daykey => p[:date]).reverse_order(:bytes).limit(10)
35
- if(stats.size > 0)
31
+ if(stats.count > 0)
36
32
  users = []
37
33
  stats.each do |stat|
38
34
  bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
@@ -62,8 +58,8 @@ class Topten < ModSpox::Plugin
62
58
  def life_stats(m, p)
63
59
  nick = p[:nick] ? Nick.locate(p[:nick], false) : m.source
64
60
  if(nick)
65
- result = ChatStat.group(:nick_id).select(:SUM[:bytes].as(:tbytes), :SUM[:words].as(:twords), :SUM[:questions].as(:tquestions)).filter(:nick_id => nick.pk).first
66
- bytes = (result[:tbytes] > 1023) ? "#{sprintf('%.2f', (result[:tbytes] / 1024.0))}kb" : "#{result[:tbytes]}b"
61
+ result = ChatStat.group(:nick_id).select('SUM(bytes) as tbytes'.lit, 'SUM(words) as twords'.lit, 'SUM(questions) as tquestions'.lit).filter(:nick_id => nick.pk).first
62
+ bytes = (result[:tbytes].to_i > 1023) ? "#{sprintf('%.2f', (result[:tbytes].to_i / 1024.0))}kb" : "#{result[:tbytes]}b"
67
63
  reply m.replyto, "#{nick.nick} (total): #{bytes} logged, #{result[:twords]} words spoken and #{result[:tquestions]} questions asked"
68
64
  else
69
65
  reply m.replyto, "\2Error:\2 Failed to find #{p[:nick]}"
@@ -100,6 +96,8 @@ class Topten < ModSpox::Plugin
100
96
  foreign_key :channel_id, :table => :channels
101
97
  foreign_key :nick_id, :table => :nicks
102
98
  end
99
+ many_to_one :channel, :class => ModSpox::Models::Channel
100
+ many_to_one :nick, :class => ModSpox::Models::Nick
103
101
  end
104
102
 
105
103
  end
@@ -10,14 +10,12 @@ class TracTicket < ModSpox::Plugin
10
10
  add_sig(:sig => 'ticket trac( (\S+))?', :method => :trac_location, :group => admin,
11
11
  :desc => 'Show/set trac site', :params => [:trash, :site])
12
12
  add_sig(:sig => 'ticket site', :method => :trac_location, :desc => 'Show trac site')
13
- @site = Config[:trac]
13
+ @site = Config.val(:trac)
14
14
  end
15
15
 
16
16
  def trac_location(message, params)
17
17
  if(params[:site])
18
- site = Config.find_or_create(:name => 'trac')
19
- site.value = params[:site]
20
- site.save
18
+ site = Config.set(:trac, params[:site])
21
19
  @site = params[:site]
22
20
  reply message.replyto, "\2Trac Update:\2 Location of trac system has been updated: #{params[:site]}"
23
21
  else
@@ -44,7 +42,7 @@ class TracTicket < ModSpox::Plugin
44
42
  'Referer' => @site,
45
43
  'Content-Type' => 'application/x-www-form-urlencoded'
46
44
  }
47
- data = "reporter=#{URI.escape(message.source.nick)}&summary=#{URI.escape(params[:short])}&description=#{URI.escape(long)}&type=#{URI.escape(params[:type])}&action=create&status=new&priority=minor&__FORM_TOKEN=#{URI.escape(fid)}"
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)}"
48
46
  resp, data = con.post(path, data, headers)
49
47
  reply message.replyto, 'Ticket was successfully added to tracker'
50
48
  rescue Object => boom
@@ -4,23 +4,13 @@ class Translate < ModSpox::Plugin
4
4
 
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
- begin
8
- require 'htmlentities'
9
- rescue Object => boom
10
- Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
11
- raise Exceptions::BotException.new("Missing required HTMLEntities library")
12
- end
13
- Signature.find_or_create(:signature => 'translate ([a-z]{2}\|[a-z]{2}) (.+)', :plugin => name, :method => 'translate',
14
- :description => 'Translate text').params = [:lang, :text]
15
- Signature.find_or_create(:signature => 'autotranslate add ([a-z]{2}) (\S+)', :plugin => name, :method => 'auto_add',
16
- :description => 'Add a nick to the autotranslate service').params = [:lang, :nick]
17
- Signature.find_or_create(:signature => 'autotranslate remove (\S+)', :plugin => name, :method => 'auto_remove',
18
- :description => 'Remove a nick from the autotranslate service').params = [:nick]
19
- add_sig(:sig => 'translate languages', :method => 'langs', :description => 'Show available languages')
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')
20
11
  @pipeline.hook(self, :listener, :Incoming_Privmsg)
21
12
  @watchers = {}
22
13
  @cache = {}
23
- @coder = HTMLEntities.new
24
14
  @allowed = {'zh'=>'Chinese-simplified','zt'=>'Chinese-traditional','en'=>'English','nl'=>'Dutch',
25
15
  'fr'=>'French','de'=>'German','el'=>'Greek','it'=>'Italian','ja'=>'Japanese',
26
16
  'ko'=>'Korean','pt'=>'Portuguese','ru'=>'Russian','es'=>'Spanish'}
@@ -82,12 +72,13 @@ class Translate < ModSpox::Plugin
82
72
  def listener(message)
83
73
  if(message.is_public? && @watchers.has_key?(message.target.pk))
84
74
  if(@watchers[message.target.pk].has_key?(message.source.pk))
85
- trans_message = do_translation("#{@watchers[message.target.pk][message.source.pk]}en", message.message)
75
+ trans_message = do_translation("#{@watchers[message.target.pk][message.source.pk]}|en", message.message)
86
76
  reply message.replyto, "\2Translation (#{message.source.nick}):\2 #{trans_message}" unless trans_message == message.message
87
- elsif(message.message =~ /^(\S+)[:,]/)
77
+ elsif(message.message =~ /^(\S+[:, ])/)
78
+ message.message.slice!(0..$1.size)
88
79
  Logger.info("Translate matched a followed nick: #{$1}")
89
80
  nick = Helpers.find_model($1, false)
90
- return unless nick
81
+ return unless nick.is_a?(Models::Nick)
91
82
  if(@watchers[message.target.pk].has_key?(nick.pk))
92
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)}"
93
84
  end
@@ -102,17 +93,24 @@ class Translate < ModSpox::Plugin
102
93
  if(@cache.has_key?(langs) && @cache[langs].has_key?(text))
103
94
  return @cache[langs][text]
104
95
  end
105
- content = Net::HTTP.post_form(URI.parse('http://babelfish.yahoo.com/translate_txt'), {
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({
106
100
  'ei' => 'UTF-8',
107
101
  'doit' => 'done',
108
- 'fr' => 'bf-home',
102
+ 'fr' => 'bf-res',
109
103
  'intl' => '1',
110
104
  'tt' => 'urltext',
111
105
  'trtext' => text,
112
106
  'lp' => langs.gsub(/\|/, '_'),
113
107
  'btnTrTxt' => 'Translate'
114
- }).body
115
- if(content)
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
116
114
  if(content =~ /<div id="result">(.+?)<input/im)
117
115
  tr = $1
118
116
  tr.gsub!(/<.+?>/, '')
@@ -122,7 +120,7 @@ class Translate < ModSpox::Plugin
122
120
  @cache[langs] = {} unless @cache.has_key?(langs)
123
121
  @cache[langs][text] = tr
124
122
  end
125
- return @coder.decode(tr).strip
123
+ return Helpers.convert_entities(tr).strip
126
124
  else
127
125
  raise 'Failed to locate translation'
128
126
  end
@@ -34,7 +34,7 @@ class Twitter < ModSpox::Plugin
34
34
  ModClient.configure do |conf|
35
35
  conf.user_agent = 'mod_spox twitter for twits'
36
36
  conf.application_name = 'mod_spox IRC bot'
37
- conf.application_version = "#{$BOTVERSION} (#{$BOTCODENAME})"
37
+ conf.application_version = "#{ModSpox.botversion} (#{ModSpox.botcodename})"
38
38
  conf.application_url = 'http://rubyforge.org/projects/mod_spox'
39
39
  conf.source = 'modspoxircbot'
40
40
  end
@@ -64,11 +64,19 @@ class Twitter < ModSpox::Plugin
64
64
  :group => admin, :req => 'public')
65
65
  add_sig(:sig => 'autotweets interval( \d+)?', :method => :auto_tweets_interval, :desc => 'Set/show interval for auto tweet checks',
66
66
  :group => admin, :params => [:interval])
67
+ add_sig(:sig => 'autotweets burst( \d+)?', :method => :auto_tweets_burst, :desc => 'Set/show maximum number of tweets to display at once',
68
+ :group => admin, :params => [:burst])
69
+ add_sig(:sig => 'twitter alias (\S+) (\S+)', :method => :alias_user, :desc => 'Set alias for twitter account', :group => twitter, :params => [:twit, :irc])
70
+ add_sig(:sig => 'twitter aliases (\S+)', :method => :show_aliases, :desc => 'Show alias for twit', :params => [:twit])
71
+ add_sig(:sig => 'twitter dealias (\S+)', :method => :remove_alias, :desc => 'Remove alias for twit', :params => [:twit], :group => twitter)
67
72
  @pipeline.hook(self, :get_timer, :Internal_TimerResponse)
68
73
  @auth_info = Models::Setting.find_or_create(:name => 'twitter').value
69
74
  @twitter = ModClient.new
70
- @coder = HTMLEntities.new
71
75
  @search_url = 'http://search.twitter.com/search.json'
76
+ @aliases = Models::Setting.find_or_create(:name => 'twitter_aliases').value
77
+ @aliases = {} if @aliases.nil?
78
+ @burst = Models::Setting.find_or_create(:name => 'twitter_burst').value
79
+ @burst = @burst.nil? ? 5 : @burst.to_i
72
80
  unless(@auth_info.is_a?(Hash))
73
81
  @auth_info = {:username => nil, :password => nil, :interval => 0, :channels => []}
74
82
  else
@@ -78,8 +86,64 @@ class Twitter < ModSpox::Plugin
78
86
  @lock = Mutex.new
79
87
  @running = false
80
88
  @timer = {:action => nil, :id => nil}
89
+ @friends = []
90
+ populate_friends
81
91
  start_auto
82
92
  end
93
+
94
+ def auto_tweets_burst(m, params)
95
+ if(params[:burst])
96
+ params[:burst] = params[:burst].to_i
97
+ if(params[:burst] == 0)
98
+ error m.replyto, 'Invalid value. Must supply a positive integer.'
99
+ else
100
+ @burst = params[:burst]
101
+ information m.replyto, "Updated maximum autotweet burst to: #{@burst}"
102
+ end
103
+ else
104
+ information m.replyto, "Maximum number of tweets to auto report: #{@burst}"
105
+ end
106
+ end
107
+
108
+ def alias_user(m, params)
109
+ begin
110
+ raise "twit #{params[:twit]} is not in my friends list" unless @friends.include?(params[:twit])
111
+ raise "twit is already aliased to #{Models::Nick[@aliases[params[:twit].to_sym]].nick}" if @aliases.has_key?(params[:twit].to_sym)
112
+ nick = Helpers.find_model(params[:irc])
113
+ raise "failed to find nick #{params[:irc]}. is this a new user?" if nick.nil?
114
+ @aliases[params[:twit].to_sym] = nick.pk
115
+ save_aliases
116
+ information m.replyto, "Nick #{params[:irc]} is now aliased to twit #{params[:twit]}"
117
+ rescue Object => boom
118
+ error m.replyto, "Failed to alias user: #{boom}"
119
+ end
120
+ end
121
+
122
+ def save_aliases
123
+ t = Models::Setting.find_or_create(:name => 'twitter_aliases')
124
+ t.value = @aliases
125
+ t.save
126
+ end
127
+
128
+ def show_aliases(m, params)
129
+ begin
130
+ raise "twit #{params[:twit]} has no alias" unless @aliases.has_key?(params[:twit].to_sym)
131
+ information m.replyto, "Twit #{params[:twit]} is aliased to: #{Models::Nick[@aliases[params[:twit].to_sym]].nick}"
132
+ rescue Object => boom
133
+ error m.replyto, "Failed to find alias. Reason: #{boom}"
134
+ end
135
+ end
136
+
137
+ def remove_alias(m, params)
138
+ begin
139
+ raise "twit #{params[:twit]} has no alias" unless @aliases.has_key?(params[:twit].to_sym)
140
+ @aliases.delete(params[:twit].to_sym)
141
+ save_aliases
142
+ information m.replyto, "Twit #{params[:twit]} is no longer aliased"
143
+ rescue Object => boom
144
+ error m.replyto, "Failed to remove alias: #{boom}"
145
+ end
146
+ end
83
147
 
84
148
  def search(m, params)
85
149
  url = URI.escape("#{@search_url}?rpp=1&q=#{params[:term]}")
@@ -109,7 +173,10 @@ class Twitter < ModSpox::Plugin
109
173
  output = ["Twitter match for: \2#{term}:\2"]
110
174
  result['results'].each do |item|
111
175
  t = Time.parse(item['created_at'])
112
- output << "[#{t.strftime("%Y/%m/%d-%H:%M:%S")}] <#{item['from_user']}> #{item['text']}"
176
+ output << "[#{t.strftime("%Y/%m/%d-%H:%M:%S")}] <#{item['from_user']}> #{Helpers.convert_entities(item['text'])}"
177
+ end
178
+ if(output.size < 2)
179
+ output = "\2Error:\2 No results found for term: #{term}"
113
180
  end
114
181
  return output
115
182
  rescue Object => boom
@@ -121,7 +188,7 @@ class Twitter < ModSpox::Plugin
121
188
  msgs = @twitter.messages(:received)
122
189
  reply m.replyto, "\2Twitter INBOX\2 Messages in inbox: #{msgs.size} (only last 5 displayed)"
123
190
  msgs.slice(0..5).each do | msg |
124
- reply m.replyto, "\2#{msg.sender.screen_name}:\2 [#{msg.id}] #{@coder.decode(msg.text)}"
191
+ reply m.replyto, "\2#{msg.sender.screen_name}:\2 [#{msg.id}] #{Helpers.convert_entities(msg.text)}"
125
192
  end
126
193
  end
127
194
 
@@ -239,15 +306,10 @@ class Twitter < ModSpox::Plugin
239
306
  end
240
307
 
241
308
  def friends(m, params)
242
- begin
243
- fs = @twitter.my(:friends)
244
- if(fs.size > 0)
245
- reply m.replyto, "\2Friends:\2 #{fs.map{|u| u.screen_name}.join(', ')}"
246
- else
247
- warning m.replyto, 'no friends found'
248
- end
249
- rescue Object => boom
250
- error m.replyto, "failed to locate friends list. (#{boom})"
309
+ if(@friends.size > 0)
310
+ reply m.replyto, "\2Friends:\2 #{@friends.join(', ')}"
311
+ else
312
+ warning m.replyto, 'no friends found'
251
313
  end
252
314
  end
253
315
 
@@ -257,6 +319,7 @@ class Twitter < ModSpox::Plugin
257
319
  unless(@twitter.my(:friends).include?(user))
258
320
  @twitter.friend(:add, user)
259
321
  information m.replyto, "added new friend: #{params[:twit]}"
322
+ @friends << params[:twit]
260
323
  else
261
324
  warning m.replyto, "#{params[:twit]} is already in friend list"
262
325
  end
@@ -271,6 +334,7 @@ class Twitter < ModSpox::Plugin
271
334
  if(@twitter.my(:friends).map{|u|u.screen_name}.include?(user.screen_name))
272
335
  @twitter.friend(:remove, user)
273
336
  information m.replyto, "removed user from friend list: #{params[:twit]}"
337
+ @friends.delete(params[:twit])
274
338
  else
275
339
  warning m.replyto, "#{params[:twit]} is not in friend list"
276
340
  end
@@ -283,7 +347,7 @@ class Twitter < ModSpox::Plugin
283
347
  begin
284
348
  msg = @twitter.status(:get, params[:m_id])
285
349
  if(msg)
286
- reply m.replyto, "\2Tweet:\2 [#{msg.created_at.strftime("%Y/%m/%d-%H:%M:%S")}}] <#{msg.user.screen_name}> #{@coder.decode(msg.text)}"
350
+ 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)}"
287
351
  else
288
352
  warning m.replyto, "failed to find message with ID: #{params[:m_id].strip}"
289
353
  end
@@ -294,6 +358,34 @@ class Twitter < ModSpox::Plugin
294
358
 
295
359
  private
296
360
 
361
+ def populate_friends
362
+ return unless @lock.try_lock
363
+ begin
364
+ fs = @twitter.my(:friends)
365
+ @friends = []
366
+ if(fs.size > 0)
367
+ @friends = fs.map{|u| u.screen_name}
368
+ end
369
+ rescue Object => boom
370
+ Logger.info("Failed to populate friends: #{boom}")
371
+ @pipeline << Messages::Internal::TimerAdd.new(self, 200, nil, true){ populate_friends }
372
+ ensure
373
+ @lock.unlock
374
+ end
375
+ end
376
+
377
+ def screen_name(n)
378
+ return @aliases.has_key?(n.to_sym) ? Models::Nick[@aliases[n.to_sym]].nick : n
379
+ end
380
+
381
+ def replace_names(s)
382
+ s.scan(/@\S+/).each do |n|
383
+ n.slice!(0)
384
+ s.gsub!("@#{n}", "@#{screen_name(n)}")
385
+ end
386
+ return s
387
+ end
388
+
297
389
  def check_timeline
298
390
  if(@auth_info[:channels].size < 1 || @auth_info[:interval].to_i < 1)
299
391
  Logger.warn('Twitter has no channels to send information to')
@@ -302,19 +394,24 @@ class Twitter < ModSpox::Plugin
302
394
  things = []
303
395
  @twitter.my(:friends).each do |f|
304
396
  @twitter.timeline_for(:friend, :id => f.screen_name, :since => @last_check) do |status|
305
- if(@coder.decode(status.text) =~ /^@(\S+)/)
397
+ next if status.created_at < @last_check
398
+ if(Helpers.convert_entities(status.text) =~ /^@(\S+)/)
306
399
  next unless @twitter.my(:friends).map{|f|f.screen_name}.include?($1) || $1 == @twitter.login
307
400
  end
308
- things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{status.user.screen_name}> #{@coder.decode(status.text)}"
401
+ things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{screen_name(status.user.screen_name)}> #{Helpers.convert_entities(replace_names(status.text))}"
309
402
  end
310
403
  end
311
404
  @twitter.timeline_for(:me, :since => @last_check) do |status|
312
- things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{status.user.screen_name}> #{@coder.decode(status.text)}"
405
+ next if status.created_at < @last_check
406
+ things << "[#{status.created_at.strftime("%H:%M:%S")}] <#{screen_name(status.user.screen_name)}> #{Helpers.convert_entities(replace_names(status.text))}"
313
407
  end
314
- things.uniq!
315
- things.sort!
316
- things.each do |status|
317
- @auth_info[:channels].each{|i| reply Models::Channel[i], "\2AutoTweet:\2 #{status}"}
408
+ unless(things.empty?)
409
+ things.uniq!
410
+ things.sort!
411
+ things = things[-@burst,@burst] if things.size > @burst
412
+ things.each do |status|
413
+ @auth_info[:channels].each{|i| reply Models::Channel[i], "\2AutoTweet:\2 #{status}"}
414
+ end
318
415
  end
319
416
  @last_check = Time.now
320
417
  rescue Object => boom
@@ -323,18 +420,6 @@ class Twitter < ModSpox::Plugin
323
420
  end
324
421
  end
325
422
 
326
- def information(to, message)
327
- reply to, "\2Twitter (info):\2 #{message}"
328
- end
329
-
330
- def warning(to, message)
331
- reply to, "\2Twitter (warn):\2 #{message}"
332
- end
333
-
334
- def error(to, message)
335
- reply to, "\2Twitter (error):\2 #{message}"
336
- end
337
-
338
423
  def save_info
339
424
  i = Models::Setting.find_or_create(:name => 'twitter')
340
425
  i.value = @auth_info
@@ -7,21 +7,12 @@ class UrbanDictionary < ModSpox::Plugin
7
7
 
8
8
  def initialize(pipeline)
9
9
  super(pipeline)
10
- begin
11
- require 'htmlentities'
12
- rescue Object => boom
13
- Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
14
- raise Exceptions::BotException.new("Missing required HTMLEntities library")
15
- end
16
- Signature.find_or_create(:signature => 'udefine (?!key)(\d+)? ?(.+)', :plugin => name, :method => 'define',
17
- :description => 'Find the definition of a word or phrase').params = [:number, :term]
18
- Signature.find_or_create(:signature => 'udefine key (.+)', :plugin => name, :method => 'key',
19
- :group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Set API key').params = [:key]
20
- @coder = HTMLEntities.new
10
+ add_sig(:sig => 'udefine (?!key)((\d+ )?(.+))', :method => :define, :desc => 'Find the definition of a word or phrase', :params => [:fullmatch, :number, :term])
11
+ add_sig(:sig => 'udefine key (.+)', :method => :key, :group => Models::Group.filter(:name => 'admin').first, :desc => 'Set API key', :params => [:key])
21
12
  end
22
13
 
23
14
  def define(message, params)
24
- key = Config[:urban_key]
15
+ key = Config.val(:urban_key)
25
16
  if(key)
26
17
  site = 'http://api.urbandictionary.com/soap?wsdl'
27
18
  result = params[:number] ? params[:number].to_i - 1 : 0
@@ -35,11 +26,11 @@ class UrbanDictionary < ModSpox::Plugin
35
26
  if defs.size < result + 1
36
27
  @pipeline << Privmsg.new(message.replyto, "Error: Definition number #{result+1} for term: #{params[:term]} not found.")
37
28
  else
38
- defin = defs[result].definition.length > 500 ? defs[result].definition.slice(0..500) + " *[CUT]*" : defs[result].definition
39
- exp = defs[result].example.length > 500 ? defs[result].example.slice(0..500) + " *[CUT]*" : defs[result].example
29
+ defin = defs[result].definition.length > 390 ? defs[result].definition.slice(0..390) + " *[CUT]*" : defs[result].definition
30
+ exp = defs[result].example.length > 390 ? defs[result].example.slice(0..390) + " *[CUT]*" : defs[result].example
40
31
  output << "Definition for \2#{defs[result].word}:\2"
41
- output << @coder.decode(defin.gsub(/[\r\n\s]+/, ' '))
42
- output << "\2Example usage:\2 #{@coder.decode(exp.gsub(/[\r\n\s]+/, ' '))}" if exp.length > 0
32
+ output << Helpers.convert_entities(defin.gsub(/[\r\n\s]+/, ' '))
33
+ output << "\2Example usage:\2 #{Helpers.convert_entities(exp.gsub(/[\r\n\s]+/, ' '))}" if exp.length > 0
43
34
  reply message.replyto, output
44
35
  end
45
36
  rescue Timeout::Error
@@ -56,7 +47,7 @@ class UrbanDictionary < ModSpox::Plugin
56
47
  if(message.is_public?)
57
48
  @pipeline << Privmsg.new(message.replyto, 'I don\'t set keys in public')
58
49
  else
59
- Config[:urban_key] = params[:key]
50
+ Config.set(:urban_key, params[:key])
60
51
  @pipeline << Privmsg.new(message.replyto, 'Urban Dictionary API key has been set.')
61
52
  end
62
53
  end