Skip to content

Instantly share code, notes, and snippets.

@ACUVE
Created July 25, 2011 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ACUVE/1104195 to your computer and use it in GitHub Desktop.
Save ACUVE/1104195 to your computer and use it in GitHub Desktop.
nowserver
# encoding: UTF-8
load 'smtpserver.rb'
require 'tmail'
require 'kconv'
require 'net/http'
require 'socket'
require 'oauth'
require 'twitter'
SETTING = {
CONSUMER_KEY: 'Your CONSUMER_KEY',
CONSUMER_SECRET: 'Your CONSUMER_SECRET',
ACCESS_TOKEN: 'Your ACCESS_TOKEN',
ACCESS_SECRET: 'Your ACCESS_SECRET',
EMAIL_ADDRESS: [
'Your EMAIL_ADDRESS'
],
DDO_PASSWORD: 'Your DDO_PASSWORD',
TIMEOUT_TIME: 10,
TIMEOUT_WAIT_TIME: 0,
INTERVAL_TIME: 60 * 60
}
class << SETTING[:EMAIL_ADDRESS]
def any
self.each do |v|
if yield v
return true
end
end
return false
end
end
ipthread = Thread.new do
TIMEOUT_TIME = SETTING[:TIMEOUT_TIME]
TIMEOUT_WAIT_TIME = SETTING[:TIMEOUT_WAIT_TIME]
INTERVAL_TIME = SETTING[:INTERVAL_TIME]
while true
thread = Thread.new do
ip = nil
begin
Net::HTTP.start('jk01.jamas.gr.jp'){|http|
ip = http.get('/ipdisp.pl').body[/(?:1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9]?[0-9])\.(?:1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9]?[0-9])\.(?:1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9]?[0-9])\.(?:1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9]?[0-9])/]
}
if ip
puts ip
Net::HTTP.start('free.ddo.jp'){|http|
http.get("/dnsupdate.php?dn=Your DomainName&ip=#{ip}&pw=#{SETTING[:DDO_PASSWORD]}")
}
end
rescue TimeoutError
sleep TIMEOUT_TIME * 2
end
end
sleep TIMEOUT_TIME
if thread.alive?
puts 'TIMEOUT'
thread.kill
sleep TIMEOUT_WAIT_TIME
else
puts 'OK'
sleep INTERVAL_TIME - TIMEOUT_TIME
end
end
end
server = SMTPServer.new({
Port: 25,
ServerName: 'localhost',
DataHook: lambda do |body, sender, recipients|
mail = TMail::Mail.parse(body)
if SETTING[:EMAIL_ADDRESS].any{|v| mail.from.include?(v)}
if match = mail.to[0].match(/^(\d+)@/)
key = match[1].to_i
Net::HTTP.post_form(
URI.parse("http://jbbs.livedoor.jp/bbs/write.cgi/computer/38153/#{key}/"),
{
DIR: 'computer',
BBS: '38153',
KEY: key,
TIME: Time.now.to_i.to_s,
NAME: '',
MAIL: '',
MESSAGE: mail.body{}.rstrip.toeuc
}
)
end
Twitter.configure do |config|
config.consumer_key = SETTING[:CONSUMER_KEY]
config.consumer_secret = SETTING[:CONSUMER_SECRET]
config.oauth_token = SETTING[:ACCESS_TOKEN]
config.oauth_token_secret = SETTING[:ACCESS_SECRET]
end
Twitter.update(mail.body{}.strip.toutf8);
File.open('log_law.txt', 'a') do |file|
file.puts body
file.puts '----------------------------------------------------------------------'
end
File.open('log.txt', 'a') do |file|
file.puts ('Time: ' + Time.now.to_s).toutf8
file.puts ('From: ' + mail.from_addrs.join(', ')).toutf8
file.puts ('To: ' + mail.to_addrs.join(', ')).toutf8
file.puts ('Body:').toutf8
file.puts mail.body{}.rstrip.toutf8
file.puts ('----------------------------------------------------------------------').toutf8
end
end
end,
})
[:INT, :TERM].each do |signal|
Signal.trap(signal) do
server.shutdown
ipthread.terminate
end
end
server.start
#http://rubyist.g.hatena.ne.jp/muscovyduck/20070707/p1より
require 'webrick'
require 'tempfile'
module GetsSafe
def gets_safe(rs = nil, timeout = @timeout, maxlength = @maxlength)
rs = $/ unless rs
f = self.kind_of?(IO) ? self : STDIN
@gets_safe_buf = '' unless @gets_safe_buf
until @gets_safe_buf.include? rs do
if maxlength and @gets_safe_buf.length > maxlength then
raise Errno::E2BIG, 'too long'
end
if IO.select([f], nil, nil, timeout) == nil then
raise Errno::ETIMEDOUT, 'timeout exceeded'
end
begin
@gets_safe_buf << f.sysread(4096)
rescue EOFError, Errno::ECONNRESET
return @gets_safe_buf.empty? ? nil : @gets_safe_buf.slice!(0..-1)
end
end
p = @gets_safe_buf.index rs
if maxlength and p > maxlength then
raise Errno::E2BIG, 'too long'
end
return @gets_safe_buf.slice!(0, p+rs.length)
end
attr_accessor :timeout, :maxlength
end
class SMTPD
class Error < StandardError; end
def initialize(sock, domain)
@sock = sock
@domain = domain
@error_interval = 5
class << @sock
include GetsSafe
end
@helo_hook = nil
@mail_hook = nil
@rcpt_hook = nil
@data_hook = nil
@data_each_line = nil
@rset_hook = nil
@noop_hook = nil
@quit_hook = nil
end
attr_writer :helo_hook, :mail_hook, :rcpt_hook, :data_hook,
:data_each_line, :rset_hook, :noop_hook, :quit_hook
def start
@helo_name = nil
@sender = nil
@recipients = []
catch(:close) do
puts_safe "220 #{@domain} service ready"
while comm = @sock.gets_safe do
catch :next_comm do
comm.sub!(/\r?\n/, '')
comm, arg = comm.split(/\s+/,2)
break if comm == nil
case comm.upcase
when 'EHLO' then comm_helo arg
when 'HELO' then comm_helo arg
when 'MAIL' then comm_mail arg
when 'RCPT' then comm_rcpt arg
when 'DATA' then comm_data arg
when 'RSET' then comm_rset arg
when 'NOOP' then comm_noop arg
when 'QUIT' then comm_quit arg
else
error '502 Error: command not implemented'
end
end
end
end
end
def line_length_limit=(n)
@sock.maxlength = n
end
def input_timeout=(n)
@sock.timeout = n
end
attr_reader :line_length_limit, :input_timeout
attr_accessor :error_interval
attr_accessor :use_file, :max_size
private
def comm_helo(arg)
if arg == nil or arg.split.size != 1 then
error '501 Syntax: HELO hostname'
end
@helo_hook.call(arg) if @helo_hook
@helo_name = arg
reply "250 #{@domain}"
end
def comm_mail(arg)
if @sender != nil then
error '503 Error: nested MAIL command'
end
if arg !~ /^FROM:/i then
error '501 Syntax: MAIL FROM: <address>'
end
sender = parse_addr $'
if sender == nil then
error '501 Syntax: MAIL FROM: <address>'
end
@mail_hook.call(sender) if @mail_hook
@sender = sender
reply '250 Ok'
end
def comm_rcpt(arg)
if @sender == nil then
error '503 Error: need MAIL command'
end
if arg !~ /^TO:/i then
error '501 Syntax: RCPT TO: <address>'
end
rcpt = parse_addr $'
if rcpt == nil then
error '501 Syntax: RCPT TO: <address>'
end
@rcpt_hook.call(rcpt) if @rcpt_hook
@recipients << rcpt
reply '250 Ok'
end
def comm_data(arg)
if @recipients.size == 0 then
error '503 Error: need RCPT command'
end
if arg != nil then
error '501 Syntax: DATA'
end
reply '354 End data with <CR><LF>.<CR><LF>'
if @data_hook
tmpf = @use_file ? Tempfile.new('smtpd') : ''
end
size = 0
loop do
l = @sock.gets_safe
if l == nil then
raise SMTPD::Error, 'unexpected EOF'
end
if l.chomp == '.' then break end
if l[0] == ?. then
l[0,1] = ''
end
size += l.size
if @max_size and @max_size < size then
error '552 Error: message too large'
end
@data_each_line.call(l) if @data_each_line
tmpf << l if @data_hook
end
if @data_hook then
if @use_file then
tmpf.pos = 0
@data_hook.call(tmpf, @sender, @recipients)
tmpf.close(true)
else
@data_hook.call(tmpf, @sender, @recipients)
end
end
reply '250 Ok'
@sender = nil
@recipients = []
end
def comm_rset(arg)
if arg != nil then
error '501 Syntax: RSET'
end
@rset_hook.call(@sender, @recipients) if @rset_hook
reply '250 Ok'
@sender = nil
@recipients = []
end
def comm_noop(arg)
if arg != nil then
error '501 Syntax: NOOP'
end
@noop_hook.call(@sender, @recipients) if @noop_hook
reply '250 Ok'
end
def comm_quit(arg)
if arg != nil then
error '501 Syntax: QUIT'
end
@quit_hook.call(@sender, @recipients) if @quit_hook
reply '221 Bye'
throw :close
end
def parse_addr(str)
str = str.strip
if str == '' then
return nil
end
if str =~ /^<(.*)>$/ then
return $1.gsub(/\s+/, '')
end
if str =~ /\s/ then
return nil
end
str
end
def reply(msg)
puts_safe msg
end
def error(msg)
sleep @error_interval if @error_interval
puts_safe msg
throw :next_comm
end
def puts_safe(str)
begin
@sock.puts str + "\r\n"
rescue
raise SMTPD::Error, "cannot send to client: '#{str.gsub(/\s+/," ")}': #{$!.to_s}"
end
end
end
SMTPDError = SMTPD::Error
class SMTPServer < WEBrick::GenericServer
def run(sock)
server = SMTPD.new(sock, @config[:ServerName])
server.input_timeout = @config[:RequestTimeout]
server.line_length_limit = @config[:LineLengthLimit]
server.helo_hook = @config[:HeloHook]
server.mail_hook = @config[:MailHook]
server.rcpt_hook = @config[:RcptHook]
server.data_hook = @config[:DataHook]
server.data_each_line = @config[:DataEachLine]
server.rset_hook = @config[:RsetHook]
server.noop_hook = @config[:NoopHook]
server.quit_hook = @config[:QuitHook]
server.start
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment