zmb 0.1.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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.markdown +39 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/zmb +188 -0
- data/lib/zmb.rb +296 -0
- data/lib/zmb/commands.rb +63 -0
- data/lib/zmb/event.rb +15 -0
- data/lib/zmb/plugin.rb +110 -0
- data/lib/zmb/settings.rb +48 -0
- data/lib/zmb/timer.rb +28 -0
- data/plugins/bank.rb +101 -0
- data/plugins/commands.rb +119 -0
- data/plugins/irc.rb +230 -0
- data/plugins/quote.rb +100 -0
- data/plugins/relay.rb +70 -0
- data/plugins/users.rb +280 -0
- data/test/helper.rb +10 -0
- data/test/test_zmb.rb +7 -0
- data/zmb.gemspec +71 -0
- metadata +97 -0
    
        data/plugins/irc.rb
    ADDED
    
    | @@ -0,0 +1,230 @@ | |
| 1 | 
            +
            require 'socket'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zmb/timer'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class Event
         | 
| 6 | 
            +
              attr_accessor :delegate, :command, :args, :name, :userhost, :message
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              def initialize(sender, line)
         | 
| 9 | 
            +
                puts line
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                if line[0,1] == ':' then
         | 
| 12 | 
            +
                  line = line[1..-1] # Remove the :
         | 
| 13 | 
            +
                  hostname, command, args = line.split(' ', 3)
         | 
| 14 | 
            +
                  args = "#{hostname} #{args}"
         | 
| 15 | 
            +
                else
         | 
| 16 | 
            +
                  command, args = line.split(' ', 3)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                @delegate = sender
         | 
| 20 | 
            +
                @command = command.downcase
         | 
| 21 | 
            +
                @args = args
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                case @command
         | 
| 24 | 
            +
                  when 'privmsg'
         | 
| 25 | 
            +
                    @userhost, @channel, @message = args.split(' ', 3)
         | 
| 26 | 
            +
                    @name, @userhost = @userhost.split('!', 2)
         | 
| 27 | 
            +
                    @message = @message[1..-1]
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
              
         | 
| 31 | 
            +
              def private?
         | 
| 32 | 
            +
                @channel == @delegate.nick
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              def sender
         | 
| 36 | 
            +
                private? ? @name : @channel
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
              
         | 
| 39 | 
            +
              def message?
         | 
| 40 | 
            +
                @message != nil
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
              
         | 
| 43 | 
            +
              def reply(m)
         | 
| 44 | 
            +
                if message? then
         | 
| 45 | 
            +
                  m = m.split("\n") if not m.respond_to?('each')
         | 
| 46 | 
            +
                  m.each{ |mess| @delegate.message(sender, mess) }
         | 
| 47 | 
            +
                else
         | 
| 48 | 
            +
                  @delegate.write m
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            class IrcConnection
         | 
| 54 | 
            +
              attr_accessor :host, :port, :channels, :nick, :name, :realname, :password, :throttle
         | 
| 55 | 
            +
              
         | 
| 56 | 
            +
              def initialize(sender, settings={})
         | 
| 57 | 
            +
                @delegate = sender
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                @host = settings['host'] if settings.has_key?('host')
         | 
| 60 | 
            +
                begin
         | 
| 61 | 
            +
                  @port = Integer(settings['port']) if settings.has_key?('port')
         | 
| 62 | 
            +
                rescue Exception
         | 
| 63 | 
            +
                  @port = 6667
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
                
         | 
| 66 | 
            +
                @channels = Array.new
         | 
| 67 | 
            +
                @channels = settings['channels'] if settings.has_key?('channels')
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                @nick = settings['nick'] if settings.has_key?('nick')
         | 
| 70 | 
            +
                @name = settings['name'] if settings.has_key?('name')
         | 
| 71 | 
            +
                @realname = settings['realname'] if settings.has_key?('realname')
         | 
| 72 | 
            +
                @password = settings['password'] if settings.has_key?('password')
         | 
| 73 | 
            +
                
         | 
| 74 | 
            +
                @throttle = 10
         | 
| 75 | 
            +
                @throttle = settings['throttle'] if settings.has_key?('throttle')
         | 
| 76 | 
            +
                
         | 
| 77 | 
            +
                sender.timer_add(Timer.new(self, :connect, 0.1, false)) if sender.running?
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
              
         | 
| 80 | 
            +
              def socket=(value)
         | 
| 81 | 
            +
                @socket = value
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
              
         | 
| 84 | 
            +
              def to_json(*a)
         | 
| 85 | 
            +
                {
         | 
| 86 | 
            +
                  'host' => @host,
         | 
| 87 | 
            +
                  'port' => @port,
         | 
| 88 | 
            +
                  
         | 
| 89 | 
            +
                  'channels' => @channels,
         | 
| 90 | 
            +
                  
         | 
| 91 | 
            +
                  'nick' => @nick,
         | 
| 92 | 
            +
                  'name' => @name,
         | 
| 93 | 
            +
                  'realname' => @realname,
         | 
| 94 | 
            +
                  'password' => @password,
         | 
| 95 | 
            +
                  
         | 
| 96 | 
            +
                  'throttle' => @throttle,
         | 
| 97 | 
            +
                  'plugin' => 'irc',
         | 
| 98 | 
            +
                }.to_json(*a)
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
              
         | 
| 101 | 
            +
              def self.wizard
         | 
| 102 | 
            +
                {
         | 
| 103 | 
            +
                  'host' => { 'help' => 'Hostname', 'default' => 'localhost' },
         | 
| 104 | 
            +
                  'port' => { 'help' => 'Port', 'default' => 6667 },
         | 
| 105 | 
            +
                  'nick' => { 'help' => 'Nickname', 'default' => 'zmb' },
         | 
| 106 | 
            +
                  'name' => { 'help' => 'Name', 'default' => 'zmb' },
         | 
| 107 | 
            +
                  'realname' => { 'help' => 'Realname', 'default' => 'zmb' },
         | 
| 108 | 
            +
                  'password' => { 'help' => 'If the ircd requires a password, enter this here.', 'default' => nil },
         | 
| 109 | 
            +
                }
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
              
         | 
| 112 | 
            +
              def commands
         | 
| 113 | 
            +
                require 'zmb/commands'
         | 
| 114 | 
            +
                {
         | 
| 115 | 
            +
                  'join' => PermCommand.new('admin', self, :join_command),
         | 
| 116 | 
            +
                  'part' => PermCommand.new('admin', self, :part_command),
         | 
| 117 | 
            +
                  'raw' => PermCommand.new('admin', self, :raw_command),
         | 
| 118 | 
            +
                  'tell' => PermCommand.new('admin', self, :tell_command, 2),
         | 
| 119 | 
            +
                }
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
              
         | 
| 122 | 
            +
              def unloaded
         | 
| 123 | 
            +
                write "Quit :ZMB"
         | 
| 124 | 
            +
                @socket.close if @socket
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
              
         | 
| 127 | 
            +
              def nick=(value)
         | 
| 128 | 
            +
                @nick = value
         | 
| 129 | 
            +
                write "NICK #{@nick}"
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
              
         | 
| 132 | 
            +
              def connected?
         | 
| 133 | 
            +
                @socket != nil
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
              
         | 
| 136 | 
            +
              def connect
         | 
| 137 | 
            +
                if @host and @port and not connected? then
         | 
| 138 | 
            +
                  Thread.new do
         | 
| 139 | 
            +
                    @socket = TCPSocket.new(@host, @port)
         | 
| 140 | 
            +
                    @delegate.socket_add(self, @socket)
         | 
| 141 | 
            +
                    perform
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
              
         | 
| 146 | 
            +
              def disconnected(sender, socket)
         | 
| 147 | 
            +
                @socket = nil
         | 
| 148 | 
            +
                sender.timer_add(Timer.new(self, :connect, @throttle))
         | 
| 149 | 
            +
              end
         | 
| 150 | 
            +
              
         | 
| 151 | 
            +
              def perform
         | 
| 152 | 
            +
                write "PASS #{@password}" if @password
         | 
| 153 | 
            +
                write "NICK #{@nick}" if @nick
         | 
| 154 | 
            +
                write "USER #{@name} 0 0 :#{@realname}" if @name and @realname
         | 
| 155 | 
            +
              end
         | 
| 156 | 
            +
              
         | 
| 157 | 
            +
              def write(line)
         | 
| 158 | 
            +
                @socket.write line + "\r\n" if @socket
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
              
         | 
| 161 | 
            +
              def message(recipient, msg)
         | 
| 162 | 
            +
                write "PRIVMSG #{recipient} :#{msg}"
         | 
| 163 | 
            +
              end
         | 
| 164 | 
            +
              
         | 
| 165 | 
            +
              def join(channel)
         | 
| 166 | 
            +
                @channels << channel if not @channels.include?(channel)
         | 
| 167 | 
            +
                write "JOIN #{channel}"
         | 
| 168 | 
            +
              end
         | 
| 169 | 
            +
              
         | 
| 170 | 
            +
              def part(channel)
         | 
| 171 | 
            +
                @channels.delete(channel) if @channels.include?(channel)
         | 
| 172 | 
            +
                write "PART #{channel}"
         | 
| 173 | 
            +
              end
         | 
| 174 | 
            +
              
         | 
| 175 | 
            +
              def received(sender, socket, data)
         | 
| 176 | 
            +
                @buffer = '' if @buffer == nil
         | 
| 177 | 
            +
                @buffer += data
         | 
| 178 | 
            +
                line, @buffer = @buffer.split("\r\n", 2)
         | 
| 179 | 
            +
                @buffer = '' if @buffer == nil
         | 
| 180 | 
            +
                
         | 
| 181 | 
            +
                while line != nil do
         | 
| 182 | 
            +
                  e = Event.new(self, line)
         | 
| 183 | 
            +
                  
         | 
| 184 | 
            +
                  # Catch some events
         | 
| 185 | 
            +
                  case e.command
         | 
| 186 | 
            +
                    when 'ping' then write "PONG #{e.args[1..-1]}"
         | 
| 187 | 
            +
                    when '001' then @channels.each{ |channel| write "JOIN #{channel}" }
         | 
| 188 | 
            +
                    when 'nick' then tmp, @nick = e.args.split(' :', 2)
         | 
| 189 | 
            +
                    when '433' then
         | 
| 190 | 
            +
                      @nick="#{@nick}_"
         | 
| 191 | 
            +
                      write "NICK #{@nick}"
         | 
| 192 | 
            +
                  end
         | 
| 193 | 
            +
                  
         | 
| 194 | 
            +
                  @delegate.event(self, e)
         | 
| 195 | 
            +
                  line, @buffer = @buffer.split("\r\n", 2)
         | 
| 196 | 
            +
                end
         | 
| 197 | 
            +
              end
         | 
| 198 | 
            +
              
         | 
| 199 | 
            +
              def join_command(e, channel)
         | 
| 200 | 
            +
                join channel
         | 
| 201 | 
            +
                "#{channel} joined"
         | 
| 202 | 
            +
              end
         | 
| 203 | 
            +
              
         | 
| 204 | 
            +
              def part_command(e, channel)
         | 
| 205 | 
            +
                part channel
         | 
| 206 | 
            +
                "left #{channel}"
         | 
| 207 | 
            +
              end
         | 
| 208 | 
            +
              
         | 
| 209 | 
            +
              def raw_command(e, line)
         | 
| 210 | 
            +
                write line
         | 
| 211 | 
            +
                nil
         | 
| 212 | 
            +
              end
         | 
| 213 | 
            +
              
         | 
| 214 | 
            +
              def tell_command(e, to, message)
         | 
| 215 | 
            +
                msg = msg.split("\n") if not msg.respond_to?('each')
         | 
| 216 | 
            +
                msg.each{ |m| message(to, m) }
         | 
| 217 | 
            +
                nil
         | 
| 218 | 
            +
              end
         | 
| 219 | 
            +
              
         | 
| 220 | 
            +
              def running(sender)
         | 
| 221 | 
            +
                connect
         | 
| 222 | 
            +
              end
         | 
| 223 | 
            +
            end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
            Plugin.define do
         | 
| 226 | 
            +
              name "irc"
         | 
| 227 | 
            +
              description "A plugin which allows you to connect to irc servers."
         | 
| 228 | 
            +
              object IrcConnection
         | 
| 229 | 
            +
              multi_instances true
         | 
| 230 | 
            +
            end
         | 
    
        data/plugins/quote.rb
    ADDED
    
    | @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            class Quote
         | 
| 2 | 
            +
              attr_accessor :quotes, :autoindex
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def initialize(sender, settings={})
         | 
| 5 | 
            +
                @quotes = Hash.new
         | 
| 6 | 
            +
                @quotes = settings['quotes'] if settings.has_key?('quotes')
         | 
| 7 | 
            +
                @autoindex = 1
         | 
| 8 | 
            +
                @autoindex = settings['autoindex'] if settings.has_key?('autoindex')
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              def to_json(*a)
         | 
| 12 | 
            +
                {
         | 
| 13 | 
            +
                  'plugin' => 'quote',
         | 
| 14 | 
            +
                  'quotes' => @quotes,
         | 
| 15 | 
            +
                  'autoindex' => @autoindex,
         | 
| 16 | 
            +
                }.to_json(*a)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              def add(quote, username=nil)
         | 
| 20 | 
            +
                @quotes["#{@autoindex}"] = {
         | 
| 21 | 
            +
                  'quote' => quote,
         | 
| 22 | 
            +
                  'time' => Time.now,
         | 
| 23 | 
            +
                  'username' => username,
         | 
| 24 | 
            +
                }
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                @autoindex += 1
         | 
| 27 | 
            +
                @autoindex - 1
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
              
         | 
| 30 | 
            +
              def count
         | 
| 31 | 
            +
                @quotes.keys.count
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
              
         | 
| 34 | 
            +
              def commands
         | 
| 35 | 
            +
                require 'zmb/commands'
         | 
| 36 | 
            +
                {
         | 
| 37 | 
            +
                  'quote' => Command.new(self, :quote_command, 1, 'Show a random quote or the quote with matching id'),
         | 
| 38 | 
            +
                  'quote-add' => Command.new(self, :add_command, 1, 'Add a quote'),
         | 
| 39 | 
            +
                  'quote-del' => PermCommand.new('quote', self, :del_command, 1, 'Delete a quote by id'),
         | 
| 40 | 
            +
                  'quote-count' => Command.new(self, :count_command, 0, 'Show amount of quotes'),
         | 
| 41 | 
            +
                  'quote-last' => Command.new(self, :last_command, 0, 'Show the last quote'),
         | 
| 42 | 
            +
                  'quote-search' => Command.new(self, :search_command, 1, 'Search to find a quote'),
         | 
| 43 | 
            +
                }
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
              
         | 
| 46 | 
            +
              def quote_command(e, id=nil)
         | 
| 47 | 
            +
                return "quote \##{id} not found" if id and not @quotes.has_key?(id)
         | 
| 48 | 
            +
                return "\"#{@quotes[id]['quote']}\" by #{@quotes[id]['username']} at #{@quotes[id]['time']}" if id
         | 
| 49 | 
            +
                return "no quotes" if count < 1
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                id = "#{rand(autoindex - 1) + 1}"
         | 
| 52 | 
            +
                while not @quotes.has_key?(id)
         | 
| 53 | 
            +
                  id = "#{rand(autoindex - 1) + 1}"
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                "\"#{@quotes[id]['quote']}\" by #{@quotes[id]['username']} at #{@quotes[id]['time']}"
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
              
         | 
| 59 | 
            +
              def add_command(e, quote)
         | 
| 60 | 
            +
                if e.user and e.user.respond_to?('authenticated?') and e.user.authenticated? then
         | 
| 61 | 
            +
                  "quote added \##{add(quote, e.user.username)}"
         | 
| 62 | 
            +
                else
         | 
| 63 | 
            +
                  'permission denied'
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
              
         | 
| 67 | 
            +
              def del_command(e, id)
         | 
| 68 | 
            +
                if @quotes.has_key?(id) then
         | 
| 69 | 
            +
                  @quotes.delete id
         | 
| 70 | 
            +
                  "quote #{id} deleted"
         | 
| 71 | 
            +
                else
         | 
| 72 | 
            +
                  "no quote found with id=#{id}"
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
              
         | 
| 76 | 
            +
              def count_command(e)
         | 
| 77 | 
            +
                "#{count} quotes"
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
              
         | 
| 80 | 
            +
              def last_command(e)
         | 
| 81 | 
            +
                return "no quotes" if count < 1
         | 
| 82 | 
            +
                quote_command(e, @quotes.keys.sort.reverse[0])
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
              
         | 
| 85 | 
            +
              def search_command(e, search)
         | 
| 86 | 
            +
                result = @quotes.map{ |id, quote| "#{id}: #{quote['quote']}" if quote['quote'].include?(search) }.reject{ |q| not q }
         | 
| 87 | 
            +
                
         | 
| 88 | 
            +
                if result.count then
         | 
| 89 | 
            +
                  result.join("\n")
         | 
| 90 | 
            +
                else
         | 
| 91 | 
            +
                  "no quotes found"
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
            end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            Plugin.define do
         | 
| 97 | 
            +
              name "quote"
         | 
| 98 | 
            +
              description "quote database"
         | 
| 99 | 
            +
              object Quote
         | 
| 100 | 
            +
            end
         | 
    
        data/plugins/relay.rb
    ADDED
    
    | @@ -0,0 +1,70 @@ | |
| 1 | 
            +
            class Relay
         | 
| 2 | 
            +
              attr_accessor :relays
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def initialize(sender, settings={})
         | 
| 5 | 
            +
                @relays = settings['relays'] if settings.has_key?('relays')
         | 
| 6 | 
            +
                @relays = Hash.new if not @relays
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                @delegate = sender
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              def to_json(*a)
         | 
| 12 | 
            +
                { 'relays' => @relays, 'plugin' => 'relay' }.to_json(*a)
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def event(sender, e)
         | 
| 16 | 
            +
                if e.message? and @delegate.instances.has_value?(sender) then
         | 
| 17 | 
            +
                  relay = "#{@delegate.instances.invert[sender]}:#{e.sender}"
         | 
| 18 | 
            +
                  
         | 
| 19 | 
            +
                  if @relays.has_key?(relay) then
         | 
| 20 | 
            +
                    instance, recipient = @relays[relay].split(':', 2)
         | 
| 21 | 
            +
                    @delegate.instances[instance].message(recipient, "<#{e.name}> #{e.message}") if @delegate.instances.has_key?(instance)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
              def commands
         | 
| 27 | 
            +
                require 'zmb/commands'
         | 
| 28 | 
            +
                {
         | 
| 29 | 
            +
                  'relays' => PermCommand.new('admin', self, :relays_command, 0, 'Show all relays'),
         | 
| 30 | 
            +
                  'relay-add' => PermCommand.new('admin', self, :add_command, 2, 'Add a relay'),
         | 
| 31 | 
            +
                  'relay-del' => PermCommand.new('admin', self, :del_command, 1, 'Delete a relay'),
         | 
| 32 | 
            +
                }
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              def relays_command(e)
         | 
| 36 | 
            +
                if @relays.count < 1 then
         | 
| 37 | 
            +
                  "no relays"
         | 
| 38 | 
            +
                else
         | 
| 39 | 
            +
                  @relays.map{ |relay, location| "#{relay} > #{location}"}.join("\n")
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
              
         | 
| 43 | 
            +
              def add_command(e, relay, location)
         | 
| 44 | 
            +
                if relay.include? ':' and location.include? ':' then
         | 
| 45 | 
            +
                  if @relays.has_key?(relay) then
         | 
| 46 | 
            +
                    "relays must be unique"
         | 
| 47 | 
            +
                  else
         | 
| 48 | 
            +
                    @relays[relay] = location
         | 
| 49 | 
            +
                    "relay setup #{relay} => #{location}"
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                else
         | 
| 52 | 
            +
                  "relays must be in the format: plugin:location, example (efnet:\#zmb)"
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
              
         | 
| 56 | 
            +
              def del_command(e, relay)
         | 
| 57 | 
            +
                if @relays.has_key?(relay) then
         | 
| 58 | 
            +
                  @relays.delete(relay)
         | 
| 59 | 
            +
                  "#{relay}: relay deleted"
         | 
| 60 | 
            +
                else
         | 
| 61 | 
            +
                  "no such relay"
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            Plugin.define do
         | 
| 67 | 
            +
              name "relay"
         | 
| 68 | 
            +
              description "This plugin allows you to relay messages from one channel/server to another."
         | 
| 69 | 
            +
              object Relay
         | 
| 70 | 
            +
            end
         | 
    
        data/plugins/users.rb
    ADDED
    
    | @@ -0,0 +1,280 @@ | |
| 1 | 
            +
            class Event
         | 
| 2 | 
            +
              attr_accessor :user
         | 
| 3 | 
            +
            end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class User
         | 
| 6 | 
            +
              require 'digest/sha1'
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              attr_accessor :username, :password, :userhosts, :permissions, :seen
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def to_json(*a)
         | 
| 11 | 
            +
                {'username' => @username, 'password' => @password, 'userhosts' => @userhosts, 'permissions' => @permissions, 'seen' => @seen}.to_json(*a)
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
              def self.create_settings(data)
         | 
| 15 | 
            +
                require 'time'
         | 
| 16 | 
            +
                user = new(data['username'], data['password'])
         | 
| 17 | 
            +
                user.userhosts = data['userhosts'] if data.has_key?('userhosts')
         | 
| 18 | 
            +
                user.permissions = data['permissions'] if data.has_key?('permissions')
         | 
| 19 | 
            +
                user.seen = Time.parse(data['seen']) if data.has_key?('seen') and data['seen']
         | 
| 20 | 
            +
                user
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              def initialize(username=nil, password=nil, userhost=nil)
         | 
| 24 | 
            +
                @username = username
         | 
| 25 | 
            +
                @password = Digest::SHA1.hexdigest(password) if password
         | 
| 26 | 
            +
                @userhosts = Array.new
         | 
| 27 | 
            +
                @userhosts << userhost if userhost
         | 
| 28 | 
            +
                @permissions = Array.new
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
              
         | 
