zetabot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +281 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +41 -0
  7. data/Rakefile +6 -0
  8. data/Zeta.gemspec +74 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +13 -0
  11. data/bin/zeta +9 -0
  12. data/bin/zeta-setup +13 -0
  13. data/lib/Zeta.rb +13 -0
  14. data/lib/Zeta/access.rb +84 -0
  15. data/lib/Zeta/admin.rb +10 -0
  16. data/lib/Zeta/admin/autojoin.rb +25 -0
  17. data/lib/Zeta/admin/bot.rb +43 -0
  18. data/lib/Zeta/admin/channels.rb +36 -0
  19. data/lib/Zeta/admin/eval.rb +43 -0
  20. data/lib/Zeta/admin/fifo.rb +45 -0
  21. data/lib/Zeta/admin/ignore.rb +112 -0
  22. data/lib/Zeta/admin/oper.rb +50 -0
  23. data/lib/Zeta/admin/plugins.rb +109 -0
  24. data/lib/Zeta/admin/users.rb +5 -0
  25. data/lib/Zeta/blacklist.rb +25 -0
  26. data/lib/Zeta/cache.rb +0 -0
  27. data/lib/Zeta/cinch.rb +35 -0
  28. data/lib/Zeta/config.rb +42 -0
  29. data/lib/Zeta/gems.rb +0 -0
  30. data/lib/Zeta/locale.rb +4 -0
  31. data/lib/Zeta/log.rb +2 -0
  32. data/lib/Zeta/models.rb +5 -0
  33. data/lib/Zeta/models/channel.rb +3 -0
  34. data/lib/Zeta/models/plugin.rb +3 -0
  35. data/lib/Zeta/models/user.rb +3 -0
  36. data/lib/Zeta/plugins.rb +27 -0
  37. data/lib/Zeta/plugins/attack.rb +61 -0
  38. data/lib/Zeta/plugins/botinfo.rb +83 -0
  39. data/lib/Zeta/plugins/darkscience.rb +215 -0
  40. data/lib/Zeta/plugins/dbz.rb +31 -0
  41. data/lib/Zeta/plugins/dcc.rb +25 -0
  42. data/lib/Zeta/plugins/dnsbl.rb +36 -0
  43. data/lib/Zeta/plugins/echo.rb +15 -0
  44. data/lib/Zeta/plugins/eightball.rb +53 -0
  45. data/lib/Zeta/plugins/fml.rb +35 -0
  46. data/lib/Zeta/plugins/fnord.rb +329 -0
  47. data/lib/Zeta/plugins/gem.rb +0 -0
  48. data/lib/Zeta/plugins/gif.rb +73 -0
  49. data/lib/Zeta/plugins/help.rb +32 -0
  50. data/lib/Zeta/plugins/libsecure.rb +34 -0
  51. data/lib/Zeta/plugins/macros.rb +124 -0
  52. data/lib/Zeta/plugins/movie.rb +67 -0
  53. data/lib/Zeta/plugins/pdfinfo.rb +69 -0
  54. data/lib/Zeta/plugins/rainbow.rb +65 -0
  55. data/lib/Zeta/plugins/russian_roulette.rb +90 -0
  56. data/lib/Zeta/plugins/seen.rb +77 -0
  57. data/lib/Zeta/plugins/silly.rb +183 -0
  58. data/lib/Zeta/plugins/snooper.rb +146 -0
  59. data/lib/Zeta/plugins/urban.rb +60 -0
  60. data/lib/Zeta/plugins/weather.rb +203 -0
  61. data/lib/Zeta/plugins/whois.rb +25 -0
  62. data/lib/Zeta/plugins/wiki.rb +75 -0
  63. data/lib/Zeta/plugins/wolfram.rb +46 -0
  64. data/lib/Zeta/tasks/db.rb +0 -0
  65. data/lib/Zeta/version.rb +3 -0
  66. data/lib/generators/config/config.rb +0 -0
  67. data/lib/generators/plugin/new_plugin.rb +0 -0
  68. data/locale/en/8ball.yml +0 -0
  69. data/locale/en/attack.yml +148 -0
  70. data/locale/en/dbz.yml +10 -0
  71. data/locale/en/ircop.yml +5 -0
  72. data/locale/en/macros.yml +98 -0
  73. data/locale/en/meme.yml +27 -0
  74. metadata +636 -0
