#!/usr/local/bin/ruby # vim:set sw=4 ts=4 autoindent: # # ToyWiki Ver 1.05 # # This code was written by H.Okada. # (email okadahiroshi at yahoo dot co dot jp) # You can freely use, copy, modify, improve, or destribute it as same as Ruby. $KCODE='u' require 'cgi' class ToyWiki < CGI FRONT_PAGE='FrontPage' DATA_DIR='/usr/local/www/data/toywiki/pagedata/' HTML_DIR='/usr/local/www/data/toywiki/pages/' NG_PHRASE='./ng_pharse.txt' HTML_URL='http://toycode.com/toywiki/pages/' THIS_CGI_URL ='/toywiki/cgi/toywiki.cgi' SITE_TITLE = 'ToyWiki - ' def initialize super("html4Tr") end def main() begin raw_page_name = unescape_pagename( params['page'][0] || FRONT_PAGE) case params['cmd'][0] when 'editform' do_editform( raw_page_name, params['referer'][0]) when 'write' do_write( raw_page_name, params['text'][0], params['referer'][0]) when 'list' do_list( nil, params['sort'][0]) when 'searchlist' do_list( params['keyword'][0], 'time') when 'backuplist' do_backup_list( raw_page_name) when 'showbackup' do_show_backup( raw_page_name, params['ymdhms'][0]) else do_show( raw_page_name) end # case rescue out( {"charset" => "UTF-8"}) do html() do head_title( $! ) + body() { pre() { "#{$!}\n#{$@}"} } end end end end def do_show( raw_page_name) save_page_name = escape_pagename( raw_page_name) html_contents = raw_contents2html( raw_page_name, get_raw_contents( raw_page_name)) save_to_file( HTML_DIR + escape_pagename( raw_page_name) + ".html" , html_contents) print "Location: " + HTML_URL + escape_pagename( raw_page_name) + ".html" + "\n\n" end def do_show_backup( raw_page_name, ymdhms) out( {"charset" => "UTF-8"}) do html() do head_title( "#{raw_page_name} #{ymdhms}" ) + body() do h1() { "#{raw_page_name} #{ymdhms}" } + wiki_format( raw_page_name, get_raw_contents( raw_page_name, '+' + ymdhms)) + hr() + a( HTML_URL + escape_pagename( raw_page_name) + ".html") { "Latest version"} end end end end def do_editform( raw_page_name, referer) out( {"charset" => "UTF-8"}) do html() do head_title( "Edit " + raw_page_name) + body() do h1() { escapeHTML( "Edit " + raw_page_name) } + form( { "METHOD"=>"post", "accept-charset" => "UTF-8"}) do hidden( "cmd", "write") + hidden( "page", raw_page_name) + (referer ? hidden( "referer", referer) : "") + textarea( { "name" => 'text', "cols" => "100", "rows" => "25"} ){ escapeHTML( get_raw_contents( raw_page_name))} + br() + submit( "write") end end end end end def do_write( raw_page_name, raw_contents, referer) if request_method != "POST" print "Status: 405\n\n" return end if (pharse = check_ng_pharse( raw_contents)) != nil then out( {"charset" => "UTF-8"}) do html() do head_title( 'Error') + body() { p() { "Sorry #{pharse} is a spam pharse."} } end end return end save_page_name = escape_pagename(raw_page_name) date_time = Time.new().strftime("%Y%m%d%H%M") save_to_file( DATA_DIR + save_page_name, raw_contents) save_to_file( DATA_DIR + save_page_name + "+" + date_time, raw_contents) html_contents = raw_contents2html( raw_page_name, raw_contents) save_to_file( HTML_DIR + escape_pagename( raw_page_name) + ".html" , html_contents) if referer referer_raw_page_name = unescape_pagename( referer) referer_raw_contents = get_raw_contents( referer_raw_page_name) referer_html_contents = raw_contents2html( referer_raw_page_name, referer_raw_contents) save_to_file( HTML_DIR + escape_pagename( referer_raw_page_name) + ".html" , referer_html_contents) end out( {"charset" => "UTF-8"}) do html() do head_title( "Wrote " + raw_page_name) + body() do h1() { escapeHTML( "Wrote " + raw_page_name) } + form( { "METHOD"=>"get", "ACTION"=>HTML_URL+escape_pagename( raw_page_name)+".html"}) do submit( "Reload") end end end end end def do_list( keyword, sorttype) files = Hash.new Dir.foreach( DATA_DIR ) do | filename | if FileTest.file?( DATA_DIR + filename) && /^\w+$/ =~ filename name = unescape_pagename( filename) if (keyword == nil) || find( name, keyword) case sorttype when "time" st = File.stat( DATA_DIR + filename) files[ - st.mtime.to_i ] = li() { st.mtime.strftime( "%Y-%m-%d %H:%M ") + format_wikiname(name)} when "alphabet" files[ name.upcase] = li() { format_wikiname( name)} else files[ name] = li() { format_wikiname( name)} end end end end lis = files.keys.sort.map { | k| files[ k] }.join('') out( {"charset" => "UTF-8"}) do html() do head_title("List pages") + body() do h1() { "List pages" + ( (keyword != nil) ? "(#{keyword})" : "")} + [ format_wikiname( FRONT_PAGE), a( THIS_CGI_URL + '?cmd=list&sort=time' ) { "Sort by time"}, a( THIS_CGI_URL + '?cmd=list&sort=alphabet' ) { "Sort by alphabet"}, a( THIS_CGI_URL + '?cmd=list' ) { "Sort by pagename"} ].join(' | ') + ul(){ lis } end end end end def find( raw_page_name, keyword) ( raw_page_name + get_raw_contents( raw_page_name))[keyword] != nil end def head_title( title) head() do meta( { "http-equiv" => "Content-Type", "content" => "text/html; charset=UTF-8" }) + title() { escapeHTML( SITE_TITLE + title) } end end def do_backup_list( raw_page_name) contents = Array.new Dir.foreach( DATA_DIR ) do | filename | if FileTest.file?( DATA_DIR + filename) && /\+/ =~ filename (name, ymdhms) = filename.split( '+', 2) name = unescape_pagename( name) if raw_page_name == name contents.push( li() { a( "#{THIS_CGI_URL}?cmd=showbackup&page=#{escape_pagename(raw_page_name)}&ymdhms=#{ymdhms}") { ymdhms}}) end end end out( {"charset" => "UTF-8"}) do html() do head_title( "List #{raw_page_name} backups" ) + body() do h1() { "List #{raw_page_name} backups" } + ul(){ contents.sort.join( "\n")} end end end end def raw_contents2html( raw_page_name, raw_contents) html() do head_title( SITE_TITLE + raw_page_name ) + body() do h1() { escapeHTML( raw_page_name) } + wiki_format( raw_page_name, raw_contents) + hr() + [ format_wikiname( FRONT_PAGE), edit_link( raw_page_name), a( THIS_CGI_URL + '?cmd=show&page=' + escape_pagename( raw_page_name)) { "Reformat"}, a( THIS_CGI_URL + '?cmd=backuplist&page=' + escape_pagename( raw_page_name)){ 'Bakups'}, a( THIS_CGI_URL + '?cmd=list'){ 'List pages'}].join(' | ') + form( { "METHOD"=>"post", "action"=>THIS_CGI_URL }) do hidden( "cmd", "searchlist") + hidden( "page", raw_page_name) + text_field("keyword") + submit( "Search") end end end end def wiki_format( raw_page_name, raw_contents) fragment = Array.new raw_contents.each_line do | line | until line.empty? do case line when /\A([A-Z][a-z]+([A-Z][a-z]+)+)/ fragment.push( format_wikiname( $1, raw_page_name) ) when /\A\[\[([^ ]+?)\]\]/ fragment.push( '[[' + format_wikiname($1, raw_page_name) + ']]') when /\A((http|https):\/\/\S{4,})/ fragment.push( a( escapeHTML( $1)) { escapeHTML( $1) }) when /\A(\w+)/ fragment.push( escapeHTML( $1)) when /\A(\W)/ fragment.push( escapeHTML( $1)) end line = $' end end pre(){ fragment.join('')} end def get_raw_contents( raw_page_name, opt = '') filename = DATA_DIR + escape_pagename( raw_page_name) + opt if FileTest.exist?( filename) open( filename) do | io | io.read end else 'empty' end end def format_wikiname( raw_page_name, referer_page_name = nil) html_name = escapeHTML( raw_page_name) save_page_name = escape_pagename( raw_page_name) if FileTest.exist?( HTML_DIR + save_page_name + ".html") a( HTML_URL + save_page_name + ".html"){ html_name } elsif FileTest.exist?( DATA_DIR + save_page_name ) a( THIS_CGI_URL + "?cmd=show&page=#{save_page_name}") { html_name } elsif referer_page_name a( THIS_CGI_URL + "?cmd=editform&page=#{save_page_name}&" + "referer=#{escape_pagename(referer_page_name)}") { html_name + '?' } else a( THIS_CGI_URL + "?cmd=editform&page=#{save_page_name}") { html_name + '?' } end end def edit_link( raw_page_name) html_name = escapeHTML( raw_page_name) save_page_name = escape_pagename( raw_page_name) a( THIS_CGI_URL + "?cmd=editform&page=#{save_page_name}") { "Edit " + html_name} end def save_to_file( path, data) t = 0 open( path, 'a+' ) do | file | until file.flock( File::LOCK_EX | File::LOCK_NB) do select( nil, nil, nil, 1.0) raise 'time out' if ++t >= 10 end file.pos = 0 file.truncate( 0) file.write( data) end end def escape_pagename( str) str.gsub(/([^a-zA-Z0-9.-]+)/n) do '_' + $1.unpack('H2' * $1.size).join('').upcase + '_' end end def unescape_pagename( str) str.gsub(/_([0-9A-F]*)_/n) do [$1.delete('_')].pack('H*') end end def check_ng_pharse( str) open( NG_PHRASE, "r") do | file | file.each() do | line | line.chomp! return line if line != "" && str.include?(line) end end nil end def escapeHTML(str) CGI.escapeHTML( str) end end ToyWiki.new().main()