| 31 | 
            +
              def concat(other_user)
         | 
| 32 | 
            +
                @permissions += other_user.permissions
         | 
| 33 | 
            +
                @userhosts += other_user.userhosts
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
              
         | 
| 36 | 
            +
              def password=(new_password)
         | 
| 37 | 
            +
                @password = Digest::SHA1.hexdigest(new_password)
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
              
         | 
| 40 | 
            +
              def password?(check_password)
         | 
| 41 | 
            +
                @password != nil and @password == Digest::SHA1.hexdigest(check_password)
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
              
         | 
| 44 | 
            +
              def authenticated?
         | 
| 45 | 
            +
                true
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
              def admin?
         | 
| 49 | 
            +
                @permissions.include?("owner") or @permissions.include?("admin")
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
              
         | 
| 52 | 
            +
              def permission?(permission)
         | 
| 53 | 
            +
                admin? or @permissions.include?(permission)
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
              
         | 
| 56 | 
            +
              def permit(permission)
         | 
| 57 | 
            +
                @permissions << permission
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
              
         | 
| 60 | 
            +
              def deny(permission)
         | 
| 61 | 
            +
                @permissions.delete(permission)
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            class AnonymousUser
         | 
| 66 | 
            +
              def authenticated?
         | 
| 67 | 
            +
                false
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
              
         | 
| 70 | 
            +
              def permission?(permission)
         | 
| 71 | 
            +
                false
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
              
         | 
| 74 | 
            +
              def admin?
         | 
| 75 | 
            +
                false
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            class Users
         | 
| 80 | 
            +
              attr_accessor :users
         | 
| 81 | 
            +
              
         | 
| 82 | 
            +
              def initialize(sender, settings={})
         | 
| 83 | 
            +
                @delegate = sender
         | 
| 84 | 
            +
                @users = settings['users'].map{ |user| User.create_settings(user) } if settings.has_key?('users')
         | 
| 85 | 
            +
                @users = Array.new if not @users
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
              
         | 
| 88 | 
            +
              def to_json(*a)
         | 
| 89 | 
            +
                {'users' => @users, 'plugin' => 'users'}.to_json(*a)
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
              
         | 
| 92 | 
            +
              def user!(search)
         | 
| 93 | 
            +
                @users.find{|user| user.userhosts.include?(search) or user.username == search}
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
              
         | 
| 96 | 
            +
              def user(search)
         | 
| 97 | 
            +
                user!(search) or AnonymousUser.new
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
              
         | 
| 100 | 
            +
              def pre_event(sender, e)
         | 
| 101 | 
            +
                e.user = user(e.userhost) if e.respond_to?('userhost') and not e.user
         | 
| 102 | 
            +
                e.user.seen = Time.now if e.user.respond_to?('seen')
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
              
         | 
| 105 | 
            +
              def create_user(username, password=nil, userhost=nil)
         | 
| 106 | 
            +
                user = User.new(username, password, userhost)
         | 
| 107 | 
            +
                @users << user
         | 
| 108 | 
            +
                user
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
              
         | 
| 111 | 
            +
              def commands
         | 
| 112 | 
            +
                require 'zmb/commands'
         | 
| 113 | 
            +
                {
         | 
| 114 | 
            +
                  'meet' => Command.new(self, :meet, 1, 'Meet a new user'),
         | 
| 115 | 
            +
                  'forget' => AuthCommand.new(self, :forget, 0, "Forget about a user"),
         | 
| 116 | 
            +
                  'permit' => PermCommand.new('admin', self, :permit, 2),
         | 
| 117 | 
            +
                  'deny' => PermCommand.new('admin', self, :deny, 2),
         | 
| 118 | 
            +
                  'perms' => AuthCommand.new(self, :perms, 1, 'List all permissions a user has.'),
         | 
| 119 | 
            +
                  'merge' => PermCommand.new('admin', self, :merge, 2, 'Merge two users together'),
         | 
| 120 | 
            +
                  'password' => AuthCommand.new(self, :password, 1, 'Set the password for your account'),
         | 
| 121 | 
            +
                  'login' => Command.new(self, :login, 2, 'Add your current host to the username and password provided.'),
         | 
| 122 | 
            +
                  'logout' => AuthCommand.new(self, :logout, 0, 'Remove your current host from your account.'),
         | 
| 123 | 
            +
                  'whoami' => Command.new(self, :whoami, 0, 'Who are you logged in as?'),
         | 
| 124 | 
            +
                  'userhosts' => AuthCommand.new(self, :userhosts, 0, 'List all the hosts associated with your account'),
         | 
| 125 | 
            +
                  'adduserhost' => AuthCommand.new(self, :adduserhost, 1, 'Add a host to your account'),
         | 
| 126 | 
            +
                  'deluserhost' => AuthCommand.new(self, :deluserhost, 1, 'Remove a host to your account'),
         | 
| 127 | 
            +
                  'names' => Command.new(self, :names, 1, 'List all the users'),
         | 
| 128 | 
            +
                  'seen' => Command.new(self, :seen, 1, 'When was a user last seen'),
         | 
| 129 | 
            +
                  'sudo' => PermCommand.new('admin', self, :sudo, 2, 'Execute a command as another user.'),
         | 
| 130 | 
            +
                }
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
              
         | 
| 133 | 
            +
              def meet(e, username=nil)
         | 
| 134 | 
            +
                if e.user.admin? and username then
         | 
| 135 | 
            +
                  return "#{username} already exists" if user!(username)
         | 
| 136 | 
            +
                  user = create_user(username)
         | 
| 137 | 
            +
                  "Hello #{username}"
         | 
| 138 | 
            +
                elsif not e.user.authenticated? then
         | 
| 139 | 
            +
                  return "#{e.sender} already exists" if user!(e.sender)
         | 
| 140 | 
            +
                  if e.respond_to?('userhost') and e.respond_to?('user') then
         | 
| 141 | 
            +
                    user = create_user(e.name, nil, e.userhost)
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
                  "Hello #{user.username}"
         | 
| 144 | 
            +
                else
         | 
| 145 | 
            +
                  "You already have an account #{e.user.username}"
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
              end
         | 
| 148 | 
            +
              
         | 
| 149 | 
            +
              def forget(e)
         | 
| 150 | 
            +
                "user #{@e.users.delete(e.user).username} deleted"
         | 
| 151 | 
            +
              end
         | 
| 152 | 
            +
              
         | 
| 153 | 
            +
              def permit(e, username, permission)
         | 
| 154 | 
            +
                if user = user!(username) then
         | 
| 155 | 
            +
                  user.permit(permission)
         | 
| 156 | 
            +
                  "permission added"
         | 
| 157 | 
            +
                else
         | 
| 158 | 
            +
                  "#{username} does not exist"
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
              end
         | 
| 161 | 
            +
              
         | 
| 162 | 
            +
              def deny(e, username, permission)
         | 
| 163 | 
            +
                if user = user!(username) then
         | 
| 164 | 
            +
                  user.deny(permission)
         | 
| 165 | 
            +
                  'permission removed'
         | 
| 166 | 
            +
                else
         | 
| 167 | 
            +
                  "#{username} does not exist"
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
              
         | 
| 171 | 
            +
              def perms(e, username=nil)
         | 
| 172 | 
            +
                e.user.permissions.empty? ? "#{e.user.username} has no permissions" : e.user.permissions.join(', ')
         | 
| 173 | 
            +
              end
         | 
| 174 | 
            +
              
         | 
| 175 | 
            +
              def merge(e, username, other_username)
         | 
| 176 | 
            +
                user = user!(username)
         | 
| 177 | 
            +
                other_user = user!(other_username)
         | 
| 178 | 
            +
                
         | 
| 179 | 
            +
                if user and other_user then
         | 
| 180 | 
            +
                  user.concat other_user 
         | 
| 181 | 
            +
                  @users.delete other_user
         | 
| 182 | 
            +
                  "#{other_user.username} now merged into #{user.username}"
         | 
| 183 | 
            +
                else
         | 
| 184 | 
            +
                  'User(s) do not exist'
         | 
| 185 | 
            +
                end
         | 
| 186 | 
            +
              end
         | 
| 187 | 
            +
              
         | 
| 188 | 
            +
              def password(e, password)
         | 
| 189 | 
            +
                e.user.password = password
         | 
| 190 | 
            +
                "#{e.user.username} password has been set to #{password}"
         | 
| 191 | 
            +
              end
         | 
| 192 | 
            +
              
         | 
| 193 | 
            +
              def login(e, username, password)
         | 
| 194 | 
            +
                user = user!(username)
         | 
| 195 | 
            +
                
         | 
| 196 | 
            +
                if e.user.authenticated? then
         | 
| 197 | 
            +
                  'already logged in'
         | 
| 198 | 
            +
                elsif user and user.password?(password) then
         | 
| 199 | 
            +
                  user.hosts << e.userhost
         | 
| 200 | 
            +
                  "#{request.hostname} added to your account #{user.username}"
         | 
| 201 | 
            +
                else
         | 
