=begin
tdcommon.rb - tDiary tool's common library.
Copyright (C) 2004 by Hahahaha.
<rin_ne@big.or.jp>
http://www20.big.or.jp/~rin_ne/
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=end
TDCOMMON_VERSION = '0.1.0'
Banner = "#{ProgramName} Version #{Version}\nCopyright (c) 2004 by Hahahaha.\n"
DefaultAgent = "#{ProgramName.tr(' ', '')}/#{Version}"
DATE_FORMAT = Regexp.new('(\d{4})-(\d\d)-(\d\d)')
CONF_FORMAT = Regexp.new('(.*?):(.*)$')
module MessagePrint
@@debug = false
@@verbose = true
## Debug flag on.
def debug_on
@@debug = true
end
def debug
return @@debug
end
## Message off.
def silent_mode
@@verbose = false
end
def silent
return (not @@verbose)
end
## Debug print.
def print_debug(str)
$stdout.puts("DEBUG: #{str}") if @@debug and @@verbose
end
## Error Exit.
def error_exit(str)
$stderr.puts("Error: #{str}")
exit(1)
end
## Print message.
def print_message(str)
$stdout.puts(str) if @@verbose
end
end
# Configureuration store class.
#
class Configure
include MessagePrint
attr_accessor :user # tDiary admin user id
attr_accessor :password # tDiary admin password
attr_accessor :filter_command # Filter command.
attr_accessor :config_file # Configure file.
attr_accessor :touch_file # Touch file.
attr_accessor :target_files # Target files.
attr_accessor :target_file # Target file.
attr_accessor :target_date # Target date.
attr_accessor :client_encoding # Client encoding.
attr_accessor :server_encoding # Server encoding.
attr_accessor :agent # Agent name.
attr_accessor :timeout # Timeout.
attr :txt_dir # Directory for "YYYY-MM-DD.txt".
attr :proxy # Proxy location.
attr :location # Your tDiary update CGI URL.
attr :delay # Delay localtime.
attr_accessor :force_update # Force update flag.
attr_accessor :mode # Action mode.
attr_accessor :use_stdout # Output data to STDOUT.
def initialize
@user = nil
@password = nil
@config_file = 'config.txt'
@touch_file = 'touch.txt'
@target_files = []
@target_file = nil
@target_date = nil
@client_encoding = 'EUC-JP'
@server_encoding = 'EUC-JP'
@agent = "#{ProgramName.tr(' ', '')}/#{Version}"
@timeout = 180
@txt_dir = '.'
@proxy = nil
@location = nil
@filter_command = nil
@delay = 0
@force_update = false
@mode = 'replace'
@use_stdout = false
end
# Load configuration file.
#
def load
print_debug("Loading config file (#{@config_file}).")
begin
File.open(@config_file) {|f|
f.each {|line|
next if /^#/.match(line)
m = CONF_FORMAT.match(line)
next unless m[1].strip
opt = m[1].strip.downcase
val = m[2].strip
val = nil if val.empty?
case opt
when "id"
@user = val unless @user
print_debug("Configure#load: id:#{@user}")
when "password"
@password = val unless @password
print_debug("Configure#load: password:#{@password}")
when "client_encoding"
@client_encoding = val
print_debug("Configure#load: client_encoding:#{@client_encoding}")
when "server_encoding"
@server_encoding = val
print_debug("Configure#load: server_encoding:#{@server_encoding}")
when "filter"
@filter_command = val
print_debug("Configure#load: filter:#{@filter_command}")
when "touch"
@touch_file = val
print_debug("Configure#load: touch:#{@touch}")
when "cgi_url"
@location = URI.parse(val).normalize
if ((not @location.host) or (not @location.port))
raise("cgi_url: Invalid URI: '#{val}'")
end
print_debug("Configure#load: cgi_url:#{val}")
when "proxy"
@proxy = URI.parse(val).normalize
if ((not @proxy.host) or (not @proxy.port))
raise("proxy: Invalid URI: '#{val}'")
end
print_debug("Configure#load: proxy:#{val}")
when "txt_dir"
unless File.directory?(val)
raise("txt_dir: No such directory: '#{val}'")
end
@txt_dir = val
print_debug("Configure#load: txt_dir:#{@txt_dir}")
when "delay"
@delay = val.to_i * 3600
print_debug("Configure#load: delay:#{val}")
else
raise("#{opt}: No such option.")
end
}
}
@proxy = URI.parse('') unless @proxy
raise 'cgi_url not found' unless @location
rescue
error_exit("[Configure#load] #$! in '#{@config_file}'.")
end
end
end
# tDiary Access class.
#
class TDiaryServer
include MessagePrint
attr :response
def initialize(config)
raise(ArgumentError, config.to_s) if config.class != Configure
@request = nil
@http = nil
@response = nil
@conf = config
create_http
end
# Open server.
#
def open(method = 'get')
return if @request
case method.strip.downcase
when 'get'
@request = Net::HTTP::Get.new(@conf.location.path)
when 'post'
@request = Net::HTTP::Post.new(@conf.location.path)
when 'head'
@request = Net::HTTP::Head.new(@conf.location.path)
when 'put'
@request = Net::HTTP::Put.new(@conf.location.path)
end
@request['User-Agent'] = @conf.agent
user = @conf.user
pass = @conf.password
unless (user)
print "Username: "
user = $stdin.gets.chomp
end
unless (pass)
print "Password: "
pass = $stdin.gets.chomp
end
@request.basic_auth(user, pass)
end
# Close server.
#
def close
@request = nil
end
# Send request.
#
def request(body = nil)
open unless @request
if (body.class == Hash)
body_ary = []
body.each_pair {|name, val|
body_ary.push( [name, val].join('=') )
}
body = body_ary.join(';')
end
@request['Content-Type'] = 'application/x-www-form-urlencoded'
2.times {|i|
begin
@http.start {|http|
@response = http.request(@request, body)
}
rescue
if (@response)
case @response.code
when 401
error_exit('[TDiaryServer#request]: Check username/password.')
when 407
error_exit('[TDiaryServer#request]: Check username/password.')
else
print_debug('[TDiaryServer#request]: RETRY.')
print_message('Retry.')
next
end
end
raise('[TDiaryServer#request]: Network error. Check cgi_url, proxy, timeout and so on.')
end
break
}
if (@response.code.to_i != 200)
error_exit("[TDiaryServer#request]: ErrorCode = #{@response.code}.")
end
end
# Send diary entry.
#
def send_entry( title, body )
open unless @request
year, month, day = DATE_FORMAT.match(@conf.target_date).captures
self.request({
@conf.mode => @conf.mode,
'old' => year + month + day,
'year' => year.to_i.to_s,
'month' => month.to_i.to_s,
'day' => day.to_i.to_s,
'title' => URI.escape(title, /./),
'body' => URI.escape(body, /./)
})
end
# Receive diary entry.
#
def receive_entry
open unless @request
year, month, day = DATE_FORMAT.match(@conf.target_date).captures
self.request({
@conf.mode => @conf.mode,
'year' => year.to_i.to_s,
'month' => month.to_i.to_s,
'day' => day.to_i.to_s,
})
end
# Create HTTP instance.
#
def create_http
p_user, p_pass = @conf.proxy.userinfo.split(':') if @conf.proxy.userinfo
print_debug("use proxy: #{@conf.proxy.normalize}") if @conf.proxy.host
@http = Net::HTTP.new(@conf.location.host, @conf.location.port,
@conf.proxy.host, @conf.proxy.port,
p_user, p_pass)
@http.read_timeout = @conf.timeout
end
private :create_http
end