zetabot 0.0.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 (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