| 202 | 
            +
                  'user and/or password is incorrect'
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
              end
         | 
| 205 | 
            +
              
         | 
| 206 | 
            +
              def logout(e)
         | 
| 207 | 
            +
                e.user.hosts.delete(e.userhost)
         | 
| 208 | 
            +
                "userhost #{e.hostname} removed from your account."
         | 
| 209 | 
            +
              end
         | 
| 210 | 
            +
              
         | 
| 211 | 
            +
              def whoami(e)
         | 
| 212 | 
            +
                e.user.authenticated? ? "#{e.user.username}" : 'nobody'
         | 
| 213 | 
            +
              end
         | 
| 214 | 
            +
              
         | 
| 215 | 
            +
              def userhosts(e)
         | 
| 216 | 
            +
                e.user.userhosts.empty? ?  "#{e.user.username} has no userhosts" : e.user.userhosts.join(', ')
         | 
| 217 | 
            +
              end
         | 
| 218 | 
            +
              
         | 
| 219 | 
            +
              def adduserhost(e, userhost)
         | 
| 220 | 
            +
                e.user.userhosts << userhost
         | 
| 221 | 
            +
                "#{userhost} added to #{e.user.username}"
         | 
| 222 | 
            +
              end
         | 
| 223 | 
            +
              
         | 
| 224 | 
            +
              def deluserhost(e, userhost)
         | 
| 225 | 
            +
                if e.user.userhosts.delete(userhost) then
         | 
| 226 | 
            +
                  "#{userhost} deleted from #{e.user.username}"
         | 
| 227 | 
            +
                else
         | 
| 228 | 
            +
                  "#{e.user.username} doesn't have #{userhost}"
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
              end
         | 
| 231 | 
            +
              
         | 
| 232 | 
            +
              def names(e, search=nil)
         | 
| 233 | 
            +
                users = @users.map{|user| user.username}
         | 
| 234 | 
            +
                users = users.grep(/#{search}/i) if search
         | 
| 235 | 
            +
                
         | 
| 236 | 
            +
                if users.empty? then
         | 
| 237 | 
            +
                  "no users found"
         | 
| 238 | 
            +
                else
         | 
| 239 | 
            +
                  users.join(', ')
         | 
| 240 | 
            +
                end
         | 
| 241 | 
            +
              end
         | 
| 242 | 
            +
              
         | 
| 243 | 
            +
              def seen(e, username=nil)
         | 
| 244 | 
            +
                if user = user!(username) and user.seen then
         | 
| 245 | 
            +
                  diff = Time.now - user.seen
         | 
| 246 | 
            +
                  
         | 
| 247 | 
            +
                  if diff < 60 then
         | 
| 248 | 
            +
                    msg = "#{Integer(diff)} seconds ago"
         | 
| 249 | 
            +
                  elsif diff < 3600 then
         | 
| 250 | 
            +
                    msg = "#{Integer(diff/60)} minutes ago"
         | 
| 251 | 
            +
                  elsif diff < 86400 then
         | 
| 252 | 
            +
                    msg = "about #{Integer(diff/3600)} hours ago"
         | 
| 253 | 
            +
                  else
         | 
| 254 | 
            +
                    msg = "#{Integer(diff/86400)} days ago"
         | 
| 255 | 
            +
                  end
         | 
| 256 | 
            +
                  
         | 
| 257 | 
            +
                  "#{username} last seen #{msg}"
         | 
| 258 | 
            +
                else
         | 
| 259 | 
            +
                  "#{username} has never been seen"
         | 
| 260 | 
            +
                end
         | 
| 261 | 
            +
              end
         | 
| 262 | 
            +
              
         | 
| 263 | 
            +
              def sudo(e, search, command)
         | 
| 264 | 
            +
                if user = user!(search) then
         | 
| 265 | 
            +
                  new_event = e.clone
         | 
| 266 | 
            +
                  new_event.user = user
         | 
| 267 | 
            +
                  new_event.message = @delegate.instances['commands'].cc + command
         | 
| 268 | 
            +
                  @delegate.event(self, new_event)
         | 
| 269 | 
            +
                  nil
         | 
| 270 | 
            +
                else
         | 
| 271 | 
            +
                  "#{search}: Username or userhost not found"
         | 
| 272 | 
            +
                end
         | 
| 273 | 
            +
              end
         | 
| 274 | 
            +
            end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
            Plugin.define do 
         | 
| 277 | 
            +
              name "users"
         | 
| 278 | 
            +
              description "users manager"
         | 
| 279 | 
            +
              object Users
         | 
| 280 | 
            +
            end
         |