Skip to content

Instantly share code, notes, and snippets.

@rsayers
Created July 7, 2009 16:54
Show Gist options
  • Save rsayers/142211 to your computer and use it in GitHub Desktop.
Save rsayers/142211 to your computer and use it in GitHub Desktop.
#!/usr/local/bin/ruby
require 'socket'
class File
def self.binary?(name)
myStat = stat(name)
return false unless myStat.file?
open(name) { |file|
blk = file.read(myStat.blksize)
return blk.size == 0 ||
blk.count("^ -~", "^\r\n") / blk.size > 0.3 ||
blk.count("\x00") > 0
}
end
end
class GopherServer
def initialize(config='/etc/gopherd.conf')
tmp={}
File.open(config).readlines.each do |l|
k,v = l.chomp.split('=') if l !~ /^#|^\n/
tmp[k.strip]=v.strip if k&&v
end
@port = (tmp['port'] || 70).to_i
@dir = tmp['gopherdocs']
@host = tmp['hostname'] || `hostname`
@routes=[]
@client_addr=''
@logfile=tmp['logfile']
end
def log(msg)
File.open(@logfile,"a").sprintf("%s - - [%s] \"%s\"",@client_addr,time,msg)
end
def defroute(key, function)
@routes << {key=>function}
end
def handle_request(url)
url,param = url.split('?')
path = @dir + ( url || "" )
@routes.each do |r|
k=r.keys.first
if k.class==String && k==url then
return r[k].call(param)
elsif k.class == Regexp && url=~k then
return r[k].call(param,url.match(k))
end
end
if url =~ /^URL\:/ then
return weburl(url.sub('URL:',''))
end
notfound(url) if !File.exist?(path)
result = case gettype(path)
when "1" then readdir(url)
else display(path,param)
end
result
end
def display(path,param='')
if File.executable?(path) then
%x{ #{path} #{param} }
else
File.open(path).read
end
end
def weburl(url)
"<html><body>Leaving gopherspace, we will miss you :(<br><a href='#{url}'>Click here to visit the site</a>"
end
def readdir(path)
dir = "#{@dir}/#{path}"
lines=[]
if File.exist?(dir+'/gophermap') then
File.open(dir+'/gophermap').readlines.map { |line|
line.chop!
iteminfo = line.split(/\t/)
if iteminfo.length < 2 then
lines << "i#{line}\t\terror.host\t1"
else
#iteminfo[1] = "/#{path}/"+iteminfo[1] if iteminfo[1][0] != "/" || iteminfo[1] !~ /^URL/
iteminfo[2] = @host if !iteminfo[2]
iteminfo[3] = @port if !iteminfo[3]
lines << iteminfo.join("\t")
end
}
else
lines = []
Dir.entries(dir).each do |item|
lines << "#{gettype(@dir+'/'+item)}#{item}\t/#{item}\t#{@host}\t70" if !['.','..'].include?(item)
end
end
lines.join("\r\n")
end
def notfound(url)
"3 '#{url}' doesn't exist!\terror.host1\yi This resource cannot be located.error.host1\n."
end
def gettype(file)
#if anyone sees cameron, don't tell him I stole his code
File.directory?(file) ? "1" :
file =~ /\.txt$/i ? "0" :
file =~ /\.gif$/i ? "g" :
file =~ /\.gz$/i ? "9" :
file =~ /\.zip$/i ? "5" :
file =~ /\.jpe?g$/i ? "I" :
file =~ /\.png$/i ? "p" :
file =~ /\.pdf$/i ? "d" :
file =~ /\.css$/i ? "c" :
file =~ /\.xml$/i ? "x" :
file =~ /\.html?$/i ? "h" :
file =~ /\.hqx$/i ? "4" :
File.binary?(file) ? "9" :
"0";
end
def socket_listen
server = TCPServer.new('localhost', @port)
while (session = server.accept)
@client_addr = session.getpeeraddr.last
session.puts handle_request(session.readline.chop)
session.close
end
end
def stdin_listen
@client_addr = ENV['REMOTE_HOST']
print handle_request(STDIN.readline.chop)
end
end
s=GopherServer.new
s.stdin_listen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment