Created
July 25, 2011 14:05
-
-
Save ACUVE/1104195 to your computer and use it in GitHub Desktop.
nowserver
This file contains 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
# 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 |
This file contains 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
#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