@@ -0,0 +1,50 @@
1
+ # This is considered a dangerous plugin, use it only if you know what you are doing
2
+ module Admin
3
+ class Oper
4
+ include Cinch::Plugin
5
+ include Cinch::Helpers
6
+
7
+ enable_acl(:oper)
8
+
9
+ # Regex
10
+ match 'operup', method: :oper_up
11
+ match /kill ([\S]+) (.+)/, method: :oper_kill
12
+ match /clearchan (.+) (true|yes)/, method: :oper_clearchan
13
+
14
+ # Methods
15
+ def oper_up(m)
16
+ if Config.oper_username && Config.oper_password
17
+ @bot.oper(Config.oper_password, Config.oper_username)
18
+ end
19
+ end
20
+
21
+ def oper_kill(m, nick, message)
22
+ return if User(nick).oper?
23
+ if @bot.irc.send("KILL #{nick} #{message}")
24
+ m.reply "#{nick}: has been killed by #{m.user.nick} for #{message}"
25
+ end
26
+ end
27
+
28
+ def oper_clearchan(m, chan, confirm=false)
29
+ if confirm == 'yes' || confirm == 'true'
30
+ Channel(chan).join
31
+ User('OperServ').send("mode #{chan} +o #{Zeta}")
32
+ User('OperServ').send("mode #{chan} +mi")
33
+ Channel(chan).send('This channel is being cleared')
34
+
35
+ number_killed = 0
36
+ Channel(chan).users.each_key do |u|
37
+ if u != Zeta
38
+ number_killed += 1
39
+ @bot.irc.send("KILL #{u.nick} This channel is being cleared")
40
+ end
41
+ end
42
+ m.safe_reply "#{chan} has been cleared, #{number_killed} clients killed"
43
+
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ Bot.config.plugins.plugins.push Admin::Oper
@@ -0,0 +1,109 @@
1
+ module Admin
2
+ class Plugins
3
+ include Cinch::Plugin
4
+ include Cinch::Helpers
5
+
6
+ enable_acl(:admin, true)
7
+
8
+ set(
9
+ plugin_name: 'PluginsAdmin',
10
+ help: "Bot administrator-only private commands.\nUsage: `~join [channel]`; `~part [channel] <reason>`; `~quit [reason]`;",
11
+ # prefix: /^\?/
12
+ )
13
+
14
+ # Regex
15
+ match(/plugin load (\S+)(?: (\S+))?/, method: :load_plugin)
16
+ match(/plugin unload (\S+)/, method: :unload_plugin)
17
+ match(/plugin reload (\S+)(?: (\S+))?/, method: :reload_plugin)
18
+ match(/plugin set (\S+) (\S+) (.+)$/, method: :set_option)
19
+
20
+ # Methods
21
+ def load_plugin(m, plugin, mapping)
22
+ mapping ||= plugin.gsub(/(.)([A-Z])/) { |_|
23
+ $1 + "_" + $2
24
+ }.downcase # we downcase here to also catch the first letter
25
+
26
+ #file_name = "lib/plugins/#{mapping}.rb"
27
+ stdlib_plugin = File.join('Zeta', 'plugins', p.to_s)
28
+ custom_plugin = File.join(Dir.home, '.zeta', 'plugins', p.to_s, "#{p.to_s}.rb")
29
+
30
+ unless File.exist?(custom_plugin)
31
+ m.reply "Could not load #{plugin} because #{file_name} does not exist."
32
+ return
33
+ end
34
+
35
+ begin
36
+ load(custom_plugin)
37
+ rescue
38
+ m.reply "Could not load #{plugin}."
39
+ raise
40
+ end
41
+
42
+ begin
43
+ const = Plugins.const_get(plugin)
44
+ rescue NameError
45
+ m.reply "Could not load #{plugin} because no matching class was found."
46
+ return
47
+ end
48
+
49
+ @bot.plugins.register_plugin(const)
50
+ m.reply "Successfully loaded #{plugin}"
51
+ end
52
+
53
+ def unload_plugin(m, plugin)
54
+ begin
55
+ plugin_class = Plugins.const_get(plugin)
56
+ rescue NameError
57
+ m.reply "Could not unload #{plugin} because no matching class was found."
58
+ return
59
+ end
60
+
61
+ @bot.plugins.select { |p| p.class == plugin_class }.each do |p|
62
+ @bot.plugins.unregister_plugin(p)
63
+ end
64
+
65
+ ## FIXME not doing this at the moment because it'll break
66
+ ## plugin options. This means, however, that reloading a
67
+ ## plugin is relatively dirty: old methods will not be removed
68
+ ## but only overwritten by new ones. You will also not be able
69
+ ## to change a classes superclass this way.
70
+ # Cinch::Plugins.__send__(:remove_const, plugin)
71
+
72
+ # Because we're not completely removing the plugin class,
73
+ # reset everything to the starting values.
74
+ plugin_class.hooks.clear
75
+ plugin_class.matchers.clear
76
+ plugin_class.listeners.clear
77
+ plugin_class.timers.clear
78
+ plugin_class.ctcps.clear
79
+ plugin_class.react_on = :message
80
+ plugin_class.plugin_name = nil
81
+ plugin_class.help = nil
82
+ plugin_class.prefix = nil
83
+ plugin_class.suffix = nil
84
+ plugin_class.required_options.clear
85
+
86
+ m.reply "Successfully unloaded #{plugin}"
87
+ end
88
+
89
+ def reload_plugin(m, plugin, mapping)
90
+ unload_plugin(m, plugin)
91
+ load_plugin(m, plugin, mapping)
92
+ end
93
+
94
+ def set_option(m, plugin, option, value)
95
+ begin
96
+ const = Plugins.const_get(plugin)
97
+ rescue NameError
98
+ m.reply "Could not set plugin option for #{plugin} because no matching class was found."
99
+ return
100
+ end
101
+ @bot.config.plugins.options[const][option.to_sym] = eval(value)
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+
108
+ # AutoLoad
109
+ Bot.config.plugins.plugins.push Admin::Plugins
@@ -0,0 +1,5 @@
1
+ module Admin
2
+ class Users
3
+
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ BlackListStruct = Struct.new :channels, :users, :plugins
2
+
3
+ # Load Cached
4
+ if File.exists?(File.join(Dir.home, '.zeta', 'cache', 'blacklist.rb'))
5
+ File.open(File.join(Dir.home, '.zeta', 'cache', 'blacklist.rb')) do |file|
6
+ Blacklist = Marshal.load(file)
7
+ end
8
+ else
9
+ Blacklist = BlackListStruct.new([], [], [])
10
+ end
11
+
12
+
13
+ ## Methods
14
+ def save_blacklist()
15
+ File.open(File.join(Dir.home, '.zeta', 'cache', 'blacklist.rb'), 'w+') do |file|
16
+ Marshal.dump(Blacklist, file)
17
+ end
18
+ end
19
+
20
+ def clear_blacklist()
21
+ Blacklist.users = []
22
+ Blacklist.plugins = []
23
+ Blacklist.channels = []
24
+ File.delete(File.join(Dir.home, '.zeta', 'cache', 'blacklist.rb'))
25
+ end
data/lib/Zeta/cache.rb ADDED
File without changes
data/lib/Zeta/cinch.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'cinch'
2
+
3
+ Bot = Cinch::Bot.new do
4
+ configure do |c|
5
+ c.nick = Config.nickname
6
+ c.nicks = Config.nicks.split(',')
7
+ c.user = Config.username
8
+ c.realname = Config.realname
9
+ c.sasl.username = Config.sasl_username
10
+ c.sasl.password = Config.sasl_password
11
+ c.server = Config.server
12
+ c.password = Config.password
13
+ c.port = Config.port
14
+ c.ssl.use = Config.ssl
15
+ c.max_messages = Config.max_messages
16
+ c.messages_per_second = Config.messages_per_second
17
+ c.modes = Config.modes.split(',')
18
+ c.channels = Config.channels.split(',')
19
+ c.plugins.prefix = /^#{Config.prefix}/
20
+ end
21
+
22
+ # Execute on confirmation of connection
23
+ on :connect do
24
+ # Gain operator privileges if oper username and password are set in config
25
+ if Config.oper_username && Config.oper_password
26
+ if !Config.oper_password.empty?
27
+ @bot.oper(Config.oper_password, Config.oper_username)
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+
@@ -0,0 +1,42 @@
1
+ ConfigStruct = Struct.new(
2
+ :locale,
3
+ :nickname,
4
+ :nicks,
5
+ :username,
6
+ :realname,
7
+ :prefix,
8
+ :server,
9
+ :password,
10
+ :port,
11
+ :ssl,
12
+ :sasl_username,
13
+ :sasl_password,
14
+ :max_messages,
15
+ :messages_per_second,
16
+ :modes,
17
+ :channels,
18
+ :custom_plugins,
19
+ :plugins,
20
+ :oper_username,
21
+ :oper_password,
22
+ :oper_overide,
23
+ :log_channel,
24
+ :services,
25
+ :secure_mode,
26
+ :secure_channel,
27
+ :secure_host,
28
+ :options,
29
+ :secrets
30
+ )
31
+ # Initialize Config
32
+ Config = ConfigStruct.new
33
+
34
+ if File.exists? File.join(Dir.home, '.zeta', 'config.rb')
35
+ begin
36
+ require File.join(Dir.home, '.zeta', 'config.rb')
37
+ rescue => e
38
+ puts e
39
+ abort('Unable to read config')
40
+ end
41
+
42
+ end
data/lib/Zeta/gems.rb ADDED
File without changes
@@ -0,0 +1,4 @@
1
+ def load_locale(file)
2
+ Config.locale ||= 'en'
3
+ YAML::load_file(File.join('locale', Config.locale, "#{file}.yml"))
4
+ end
data/lib/Zeta/log.rb ADDED
@@ -0,0 +1,2 @@
1
+ Bot.loggers << Cinch::Logger::FormattedLogger.new(File.open(File.join(Dir.home, '.zeta', 'log', 'error.log'), 'a'))
2
+ Bot.loggers.last.level = :error
@@ -0,0 +1,5 @@
1
+ module DB; end
2
+
3
+ require 'Zeta/models/user'
4
+ require 'Zeta/models/plugin'
5
+ require 'Zeta/models/channel'
@@ -0,0 +1,3 @@
1
+ class DB::Channel
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class DB::Plugin
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class DB::User
2
+
3
+ end
@@ -0,0 +1,27 @@
1
+ module Plugins; end
2
+
3
+ # Load STDLib plugins
4
+ if Config.plugins.class == Array
5
+ Config.plugins.each do |p|
6
+ begin
7
+ require File.join('Zeta', 'plugins', p.to_s)
8
+ rescue => e
9
+ puts e
10
+ warn "## Unable to load plugin: #{p} ##"
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ ## Load Custom Plugins
17
+ if Config.custom_plugins.class == Array
18
+ Config.custom_plugins.each do |p|
19
+ begin
20
+ require File.join(Dir.home, '.zeta', 'plugins', p.to_s, "#{p.to_s}.rb")
21
+ rescue => e
22
+ puts e
23
+ warn "## Unable to load Custom plugin: #{p} ##"
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'yaml'
4
+
5
+ module Plugins
6
+ class Attack
7
+ include Cinch::Plugin
8
+ include Cinch::Helpers
9
+
10
+ enable_acl
11
+
12
+ set(
13
+ plugin_name: 'Random Attacker',
14
+ help: 'Attacks a user with a random attack.\nUsage: `?attack <nick or phrase>`; `<nick or phrase>` may be omitted for a random attack on a random nick.',
15
+ react_on: :channel
16
+ )
17
+
18
+ def initialize(*args)
19
+ @attackdict = []
20
+ super
21
+ end
22
+
23
+ # Regex
24
+ match /attack(?: (.+))?/, group: :attack
25
+
26
+ # Methods
27
+ def execute(m, target=nil)
28
+ target = target.rstrip
29
+ target = m.user.nick if !target.nil? && target.match(/(\bmy\b|\b#{@bot.nick}\S*\b|\b\S*self\b)/i)
30
+ target.gsub(/(\bmy\b|\b#{@bot.nick}\S*\b|\b\S*self\b)/i,m.user.nick+"'s") if !target.nil?;
31
+ populate_attacks!
32
+ output = if target
33
+ attack!(target.gsub(/\x03([0-9]{2}(,[0-9]{2})?)?/,''), m.user.nick)
34
+ else
35
+ random_attack!(m.channel.users, m.user.nick)
36
+ end
37
+ m.channel.action output
38
+ end
39
+
40
+ private
41
+ def populate_attacks!
42
+ @attackdict.replace load_locale('attack').map {|e| e.gsub(/<(\w+)>/, "%<#{'\1'.downcase}>s") }
43
+ end
44
+
45
+ def grab_random_nick(users)
46
+ users.to_a.sample[0].nick;
47
+ end
48
+
49
+ def attack!(target, assailant)
50
+ return nil if target.nil?;
51
+ @attackdict.sample % {:target => target, :assailant => assailant, :bot => @bot.nick};
52
+ end
53
+
54
+ def random_attack!(targets, assailant)
55
+ @attackdict.sample % {:target => grab_random_nick(targets), :assailant => assailant, :bot => @bot.nick};
56
+ end
57
+ end
58
+ end
59
+
60
+ # AutoLoad
61
+ Bot.config.plugins.plugins.push Plugins::Attack
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tag_formatter'
3
+ require 'active_support/core_ext/object/blank'
4
+ require 'active_support/core_ext/array/conversions'
5
+ require 'chronic_duration'
6
+
7
+
8
+ module Plugins
9
+ class BotInfo
10
+ include Cinch::Plugin
11
+ include Cinch::Helpers
12
+
13
+ enable_acl
14
+
15
+ set(
16
+ plugin_name: "Botinfo",
17
+ help: "Notices you information about me.\nUsage: `/msg <nick> info`\nUsage: `/msg <nick> list plugins`",
18
+ react_on: :private)
19
+
20
+ def initialize *args
21
+ super
22
+ @started_at = Time.now
23
+ end
24
+
25
+ # How to config:
26
+ # :template -- a path to a textual file (such as *.txt) with fields in it.
27
+ # :owner -- What to display for the "owner_name" field.
28
+ # All fields in the text file must be surrounded by '<>', and lines can be commented out using '#'.
29
+
30
+ # Regex
31
+ match 'info', use_prefix: false
32
+ match 'list plugins', method: :execute_list, use_prefix: false
33
+ match /^help (.+)$/i, method: :execute_help, use_prefix: false
34
+
35
+ # Methods
36
+ def execute(m)
37
+ tags = {
38
+ bot_name: @bot.nick,
39
+ cinch_version: Cinch::VERSION,
40
+ #is_admin: config[:admins].is_admin?(m.user.mask) ? "an admin" : "not an admin",
41
+ owner_name: 'Liothen',
42
+ plugins_count_remaining: @bot.plugins.length - 10,
43
+ plugins_head: @bot.plugins[0..9].map {|p| p.class.plugin_name }.join(", "),
44
+ ruby_platform: RUBY_PLATFORM,
45
+ ruby_release_date: RUBY_RELEASE_DATE,
46
+ ruby_version: RUBY_VERSION,
47
+ session_start_date: @started_at.strftime("%A, %B %e, %Y, at %l:%M:%S %P"),
48
+ total_channels: @bot.channels.length,
49
+ total_users: proc {
50
+ users = [];
51
+ @bot.channels.each {|c|
52
+ c.users.each {|u| users << u[0].nick
53
+ }
54
+ };
55
+ users.uniq.size
56
+ }.call,
57
+ uptime: ChronicDuration.output(Time.now.to_i - @started_at.to_i)
58
+ }
59
+
60
+ tf = TagFormatter.new open(File.join(__dir__, '../botinfo.txt'),&:read), tags: tags
61
+
62
+ m.user.notice tf.parse
63
+ end
64
+
65
+ def execute_list(m)
66
+
67
+ list = []
68
+ @bot.plugins.each {|p| list << p.class.plugin_name };
69
+ m.user.notice("All #{list.size} currently loaded plugins for #{@bot.nick}:\n#{list.to_sentence}.\nTo view help for a plugin, use `/msg #{@bot.nick} help <plugin name>`.")
70
+ end
71
+
72
+ def execute_help(m, name)
73
+ list = {}
74
+ @bot.plugins.each {|p| list[p.class.plugin_name.downcase] = {name: p.class.plugin_name, help: p.class.help} };
75
+ return m.user.notice("Help for \"#{name}\" could not be found.") if !list.has_key?(name.downcase)
76
+ m.user.notice("Help for #{Format(:bold,list[name.downcase][:name])}:\n#{list[name.downcase][:help]}")
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+ # AutoLoad
83
+ Bot.config.plugins.plugins.push Plugins::BotInfo