Last active
August 29, 2015 13:56
-
-
Save jangler/9165383 to your computer and use it in GitHub Desktop.
extensible IRC bot (requires suckless.org sic)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# vim:sw=2 | |
# IRC bot (requires suckless.org sic). | |
# Each executable file in the current directory is treated as a command | |
# plugin for the bot, and is executed when a command corresponding to its | |
# filename is called. For example, a plugin with filename "greet" would be | |
# invoked via the command "!greet". | |
# The plugin is passed the channel, nick, and message of its invocation as | |
# 3 positional arguments. Any line printed to standard output by the plugin | |
# is forwarded to the channel of the invoking message. | |
require 'optparse' | |
require 'shellwords' | |
OPTIONS, CHANNELS = begin | |
options, channels = [], [] | |
OptionParser.new do |opts| | |
opts.on('-s', '--server <server>', | |
'Overrides the default server') { |serv| options << '-h' << serv } | |
opts.on('-p', '--port <port>', Integer, | |
'Overrides the default port') { |port| options << '-p' << port } | |
opts.on('-n', '--nick <nick>', | |
'Override the default nick') { |nick| options << '-n' << nick } | |
opts.on('-k', '--keyword <keyword>', | |
'Specifies the keyword to authenticate your', | |
'nick on the host') { |keyword| options << '-k' << keyword } | |
opts.on('-c', '--channels <channels>', | |
'Comma-separated list of channels to join') do |list| | |
channels = list.split(',') | |
end | |
end.parse! | |
[options.freeze, channels.freeze] | |
end | |
def join_channels(subprocess) | |
subprocess.each_line do |line| | |
if line.include? ' >< MODE (' | |
CHANNELS.each { |chan| subprocess.write(":j ##{chan}\n") } | |
subprocess.flush | |
break | |
end | |
end | |
end | |
def run_plugin(subprocess, plugin, channel, nick, msg) | |
args = [plugin, channel, nick, msg].map { |arg| arg.shellescape } | |
IO.popen(args.join(' ')) do |plugin| | |
plugin.each_line do |line| | |
target = channel[0] == '#' ? channel : nick | |
subprocess.write(":m #{target} #{line}") | |
subprocess.flush | |
end | |
end | |
end | |
def loop_input(subprocess) | |
subprocess.each_line do |line| | |
begin | |
line_match = /(\S+).+<(.+?)> (.+)/.match(line) | |
rescue ArgumentError | |
next | |
end | |
if line_match | |
channel, nick, msg = line_match[1, 3] | |
cmd, args = msg.split(' ', 2) | |
args = '' if not args | |
/^\W(.+)/.match(cmd) do |cmd_match| | |
files = Dir.glob(cmd_match[1]).select do |file| | |
File.executable? file and not File.directory? file | |
end | |
files.each do |plugin| | |
Thread.new do | |
run_plugin(subprocess, './' + plugin, channel, nick, args) | |
end | |
end | |
end | |
end | |
end | |
end | |
if fork | |
exit! | |
end | |
IO.popen("sic #{OPTIONS.join(' ')}", 'w+') do |subprocess| | |
join_channels(subprocess) | |
loop_input(subprocess) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment