#!/usr/bin/ruby

$LOAD_PATH.push '/usr/local/etc'

class String
  def urlencode
    unpack('H*').first.upcase.gsub(/(..)/, "%\\1")
  end
end

class Time
  def rfc1123
    utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
  end
  def jst
    (utc + 32400).strftime('%Y-%m-%d %H:%M:%S')
  end
  def mysql
    utc.strftime('%Y-%m-%d %H:%M:%S')
  end
  def to_atom
    fmt = ('%%Y-%%m-%%dT%%H:%%M:%%S.%06uZ' % usec)
    utc.strftime(fmt)
  end
  MONTAB = {
    :jan => 1,	:feb => 2,	:mar => 3,	:apr => 4,
    :may => 5,	:jun => 6,	:jul => 7,	:aug => 8,
    :sep => 9,	:oct => 10,	:nov => 11,	:dec => 12
  }
  def Time.parse str
    begin
      case str
      when Mysql::Time then
        # considered UTC
	ymdhms = [:year, :month, :day, :hour, :minute, :second].map{|sym|
	  str.send(sym)
	}
	STDERR.puts ymdhms.inspect if $DEBUG
	if ymdhms.first.zero?
	  then nil
	  else Time.gm(*ymdhms)
	  end
      when /(\d+)\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+GMT/ then
	d, m, y, h, n, s = $1, $2, $3, $4, $5, $6
	d, y, h, n, s = [d, y, h, n, s].map{|s| s.to_i}
	m = MONTAB[m.downcase.to_sym].to_i
	Time.gm(y, m, d, h, n, s)
      when /(\d+)-(\d+)-(\d+)[T ](\d+):(\d+):(\d+(?:\.\d+)?)Z/ then
	y, m, d, h, n = [$1, $2, $3, $4, $5].map{|s| s.to_i}
	s = $6.to_f
	Time.gm(y, m, d, h, n, s)
      when /(\d+)-(\d+)-(\d+)[T ](\d+):(\d+):(\d+(?:\.\d+)?)([-+]\d\d):?(\d\d)/ then
	y, m, d, h, n, zh, zn = [$1, $2, $3, $4, $5, $7, $8].map{|s| s.to_i}
	STDERR.puts [y, m, d, h, n, s, zh, zn].inspect if $DEBUG
	s = $6.to_f
	Time.gm(y, m, d, h, n, s) - (zh * 60 + zn) * 60
      else raise "unknown datetime format '#{str}'"
      end
    rescue => e
      STDERR.puts "\t" + e.backtrace.join("\n\t")
      Time.now
    end
  end
end

module PSHBSpool

class HtmlFeed

  def initialize url, css, title = 'title'
    require 'rexml/document'
    require 'digest/md5'
    @url, @css, @title = url, css, title
    @n = 0
    @updated = Time.at(0)
    # to be completed by compile()
    @doc = @root = @ul = nil
    @cols = %w< updated title >
  end

  def add_col *name
    name.each{|n| @cols.push(n.to_s) }
  end

  def ins_link
    @cols.unshift('link')
  end

  COLN = {
    'updated' => '発表時刻', #MAX(utime)
    'title' => '表題',
    'author' => '発表官署名', #pbof
    'summary' => '見出し',
    'Xstatus' => '運用種別',
    'Xedof' => '編集官署名',
    'Xitype' => '情報形態',
    'Xevid' => '識別情報',
    'Xexpire' => '有効期限',
    'Xrtime' => '公式発表時刻',
    'abr' => 'データ種類コード',
  }

  require 'pshbspool-cfg'
  PRMS = PSHBSpool::PRMS

  def compile
    return if @doc
    ths = @cols.map{|name| "<th>#{COLN[name] or name}</th>"}.join
    template = <<ENDXML
<html>
<head>
<title>#{@title}</title>
<link rel="self" href="#{@url}"/>
<link rel="stylesheet" type="text/css" href="#{@css}" />
</head>
<body>
<header>
<h1>#{@title}</h1>
</header>
<div><ul id="Notes">
<li>Date: <span id="Date">#{Time.now.jst}</span></li>
<li>Last-Modified: <span id="Updated">#{@updated.to_atom}</span></li>
</ul></div>
<div>
<table border="1" id="MainList">
<tbody>
<tr>
 #{ths}
</tr>
</tbody>
</table>
</div>
<footer>
<p>Data source: <a href="https://www.data.jma.go.jp/developer/">JMA</a>;
  DB operated by
  <a href="https://twitter.com/#{PRMS[:admintw]}">@#{PRMS[:admintw]}</a></p>
</footer>
</body>
</html>
ENDXML
    @doc = REXML::Document.new(template)
    @root = @doc.root
    @ul = REXML::XPath.first(@root, '//table[@id="MainList"]/tbody')
  end

  def add_note url, text
    compile
    ul = REXML::XPath.first(@root, '//ul[@id="Notes"]')
    ul.add_element('li').add_element('a', 'href'=>url.to_s).add_text(text.to_s)
  end

  def to_s
    compile
    REXML::XPath.first(@root, '//span[@id="Updated"]').text = @updated.jst
    head = <<EOF
Last-Modified: #{@updated.rfc1123}\r
Content-Type: text/html; charset=utf8\r
\r
EOF
    head + @doc.to_s
  end

  def add_ent updated, attrs
    compile
    @n += 1
    ent = @ul.add_element('tr', 'data-ir'=>@n.to_s)
    ent.add_attribute('data-ip', attrs['#postid'].to_s) if attrs['#postid']
    @updated = [@updated, updated].compact.max
    attrs['updated'] = updated.jst
    for col in @cols
      if 'link' == col then
        td = ent.add_element('td', 'title'=>col)
        for mcol in attrs.keys.grep(/^=/).sort
	  kw = mcol[1..-1]
	  td.add_element('a', 'class'=>kw, 'href'=>attrs[mcol].to_s).add_text(kw)
	end
        next
      end
      collink = '@' + col
      if attrs[collink] then
        ent.add_element('td', 'title'=>col) \
	.add_element('a', 'href'=>attrs[collink].to_s) \
	.add_text(attrs[col].to_s)
      else
        ent.add_element('td', 'title'=>col).add_text(attrs[col].to_s)
      end
    end
    @ul.add_text("\n")
    if attrs['summary'] then
      ent = @ul.add_element('tr', 'data-ir'=>@n.to_s)
      ent.add_element('td', 'title'=>"summary", 'colspan'=>@cols.size.to_s,
      'class'=>'summary').add_text(attrs['summary'].to_s)
      @ul.add_text("\n")
    end
  end

  def nrows
    compile
    @n + 0
  end

  def banner text, alturl = nil
    compile
    ent = @ul.add_element('tr')
    td = ent.add_element('td', 'colspan'=>@cols.size)
    td.add_text(text)
    if alturl
      f = td.add_element('form', 'style'=>'display:inline;',
        'action'=>alturl, 'method'=>'GET', 'id'=>"f#{@n}")
      f.add_element('input', 'type'=>'submit', 'value'=>"More")
    end
    true
  end

end

class App

  def initialize
    @method = ENV['REQUEST_METHOD'].to_s
    @qstr = ENV['QUERY_STRING'].to_s
    @path = ENV['PATH_INFO'].to_s
    @addr = ENV['REMOTE_ADDR'].to_s
    @ctype = ENV['CONTENT_TYPE'].to_s
    @clen = ENV['CONTENT_LENGTH']
    @clen = @clen.to_i if @clen
    @reqbody = nil
    @myname = nil
  end

  def database
    $stderr.puts STORAGE.inspect if $DEBUG
    db = Mysql.connect(STORAGE[:srv], STORAGE[:usr],
      STORAGE[:pwd], STORAGE[:db])
    begin
      yield db
    ensure
      db.close
    end
  end

  def prepare(db, sql)
    st = db.prepare(sql)
    begin
      yield st
    ensure
      st.close
    end
  end

  def myname
    return @myname if @myname
    host = ENV['SERVER_NAME'] || 'localhost'
    port = ENV['SERVER_PORT'] || '80'
    script = ENV['SCRIPT_NAME']
    @myname = "http://#{host}:#{port}#{script}"
    if PRMS[:urlhook]
      PRMS[:urlhook].call(@myname)
    end
    @myname
  end

  JMXNS = {
    'jmx' => 'http://xml.kishou.go.jp/jmaxml1/',
    'ib' => 'http://xml.kishou.go.jp/jmaxml1/informationBasis1/'
  }

  XPATHS = {
    :title => '/jmx:Report/jmx:Control/jmx:Title',
    :status => '/jmx:Report/jmx:Control/jmx:Status',
    :edof => '/jmx:Report/jmx:Control/jmx:EditorialOffice',
    :evid => '/jmx:Report/ib:Head/ib:EventID',
    :utime => '/jmx:Report/jmx:Control/jmx:DateTime',
    :expire => '/jmx:Report/ib:Head/ib:ValidDateTime',
    :pbof => '/jmx:Report/jmx:Control/jmx:PublishingOffice',
    :rtime => '/jmx:Report/ib:Head/ib:ReportDateTime',
    :ikind => '/jmx:Report/ib:Head/ib:InfoKind',
    :hdline => '/jmx:Report/ib:Head/ib:Headline/ib:Text',
    :itype => '/jmx:Report/ib:Head/ib:InfoType',
  }

  def updatedb
    require 'rexml/document'
    n = 0
    database {|db|
      rows = []
      # phase 1
      sql = <<-ENDSQL
      SELECT postid, uri, body
      FROM msgs
      WHERE postid > (SELECT IFNULL(MAX(postid), 0) FROM jmxmsgs)
      ORDER BY postid ASC
      LIMIT 40
      ENDSQL
      prepare(db, sql) {|st|
	st.execute
	while row = st.fetch
	  next unless /^urn:uuid/ === row[1]
	  rows.push row
	end
      }
      # phase 2
      db.autocommit(false)
      sql = <<-ENDSQL
      REPLACE INTO jmxmsgs(postid, uri, ins,
        title, status, edof, evid, utime, expire, 
	pbof, rtime, ikind, hdline, itype)
      VALUES (?, ?, NOW(),
        ?, ?, ?, ?, ?, ?,
	?, ?, ?, ?, ?)
      ENDSQL
      prepare(db, sql) {|st|
	for row in rows
	  postid, uri, body = row
	  next if body.empty?
	  h = {}
	  begin
	    d = REXML::Document.new(body)
	  rescue REXML::ParseException => e
	    next
	  end
	  for k, x in XPATHS
	    v = REXML::XPath.first(d.root, x + '/text()', JMXNS)
	    h[k] = v.to_s
	  end
	  utime = Time.parse(h[:utime]).mysql
	  expire = if h[:expire].empty?
	    then '0000-00-00T00:00:00' 
	    else Time.parse(h[:expire]).mysql
	    end
	  rtime = Time.parse(h[:rtime]).mysql
	  #STDERR.puts h.inspect
	  xrow = [postid, uri, 
	    h[:title], h[:status], h[:edof], h[:evid], utime, expire,
	    h[:pbof], rtime, h[:ikind], h[:hdline], h[:itype]
	  ]
	  st.execute(*xrow)
	  n = n.succ
	end
      }
      db.commit
    }
    <<EOF
Content-Type: text/plain\r
X-Processed-Rows: #{n}\r
\r
EOF
  end

  def check_ims span = 60
    now = (tnow = Time.now).rfc1123
    if hims = ENV['HTTP_IF_MODIFIED_SINCE'] then
      STDERR.puts "HIMS #{hims.inspect}" if $DEBUG
      t = Time.parse(hims) + span
      STDERR.puts "CMP t=#{t} tnow=#{tnow}" if $DEBUG
      raise Errno::EAGAIN, "#{myname}#{@path}" if t > tnow
      STDERR.puts "CMP PASSTHRU" if $DEBUG
    end
  end

  def mlatest
    check_ims
    uri_this = File.join(myname, @path)
    title_feed = "新着電文"
    a = HtmlFeed.new(uri_this, './res/tab.css', title_feed)
    a.add_col(*%w( author Xstatus Xedof Xevid Xrtime ))
    a.ins_link
    database {|db|
      sql = <<-ENDSQL
        SELECT uri, title, status, evid, utime, pbof, rtime, edof, hdline, postid
	FROM jmxmsgs
	ORDER BY postid DESC
	LIMIT 50
      ENDSQL
      prepare(db, sql) {|st|
        st.execute
	while row = st.fetch
	  uri, title, status, evid, utime, pbof, rtime, edof, hdline, postid = row
	  linkto = File.join(myname, "/msg/#{uri}")
	  raw = File.join(File.dirname(myname), 'pshbspool', 'entry', uri)
	  hdline = nil if hdline.empty?
	  a.add_ent(Time.parse(utime), '=JMX'=>raw,
	    'title'=>title, '=HTML'=>linkto, 'author'=>pbof, 'summary'=>hdline,
	    'Xstatus'=>status, 'Xedof'=>edof, 'Xevid'=>evid,
	    'Xrtime'=> begin Time.parse(rtime).jst rescue '-' end,
	    '#postid'=>postid.to_s)
	end
      }
    }
    uri = File.join(myname, '/titles.html')
    a.add_note(uri, '情報名称 新着順一覧')
    a.to_s
  end

  def cutoff_time nposts
    utime = nil
    sql = <<-ENDSQL
      SELECT MAX(utime)
      FROM jmxmsgs
      WHERE postid <= (SELECT MAX(postid) - ? FROM jmxmsgs)
    ENDSQL
    database {|db|
      prepare(db, sql) {|st|
        st.execute(nposts)
        utime, dummy = st.fetch
      }
    }
    if utime then Time.parse(utime).jst else '-' end
  end

  def mlatest_bytitle(title, speedhack = false)
    check_ims
    uri_this = File.join(myname, @path)
    title_feed = "新着電文 (情報名称=#{title})"
    a = HtmlFeed.new(uri_this, '../res/tab.css', title_feed)
    a.add_col(*%w( author Xstatus Xedof Xevid Xrtime ))
    a.ins_link
    database {|db|
      sql = <<-ENDSQL
        SELECT uri, status, evid, utime, pbof, edof, rtime, hdline, jmxmsgs.title
	FROM jmxmsgs
	  -- abrhack
	WHERE
	  -- speedhack
	  title = ?
	ORDER BY utime DESC
	LIMIT 21
      ENDSQL
      if /^V/ === title then
	sql.sub!(/-- abrhack/,
	'LEFT JOIN jmxxsl ON jmxmsgs.title = jmxxsl.title')
        sql.sub!(/title = \?/, 'abr = ?')
      end
      if speedhack then
	sql.sub!(/-- speedhack/,
	  "postid > (SELECT MAX(postid) - 5000 FROM jmxmsgs) AND")
      end
      $stderr.puts sql if $DEBUG
      prepare(db, sql) {|st|
        st.execute(title)
	while row = st.fetch
	  uri, status, evid, utime, pbof, edof, rtime, hdline, xtitle = row
	  linkto = File.join(myname, "/msg/#{uri}")
	  raw = File.join(File.dirname(myname), 'pshbspool', 'entry', uri)
	  hdline = nil if hdline.empty?
	  a.add_ent(Time.parse(utime), '=JMX'=>raw,
	    'title'=>xtitle, '=HTML'=>linkto, 'author'=>pbof, 'summary'=>hdline,
	    'Xstatus'=>status, 'Xedof'=>edof, 'Xevid'=>evid,
	    'Xrtime'=> begin Time.parse(rtime).jst rescue '-' end )
	end
      }
    }
    uri = File.join(myname, '/titles.html')
    uri_t = File.join(myname, "/t1/#{title.urlencode}")
    a.add_note(uri, '情報名称 新着順一覧')
    a.add_note(uri_t, "編集官署 新着順一覧 (情報名称=#{title})")
    if a.nrows.zero? then
      if speedhack then
        url_a = File.join(myname, "/m6/#{title.urlencode}")
	ct = cutoff_time(5000) 
	a.banner "検索範囲 #{ct} 以後にはみつかりません。", url_a
      else
	a.banner "みつかりません。"
      end
    end
    a.to_s
  end

  def mlatest_bytitle_edof(title, edof, speedhack = false)
    check_ims
    uri_this = File.join(myname, @path)
    title_feed = "新着電文 (情報名称=#{title} 編集官署=#{edof})"
    a = HtmlFeed.new(uri_this, '../../res/tab.css', title_feed)
    a.add_col(*%w( author Xstatus Xedof Xevid Xrtime ))
    a.ins_link
    database {|db|
      sql = <<-ENDSQL
        SELECT
	  uri, title, status, evid, utime, pbof, rtime, hdline, postid
	FROM jmxmsgs
	WHERE
	  -- speedhack
	  title = ? AND edof = ?
	ORDER BY utime DESC
	LIMIT 21
      ENDSQL
      if speedhack then
	sql.sub!(/-- speedhack/,
	  "postid > (SELECT MAX(postid) - 20000 FROM jmxmsgs) AND")
      end
      prepare(db, sql) {|st|
        st.execute(title, edof)
	while row = st.fetch
	  uri, title, status, evid, utime, pbof, rtime, hdline, postid = row
	  linkto = File.join(myname, "/msg/#{uri}")
	  raw = File.join(File.dirname(myname), 'pshbspool', 'entry', uri)
	  hdline = nil if hdline.empty?
	  a.add_ent(Time.parse(utime), '=JMX'=>raw,
	    'title'=>title, '=HTML'=>linkto, 'author'=>pbof, 'summary'=>hdline,
	    'Xstatus'=>status, 'Xedof'=>edof, 'Xevid'=>evid,
	    'Xrtime'=> begin Time.parse(rtime).jst rescue '-' end,
	    '#postid'=>postid.to_s)
	end
      }
    }
    uri = File.join(myname, '/titles.html')
    uri_t = File.join(myname, "/t1/#{title.urlencode}")
    a.add_note(uri, '情報名称 新着順一覧')
    a.add_note(uri_t, "編集官署 新着順一覧 (情報名称=#{title})")
    if a.nrows.zero? then
      if speedhack then
        url_a = File.join(myname, "/m7/#{title.urlencode}/#{edof.urlencode}")
	ct = cutoff_time(20_000) 
	a.banner "検索範囲 #{ct} 以後にはみつかりません。", url_a
      else
	a.banner "みつかりません。"
      end
    end
    a.to_s
  end

  def eolist_bytitle t
    check_ims
    uri_this = File.join(myname, @path)
    a = HtmlFeed.new(uri_this, '../res/tab.css', "編集官署 新着順一覧 (情報名称=#{t})")
    a.add_col 'author'
    url_t = File.join(myname, "/titles.html")
    url_m = File.join(myname, "/m1/#{t.urlencode}")
    database {|db|
      sql = <<-ENDSQL
        SELECT edof, MAX(utime) AS updated
	FROM jmxmsgs
	WHERE title = ?
	GROUP BY edof
	ORDER BY updated DESC
      ENDSQL
      prepare(db, sql) {|st|
        st.execute(t)
	while row = st.fetch
	  edof, updated = row
	  uri = File.join(myname, "/m2/#{t.urlencode}/#{edof.urlencode}")
	  a.add_ent(Time.parse(updated), 'title'=>t, '@title'=>url_m,
	    'author'=>edof, '@author'=>uri)
	end
      }
    }
    a.add_note(url_t, "情報名称 新着順一覧")
    a.add_note(url_m, "新着電文 (情報名称=#{t})")
    a.to_s
  end

  def tlist
    check_ims
    uri_this = File.join(myname, @path)
    a = HtmlFeed.new(uri_this, './res/tab.css', "情報名称 新着順一覧")
    a.add_col 'abr'
    upd = nil
    database {|db|
      sql = <<-ENDSQL
        SELECT jmxmsgs.title, MAX(utime) AS updated, abr
	FROM jmxmsgs
	  LEFT JOIN jmxxsl ON jmxmsgs.title = jmxxsl.title
	GROUP BY jmxmsgs.title
	ORDER BY updated DESC
      ENDSQL
      prepare(db, sql) {|st|
        st.execute
	while row = st.fetch
	  title, updated, abr = row
	  uri = File.join(myname, "/t1/#{title.urlencode}")
	  a.add_ent(Time.parse(updated), 'title'=>title, '@title'=>uri,
	  'abr'=>abr)
	end
      }
    }
    uri = File.join(myname, '/msgs.html')
    a.add_note(uri, '直近電文一覧')
    a.to_s
  end

  def showday yyyy, mm, dd
    check_ims
    day1 = "#{yyyy}-#{mm}-#{dd}"
    day2 = (Time.gm(yyyy.to_i, mm.to_i, dd.to_i) + 86400).strftime('%Y-%m-%d')
    body = []
    insmax = "1999-12-31 12:34:56"
    $stderr.puts "#showday ins > #{day1} AND ins < #{day2}" if $stderr.tty?
    database {|db|
      sql = <<-ENDSQL
        SELECT uri, ins
	FROM msgs
	WHERE ins > ? and ins < ?
      ENDSQL
      prepare(db, sql) {|st|
        st.execute(day1, day2)
	while row = st.fetch
	  uri, ins = row
	  ins = ins.to_s
	  insmax = ins if ins > insmax
	  body.push [uri, "\t", ins].join
	end
      }
    }
    utime = Time.parse(insmax + 'Z')
    head = <<EOF
Last-update: #{utime.rfc1123}\r
Content-Type: text/plain\r
\r
EOF
    head + body.join("\n") + "\n"
  end

  def showmsg uri
    body = xsl = utime = nil
    subtype = 'xml'
    check_ims
    database {|db|
      sql = <<-ENDSQL
        SELECT utime, body, xsl
	FROM jmxmsgs
	  LEFT JOIN jmxxsl USING(title)
	  LEFT JOIN msgs USING(uri)
	WHERE uri = ?
	LIMIT 1
      ENDSQL
      prepare(db, sql) {|st|
        st.execute(uri)
	while row = st.fetch
	  utimeS, body, xsl = row
	  utime = Time.parse(utimeS)
	end
      }
      raise Errno::EPERM, "requested #{uri} not found" unless body
    }
    if xsl and false
      require 'rexml/document'
      d = REXML::Document.new(body)
      pi = REXML::Instruction.new('xml-stylesheet',
        "type='text/xsl' href='../res/#{xsl}'")
      d.root.previous_sibling = pi
      body = d.to_s
    elsif xsl 
      require 'open3'
      xslpath = File.join(PRMS[:resdir], xsl).strip
      si, so, se = *Open3.popen3("xsltproc #{xslpath} /dev/stdin")
      si.write(body.to_s)
      si.close
      body = nil
      body = so.read
      STDERR.write se.read
      so.close
      se.close
      subtype = 'html'
    elsif xsl
      require 'tempfile'
      xslpath = File.join(PRMS[:resdir], xsl).strip
      t = Tempfile.open('pshbjmx')
      t.write(body.to_s)
      t.close
      body = nil
      body = `xsltproc #{xslpath} #{t.path}`
      subtype = 'html'
    end
    head = <<EOF
Last-update: #{utime.rfc1123}\r
Content-Type: text/#{subtype}\r
\r
EOF
    head + body
  end

  def showres fnam
    check_ims
    path = File.join(PRMS[:resdir], fnam)
    body = File.read(path)
    t = File.stat(path).mtime
    ctype = case fnam
      when /\.xsl/ then 'text/xml'
      when /\.css/ then 'text/css'
      else 'application/octet-stream'
      end
    head = <<EOF
Content-Type: #{ctype}\r
Last-Modified: #{t.rfc1123}\r
\r
EOF
    head + body
  end

  def redirect path
    <<EOF
Status: 302 Found\r
Location: #{myname}#{path}
\r
EOF
  end

  def getmethod
    case @path
    when %r{^/updatedb$} then updatedb
    when %r{^/m1/([^/]+)$} then mlatest_bytitle($1, true)
    when %r{^/m6/([^/]+)$} then mlatest_bytitle($1)
    when %r{^/m2/([^/]+)/([^/]+)$} then mlatest_bytitle_edof($1, $2, true)
    when %r{^/m7/([^/]+)/([^/]+)$} then mlatest_bytitle_edof($1, $2)
    when %r{^/t1/([^/]+)$} then eolist_bytitle($1)
    when %r{^/msgs\.html$} then mlatest
    when %r{^/titles\.html$} then tlist
    when %r{^/res/([^/]+)$} then showres($1)
    when %r{^/day/(\d\d\d\d)-(\d\d)-(\d\d)$} then showday($1, $2, $3)
    when %r{^/msg/([^/]+)$} then showmsg($1)
    else redirect('/titles.html')
    #else raise Errno::EPERM, "bad path #@path"
    end
  end

  def run
    require 'pshbspool-cfg'
    require 'mysql'
    resp = ["Date: #{Time.now.rfc1123}\r\n", getmethod].join
    print resp
  rescue Errno::EAGAIN => e
    puts <<EOF
Status: 304 Not Modified\r
Date: #{Time.now.rfc1123}\r
Content-Location: #{e.message.sub(/.* - /, '')}\r
\r
EOF
  rescue Errno::EPERM => e
    puts <<EOF
Status: 404 File Not Found\r
Date: #{Time.now.rfc1123}\r
Content-Type: text/plain; charset=utf8\r
\r
#{e.message}\r
EOF
  rescue Exception => e
    puts <<EOF
Status: 501 Internal Server Error\r
Content-Type: text/plain; charset=utf8\r
\r
#{e.message} (#{e.class})
#{e.backtrace.join("\n")}
EOF
  end
  
end
end

PSHBSpool::App.new.run
