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
@@ -7,18 +7,16 @@ class Karma < ModSpox::Plugin
7
7
  Datatype::Karma.create_table unless Datatype::Karma.table_exists?
8
8
  Datatype::Alias.create_table unless Datatype::Alias.table_exists?
9
9
  alias_group = Models::Group.find_or_create(:name => 'alias')
10
- Models::Signature.find_or_create(:signature => 'karma (?!(fight|alias|dealias|aliases|reset) (\S+|\(.+?\)) ?(\S+|\(.+?\))?$)(\S+|\(.+?\))', :plugin => name, :method => 'score', :description => 'Returns karma for given thing').params = [:crap, :crap2, :crap3, :thing]
11
- Models::Signature.find_or_create(:signature => 'karma reset (\S+|\(.+?\))', :plugin => name, :method => 'reset',
12
- :group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Reset a karma score').params = [:thing]
13
- Models::Signature.find_or_create(:signature => 'karma alias (\S+|\(.+?\)) (\S+|\(.+?\))', :plugin => name, :method => 'aka',
14
- :group_id => alias_group.pk, :description => 'Alias a karma object to another karma object').params = [:thing, :thang]
15
- Models::Signature.find_or_create(:signature => 'karma dealias (\S+|\(.+?\)) (\S+|\(.+?\))', :plugin => name, :method => 'dealias',
16
- :group_id => alias_group.pk, :description => 'Remove a karma alias').params = [:thing, :otherthing]
17
- Models::Signature.find_or_create(:signature => 'karma aliases (\S+|\(.+?\))', :plugin => name, :method => 'show_aliases',
18
- :description => 'Show all aliases for given thing').params = [:thing]
19
- Models::Signature.find_or_create(:signature => 'karma fight (\S+|\(.+?\)) (\S+|\(.+?\))', :plugin => name, :method => 'fight',
20
- :description => 'Make two karma objects fight').params = [:thing, :thang]
10
+ add_sig(:sig => 'karma (?!topten|bottomten$)(?!(fight|alias|dealias|aliases|reset) (\S+|\(.+?\)) ?(\S+|\(.+?\))?$)(\S+|\(.+?\))', :method => :score, :desc => 'Returns karma for given thing', :params => [:crap, :crap2, :crap3, :thing])
11
+ add_sig(:sig => 'karma reset (\S+|\(.+?\))', :method => :reset, :group => Models::Group.filter(:name => 'admin').first, :desc => 'Reset a karma score', :params => [:thing])
12
+ add_sig(:sig => 'karma alias (\S+|\(.+?\)) (\S+|\(.+?\))', :method => :aka, :group => alias_group, :desc => 'Alias a karma object to another karma object', :params => [:thing, :thang])
13
+ add_sig(:sig => 'karma dealias (\S+|\(.+?\)) (\S+|\(.+?\))', :method => :dealias, :group => alias_group, :desc => 'Remove a karma alias', :params => [:thing, :otherthing])
14
+ add_sig(:sig => 'karma aliases (\S+|\(.+?\))', :method => :show_aliases, :desc => 'Show all aliases for given thing', :params => [:thing])
15
+ add_sig(:sig => 'karma fight (\S+|\(.+?\)) (\S+|\(.+?\))', :method => :fight, :desc => 'Make two karma objects fight', :params => [:thing, :thang])
21
16
  add_sig(:sig => 'antikarma (\S+|\(.+?\))', :method => :antikarma, :desc => 'Show things antikarma', :params => [:thing])
17
+ add_sig(:sig => 'antikarma fight (\S+|\(.+?\)) (\S+|\(.+?\))', :method => :antifight, :desc => 'Make two antikarma objects fight', :params => [:thing, :thang])
18
+ add_sig(:sig => 'karma topten', :method => :topten, :desc => 'Show top ten highest karma objects')
19
+ add_sig(:sig => 'karma bottomten', :method => :bottomten, :desc => 'Show bottom ten lowest karma objects')
22
20
  @pipeline.hook(self, :check, :Incoming_Privmsg)
23
21
  @thing_maxlen = 32
24
22
  @karma_regex = /(\(.{1,#@thing_maxlen}?\)|\S{1,#@thing_maxlen})([+-]{2})(?:\s|$)/
@@ -32,10 +30,14 @@ class Karma < ModSpox::Plugin
32
30
 
33
31
  def check(message)
34
32
  if(message.is_public?)
33
+ @dupes = {}
35
34
  message.message.scan(@karma_regex) do |match|
36
35
  thing, adj = match
37
36
  thing.downcase!
38
37
  thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..-1] == ')'
38
+ next if @dupes.has_key?(thing) && @dupes[thing].include?(adj)
39
+ @dupes[thing] = [] unless @dupes[thing]
40
+ @dupes[thing] << adj
39
41
  adj = adj == '++' ? +1 : -1
40
42
  things = [thing]
41
43
  karma = Datatype::Karma.find_or_create(:thing => thing, :channel_id => message.target.pk)
@@ -68,6 +70,32 @@ class Karma < ModSpox::Plugin
68
70
  @pipeline << Messages::Internal::TimerAdd.new(self, rand(5) + 1, nil, true){ egg(params[:thing].downcase, message) }
69
71
  end
70
72
  end
73
+
74
+ def bottomten(m, params)
75
+ set = Datatype::Karma.filter(:channel_id => m.target.pk).order(:thing.asc).order(:score.asc).limit(10)
76
+ if(set.count > 0)
77
+ output = []
78
+ set.each do |thing|
79
+ output << "#{thing.thing} (#{thing.score.to_s.slice(0) == '-' ? '' : '+'}#{thing.score})"
80
+ end
81
+ reply m.replyto, "\2Karma bottom ten:\2 #{output.join(', ')}"
82
+ else
83
+ error m.replyto, 'No karma objects stored'
84
+ end
85
+ end
86
+
87
+ def topten(m, params)
88
+ set = Datatype::Karma.filter(:channel_id => m.target.pk).order(:thing.asc).order(:score.desc).limit(10)
89
+ if(set.count > 0)
90
+ output = []
91
+ set.each do |thing|
92
+ output << "#{thing.thing} (#{thing.score.to_s.slice(0) == '-' ? '' : '+'}#{thing.score})"
93
+ end
94
+ reply m.replyto, "\2Karma topten:\2 #{output.join(', ')}"
95
+ else
96
+ error m.replyto, 'No karma objects stored'
97
+ end
98
+ end
71
99
 
72
100
  def antikarma(message, params)
73
101
  return unless message.is_public?
@@ -89,7 +117,7 @@ class Karma < ModSpox::Plugin
89
117
  return unless message.is_public?
90
118
  karma = Datatype::Karma.filter(:thing => sthing, :channel_id => message.target.pk).first
91
119
  if(karma)
92
- karma.update_with_params(:score => 0)
120
+ karma.update(:score => 0)
93
121
  @pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 has been reset")
94
122
  else
95
123
  @pipeline << Privmsg.new(message.replyto, "\2Error:\2 #{sthing} has no karma")
@@ -108,12 +136,34 @@ class Karma < ModSpox::Plugin
108
136
  winner = thing_score > thang_score ? thing : thang
109
137
  loser = thing_score > thang_score ? thang : thing
110
138
  distance = (thing_score - thang_score).abs
111
- output = "\2KARMA FIGHT RESULTS:\2 "
139
+ output = ["\2KARMA FIGHT RESULTS:\2 "]
112
140
  if(distance > 0)
113
- reply message.replyto, "\2#{winner}\2 #{winner[-1] == 's' || winner[-1] == 115 ? 'have' : 'has'} beaten \2#{loser}\2 #{distance > 50 ? 'like a redheaded step child' : ''} (+#{distance} points)"
141
+ output << "\2#{winner}\2 #{winner[-1] == 's' || winner[-1] == 115 ? 'have' : 'has'} beaten \2#{loser}\2 #{distance > 50 ? 'like a redheaded step child' : ''} (+#{distance} points)"
114
142
  else
115
- reply message.replyto, "\2#{winner}\2 #{winner[-1] == 's' || winner[-1] == 115 ? 'have' : 'has'} tied \2#{loser}\2"
143
+ output << "\2#{winner}\2 #{winner[-1] == 's' || winner[-1] == 115 ? 'have' : 'has'} tied \2#{loser}\2"
116
144
  end
145
+ reply message.replyto, output
146
+ end
147
+
148
+ def antifight(message, params)
149
+ thing = params[:thing]
150
+ thang = params[:thang]
151
+ thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..-1] == ')'
152
+ thang = thang[1..-2] if thang[0..0] == '(' && thang[-1..-1] == ')'
153
+ rthing = Datatype::Karma.find_or_create(:thing => thing.downcase, :channel_id => message.target.pk)
154
+ rthang = Datatype::Karma.find_or_create(:thing => thang.downcase, :channel_id => message.target.pk)
155
+ thing_score = Datatype::Alias.score_object(rthing.pk) * -1
156
+ thang_score = Datatype::Alias.score_object(rthang.pk) * -1
157
+ winner = thing_score > thang_score ? thing : thang
158
+ loser = thing_score > thang_score ? thang : thing
159
+ distance = (thing_score - thang_score).abs
160
+ output = ["\2ANTI-KARMA FIGHT RESULTS:\2 "]
161
+ if(distance > 0)
162
+ output << "\2#{winner}\2 #{winner[-1] == 's' || winner[-1] == 115 ? 'have' : 'has'} beaten \2#{loser}\2 #{distance > 50 ? 'like a redheaded step child' : ''} (+#{distance} points)"
163
+ else
164
+ output << "\2#{winner}\2 #{winner[-1] == 's' || winner[-1] == 115 ? 'have' : 'has'} tied \2#{loser}\2"
165
+ end
166
+ reply message.replyto, output
117
167
  end
118
168
 
119
169
  def aka(message, params)
@@ -140,7 +190,7 @@ class Karma < ModSpox::Plugin
140
190
  otherthing = Datatype::Karma.filter(:thing => sotherthing, :channel_id => message.target.pk).first
141
191
  if(thing && otherthing)
142
192
  set = Datatype::Alias.filter('(thing_id = ? AND aka_id = ?) OR (thing_id = ? AND aka_id = ?)', thing.pk, otherthing.pk, otherthing.pk, thing.pk)
143
- if(set.size < 1)
193
+ if(set.count < 1)
144
194
  reply message.replyto, "\2Error:\2 No alias found between #{thing.thing} and #{otherthing.thing}"
145
195
  else
146
196
  set.destroy
@@ -155,18 +205,22 @@ class Karma < ModSpox::Plugin
155
205
  thing = params[:thing].downcase
156
206
  thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..-1] == ')'
157
207
  thing = Datatype::Karma.filter(:thing => thing, :channel_id => message.target.pk).first
158
- if(thing)
159
- things = []
160
- Datatype::Alias.get_aliases(thing.pk).each do |id|
161
- things << Datatype::Karma[id].thing
162
- end
163
- if(things.empty?)
164
- reply message.replyto, "#{thing.thing} is not currently aliased"
208
+ begin
209
+ if(thing)
210
+ things = []
211
+ Datatype::Alias.get_aliases(thing.pk).each do |id|
212
+ things << Datatype::Karma[id].thing
213
+ end
214
+ if(things.empty?)
215
+ reply message.replyto, "#{thing.thing} is not currently aliased"
216
+ else
217
+ reply message.replyto, "#{thing.thing} is currently aliased to: #{things.sort.join(', ')}"
218
+ end
165
219
  else
166
- reply message.replyto, "#{thing.thing} is currently aliased to: #{things.join(', ')}"
220
+ reply message.replyto, "\2Error:\2 #{params[:thing]} has never been used and has no aliases"
167
221
  end
168
- else
169
- reply message.replyto, "\2Error:\2 #{thing.thing} has never been used and has no aliases"
222
+ rescue Object
223
+ error message.replyto, "No aliases found"
170
224
  end
171
225
  end
172
226
 
@@ -186,9 +240,7 @@ class Karma < ModSpox::Plugin
186
240
  index [:thing, :channel_id], :unique => true
187
241
  end
188
242
 
189
- def channel
190
- ModSpox::Models::Channel[channel_id]
191
- end
243
+ many_to_one :channel, :class => ModSpox::Models::Channel
192
244
  end
193
245
  class Alias < Sequel::Model
194
246
  set_schema do
@@ -22,8 +22,8 @@ class ChatLogger < ModSpox::Plugin
22
22
  @pipeline.hook(self, :log_privmsg, :Incoming_Notice)
23
23
  @pipeline.hook(self, :log_outpriv, :Outgoing_Privmsg)
24
24
  @pipeline.hook(self, :log_outpriv, :Outgoing_Notice)
25
- Signature.find_or_create(:signature => 'seen (\S+)', :plugin => name, :method => 'seen', :description => 'Report last sighting of nick').params = [:nick]
26
- Signature.find_or_create(:signature => 'lastspoke (\S+)', :plugin => name, :method => 'spoke', :description => 'Report last time nick spoke').params = [:nick]
25
+ add_sig(:sig => 'seen (\S+)', :method => :seen, :desc => 'Report last sighting of nick', :params => [:nick])
26
+ add_sig(:sig => 'lastspoke (\S+)', :method => :spoke, :desc => 'Report last time nick spoke', :params => [:nick])
27
27
  end
28
28
 
29
29
  def log_outpriv(message)
@@ -11,8 +11,7 @@ class LolSpeak < ModSpox::Plugin
11
11
  Logger.warn('Error: This plugins requires the lolspeak gem. Please install gem and reload plugin.')
12
12
  raise BotException.new("Failed to initialize plugin. Missing lolspeak gem.")
13
13
  end
14
- Signature.find_or_create(:signature => 'lolspeak (.+)', :plugin => name, :method => 'translate',
15
- :description => 'Translate text to lolspeak').params = [:text]
14
+ add_sig(:sig => 'lolspeak (.+)', :method => :translate, :desc => 'Translate text to lolspeak', :params => [:text])
16
15
  end
17
16
 
18
17
  def translate(message, params)
@@ -6,7 +6,7 @@ class PhpCli < ModSpox::Plugin
6
6
 
7
7
  def initialize(pipeline)
8
8
  super(pipeline)
9
- @path = Config[:plugin_directory] + '/phpcli'
9
+ @path = Config.val(:plugin_directory) + '/phpcli'
10
10
  @botini = @path + '/bot.ini'
11
11
  unless(File.directory?(@path))
12
12
  FileUtils.mkdir_p(@path)
@@ -18,12 +18,20 @@ class PhpCli < ModSpox::Plugin
18
18
  ini.write($ini)
19
19
  ini.close
20
20
  end
21
+ PhpFunction.create_table unless PhpFunction.table_exists?
21
22
  php = Group.find_or_create(:name => 'php')
23
+ phpfunc = Group.find_or_create(:name => 'phpfunc')
22
24
  admin = Group.filter(:name => 'admin').first
23
- Signature.find_or_create(:signature => 'php (on|off)', :plugin => name, :method => 'set_channel', :group_id => admin.pk,
24
- :description => 'Add or remove channel from allowing PHP command').params = [:action]
25
- Signature.find_or_create(:signature => 'php (?!on|off)(.+)', :plugin => name, :method => 'execute_php', :group_id => php.pk,
26
- :description => 'Execute PHP code').params = [:code]
25
+ add_sig(:sig => 'php (on|off)', :method => :set_channel, :group => admin, :desc => 'Add or remove channel from allowing PHP command', :params => [:action])
26
+ add_sig(:sig => 'php (?!on|off)(.+)', :method => :execute_php, :group => php, :desc => 'Execute PHP code', :params => [:code])
27
+ add_sig(:sig => 'phpq (?!on|off)(.+)', :method => :quiet_php, :group => php, :params => [:code], :desc => 'Execute PHP quietly')
28
+ add_sig(:sig => 'pf add (.+)', :method => :add, :params => [:function], :group => phpfunc, :desc => 'Add a custom PHP function')
29
+ add_sig(:sig => 'pf remove (\d+)', :method => :remove, :params => [:func_id], :group => phpfunc, :desc => 'Remove a custom PHP function')
30
+ add_sig(:sig => 'pf list', :method => :list, :desc => 'List custom PHP functions')
31
+ add_sig(:sig => 'pf edit (.+)', :method => :edit, :params => [:function], :group => phpfunc, :desc => 'Overwrite existing custom PHP function')
32
+ add_sig(:sig => 'pf show (\d+)', :method => :show, :params => [:func_id], :group => phpfunc, :desc => 'Show given PHP function source')
33
+ @customfuncs = []
34
+ populate_customs
27
35
  @channels = Setting.filter(:name => 'phpcli').first
28
36
  @channels = @channels.nil? ? [] : @channels.value
29
37
  end
@@ -51,11 +59,15 @@ class PhpCli < ModSpox::Plugin
51
59
  end
52
60
  end
53
61
 
54
- def execute_php(message, params)
62
+ def quiet_php(message, params)
63
+ execute_php(message, params, true)
64
+ end
65
+
66
+ def execute_php(message, params, shh=false)
55
67
  return unless @channels.include?(message.target.pk)
56
68
  filepath = @path + "/#{rand(99999)}.bot.php"
57
69
  file = File.open(filepath, 'w')
58
- file.write("<? $_SERVER = $_ENV = array(); #{params[:code]} ?>")
70
+ file.write("<? $_SERVER = $_ENV = $GLOBALS = array(); #{@customfuncs.join(' ')} #{params[:code]} ?>")
59
71
  file.close
60
72
  begin
61
73
  output = Helpers.safe_exec("php -c #{@path}/bot.ini -d max_execution_time=10 #{filepath} 2>&1 | head -n 4")
@@ -75,7 +87,7 @@ class PhpCli < ModSpox::Plugin
75
87
  reply message.replyto, "PHP #{type}: "+warning
76
88
  end
77
89
  if(warning.nil? || type !~ /(Fatal|Parse)/)
78
- reply message.replyto, "Result: "+output
90
+ reply message.replyto, "#{shh ? '' : 'Result: '}"+output
79
91
  end
80
92
  File.delete(filepath)
81
93
  rescue Timeout::Error => boom
@@ -85,9 +97,127 @@ class PhpCli < ModSpox::Plugin
85
97
  File.delete(filepath)
86
98
  end
87
99
  end
100
+
101
+ def add(m, params)
102
+ if(params[:function].scan(/function\s+([^\(]+)\(/).size > 1)
103
+ error m.replyto, 'Only one function can be added at a time'
104
+ return
105
+ end
106
+ if(params[:function] =~ /^function\s+([^\(]+)\(/)
107
+ name = $1.downcase
108
+ f = PhpFunction.filter(:name => name).first
109
+ unless(f)
110
+ begin
111
+ parse(params[:function])
112
+ save(params[:function], name, m.source)
113
+ information m.replyto, "New function \2#{name}\2 added to custom PHP functions"
114
+ populate_customs
115
+ rescue Object => boom
116
+ error m.replyto, "Failed to add function #{name}. Error: #{boom}"
117
+ end
118
+ else
119
+ error m.replyto, "Function with name: #{name} already exists"
120
+ end
121
+ else
122
+ error m.replyto, "Function is not in proper format"
123
+ end
124
+ end
125
+
126
+ def remove(m, params)
127
+ f = PhpFunction[params[:func_id].to_i]
128
+ if(f)
129
+ name = f.name
130
+ f.destroy
131
+ information m.replyto, "Function \2#{name}\2 has been removed"
132
+ populate_customs
133
+ else
134
+ error m.replyto, "Failed to locate function with ID: #{params[:func_id]}"
135
+ end
136
+ end
137
+
138
+ def list(m, params)
139
+ output = ["\2Custom PHP functions:\2"]
140
+ PhpFunction.all.each do |f|
141
+ output << "\2ID:\2 #{f.pk} \2Name:\2 #{f.name} \2Author:\2 #{f.nick.nick} \2Added:\2 #{f.added.strftime("%Y/%m/%d-%H:%M:%S")}"
142
+ end
143
+ reply m.replyto, output
144
+ end
145
+
146
+ def edit(m, params)
147
+ if(params[:function] =~ /^function\s+([^\(]+)\(/)
148
+ name = $1.downcase
149
+ begin
150
+ parse(params[:function])
151
+ save(params[:function], name, m.source)
152
+ information m.replyto, "New function \2#{name}\2 added to custom PHP functions"
153
+ populate_customs
154
+ rescue Object => boom
155
+ error m.replyto, "Failed to add function #{name}. Error: #{boom}"
156
+ end
157
+ else
158
+ error m.replyto, "Function is not in proper format"
159
+ end
160
+ end
161
+
162
+ def show(m, params)
163
+ f = PhpFunction[params[:func_id].to_i]
164
+ if(f)
165
+ reply m.replyto, ["Source for function \2#{f.name}\2:", f.php_function]
166
+ else
167
+ error m.replyto, "Failed to find custom PHP function with ID: #{params[:func_id]}"
168
+ end
169
+ end
170
+
171
+ def parse(func)
172
+ filepath = @path + "/#{rand(99999)}.bot.php"
173
+ file = File.open(filepath, 'w')
174
+ file.write("<? #{func} ?>")
175
+ file.close
176
+ output = Helpers.safe_exec("php -l #{filepath} 2>&1 | head -n 4").strip.gsub(/\s{2,}/, ' ').gsub(/[\r\n]+/, ' ')
177
+ File.delete(filepath)
178
+ if(output =~ /(Parse error.+) in/)
179
+ raise "#{$1}"
180
+ end
181
+ end
182
+
183
+ def save(func, name, nick)
184
+ f = PhpFunction.filter(:name => name).first
185
+ f = PhpFunction.new unless f
186
+ f.name = name
187
+ f.php_function = func
188
+ f.added = ::Time.now
189
+ f.nick = nick
190
+ f.save
191
+ end
192
+
193
+ def populate_customs
194
+ @customfuncs = []
195
+ PhpFunction.all.each{|f| @customfuncs << f.php_function }
196
+ end
88
197
 
89
198
  class NoInterpreter < Exceptions::BotException
90
199
  end
200
+
201
+ class PhpFunction < Sequel::Model
202
+ set_schema do
203
+ text :php_function, :null => false
204
+ varchar :name, :null => false, :unique => true
205
+ timestamp :added, :null => false
206
+ foreign_key :nick_id, :null => false
207
+ primary_key :id
208
+ end
209
+
210
+ Sequel::Model.plugin :serialization, :marshal, :php_function
211
+ # serialize(:php_function, :format => :marshal)
212
+
213
+ def nick
214
+ Models::Nick[nick_id]
215
+ end
216
+
217
+ def nick=(n)
218
+ values[:nick_id] = n.pk
219
+ end
220
+ end
91
221
 
92
222
  end
93
223
 
@@ -12,8 +12,8 @@ class PhpFuncLookup < ModSpox::Plugin
12
12
  def initialize(pipeline)
13
13
  super(pipeline)
14
14
  setup_setting
15
- @path = Setting[:phpfunc][:directory]
16
- @trigger = Setting[:phpfunc][:trigger]
15
+ @path = Setting.val(:phpfunc)[:directory]
16
+ @trigger = Setting.val(:phpfunc)[:trigger]
17
17
  @manual = "#{@path}/html"
18
18
  @classlist = []
19
19
  fetch_manual unless File.exists?("#{@path}/manual.tar.gz")
@@ -65,15 +65,12 @@ class PhpFuncLookup < ModSpox::Plugin
65
65
  "->" => [ "?", "Object member accessor thingy","" ],
66
66
  }
67
67
  admin = Group.filter(:name => 'admin').first
68
- Signature.find_or_create(:signature => 'pfunc (\S+)', :plugin => name, :method => 'phpfunc', :description => 'Lookup PHP function').params = [:name]
69
- Signature.find_or_create(:signature => 'fetch php manual', :plugin => name, :method => 'fetch', :group_id => admin.pk,
70
- :description => 'Download and extract PHP manual')
71
- Signature.find_or_create(:signature => 'pfunc trigger (\S+)', :plugin => name, :method => 'set_trigger', :group_id => admin.pk,
72
- :description => 'Set the trigger for auto-lookups').params = [:trigger]
73
- Signature.find_or_create(:signature => 'pfunc show trigger', :plugin => name, :method => 'show_trigger', :description => 'Show current trigger')
74
- Signature.find_or_create(:signature => 'pfunc (add|remove) (\S+)', :plugin => name, :method => 'set_channels', :group_id => admin.pk,
75
- :description => 'Add or remove channels from auto-lookups').params = [:action, :channel]
76
- Signature.find_or_create(:signature => 'pfunc show channels', :plugin => name, :method => 'list_channels', :description => 'Show channels with auto lookup enabled')
68
+ add_sig(:sig => 'pfunc (\S+)', :method => :phpfunc, :desc => 'Lookup PHP function', :params => [:name])
69
+ add_sig(:sig => 'fetch php manual', :method => :fetch, :group => admin, :desc => 'Download and extract PHP manual')
70
+ add_sig(:sig => 'pfunc trigger (\S+)', :method => :set_trigger, :group => admin, :desc => 'Set the trigger for auto-lookups', :params => [:trigger])
71
+ add_sig(:sig => 'pfunc show trigger', :method => :show_trigger, :desc => 'Show current trigger')
72
+ add_sig(:sig => 'pfunc (add|remove) (\S+)', :method => :set_channels, :group => admin, :desc => 'Add or remove channels from auto-lookups', :params => [:action, :channel])
73
+ add_sig(:sig => 'pfunc show channels', :method => :list_channels, :desc => 'Show channels with auto lookup enabled')
77
74
  @pipeline.hook(self, :listen, :Incoming_Privmsg)
78
75
  populate_classes
79
76
  end
@@ -100,7 +97,7 @@ class PhpFuncLookup < ModSpox::Plugin
100
97
  end
101
98
 
102
99
  def listen(m)
103
- if(m.target.is_a?(Channel) && Setting[:phpfunc][:channels].include?(m.target.pk))
100
+ if(m.target.is_a?(Channel) && Setting.val(:phpfunc)[:channels].include?(m.target.pk))
104
101
  if m.message =~ /^#{Regexp.escape(@trigger)}(\S+)$/
105
102
  phpfunc(m, {:name => $1})
106
103
  end
@@ -108,7 +105,7 @@ class PhpFuncLookup < ModSpox::Plugin
108
105
  end
109
106
 
110
107
  def set_trigger(message, params)
111
- vals = Setting[:phpfunc]
108
+ vals = Setting.val(:phpfunc)
112
109
  vals[:trigger] = params[:trigger]
113
110
  Setting.filter(:name => 'phpfunc').first.value = vals
114
111
  @trigger = params[:trigger]
@@ -118,12 +115,12 @@ class PhpFuncLookup < ModSpox::Plugin
118
115
  def set_channels(message, params)
119
116
  channel = Channel.filter(:name => params[:channel]).first
120
117
  if(channel)
121
- vals = Setting[:phpfunc]
118
+ vals = Setting.val(:phpfunc)
122
119
  if(params[:action] == 'add')
123
- vals[:channels] << channel.pk unless Setting[:phpfunc][:channels].include?(channel.pk)
120
+ vals[:channels] << channel.pk unless Setting.val(:phpfunc)[:channels].include?(channel.pk)
124
121
  reply message.replyto, "Channel \2#{params[:channel]}\2 added to PHP auto lookup"
125
122
  else
126
- vals[:channels].delete(channel.pk) if Setting[:phpfunc][:channels].include?(channel.pk)
123
+ vals[:channels].delete(channel.pk) if Setting.val(:phpfunc)[:channels].include?(channel.pk)
127
124
  reply message.replyto, "Channel \2#{params[:channel]}\2 has been removed from PHP auto lookup"
128
125
  end
129
126
  Setting.filter(:name => 'phpfunc').first.value = vals
@@ -133,9 +130,9 @@ class PhpFuncLookup < ModSpox::Plugin
133
130
  end
134
131
 
135
132
  def list_channels(message, params)
136
- if(Setting[:phpfunc][:channels].size > 0)
133
+ if(Setting.val(:phpfunc)[:channels].size > 0)
137
134
  chans = []
138
- Setting[:phpfunc][:channels].each do |id|
135
+ Setting.val(:phpfunc)[:channels].each do |id|
139
136
  chans << Channel[id].name
140
137
  end
141
138
  reply message.replyto, "PHP auto lookup enabled channels: #{chans.join(', ')}"
@@ -145,7 +142,7 @@ class PhpFuncLookup < ModSpox::Plugin
145
142
  end
146
143
 
147
144
  def show_trigger(message, p)
148
- reply message.replyto, "PHP auto lookup trigger: \2#{Setting[:phpfunc][:trigger]}\2"
145
+ reply message.replyto, "PHP auto lookup trigger: \2#{Setting.val(:phpfunc)[:trigger]}\2"
149
146
  end
150
147
 
151
148
  private
@@ -179,10 +176,10 @@ class PhpFuncLookup < ModSpox::Plugin
179
176
  s = Setting.filter(:name => 'phpfunc').first
180
177
  unless(s)
181
178
  s = Setting.find_or_create(:name => 'phpfunc')
182
- s.value = {:directory => Config[:plugin_directory] + '/php', :trigger => '@', :channels => []}
179
+ s.value = {:directory => Config.val(:plugin_directory) + '/php', :trigger => '@', :channels => []}
183
180
  end
184
- unless(File.directory?(Setting[:phpfunc][:directory]))
185
- FileUtils.mkdir_p(Setting[:phpfunc][:directory])
181
+ unless(File.directory?(Setting.val(:phpfunc)[:directory]))
182
+ FileUtils.mkdir_p(Setting.val(:phpfunc)[:directory])
186
183
  end
187
184
  end
188
185
 
@@ -242,7 +239,7 @@ class PhpFuncLookup < ModSpox::Plugin
242
239
  desc = CGI::unescapeHTML(desc.gsub(/<.+?>/, ' ').gsub(/[\s]+/, ' '))
243
240
  output = [versions]
244
241
  output << "\2#{proto}\2"
245
- output << desc
242
+ output << Helpers.convert_entities(desc)
246
243
  output << "http://www.php.net/manual/en/#{filename.gsub(/\.html$/, '.php')}"
247
244
  reply m.replyto, output
248
245
  end