#!/usr/local/bin/ruby # # Uogashi Planing System # (C)2000-2005 by HIROSE Yuuji [yuuji@gentei.org] # $Id: uogashi.rb,v 1.14 2005/05/09 02:25:22 yuuji Exp $ # Last modified Mon May 9 11:24:04 2005 on firestorm # See http://www.gentei.org/~yuuji/software/uogashi/ # このスクリプトはEUCで保存してください。 require 'cgi' require 'kconv' me = File.expand_path($0) $mydir, $myname = File.dirname(me), File.basename(me) $mybase = $myname.sub(/\.\w+$/, '') =begin 【なんだこれ】 スクリプトと同じディレクトリの uogashi.conf というファイルに 表となる項目の一覧を書いておく。 例: [uogashi.conf] name 7/20 option(○,×,△) 7/21 option(○,×,△) 7/27 option(○,×,△) ひとこと text(10) すると、このページに何人かが書き込んだあとはこんな感じの表になる。 +----------+------+------+------+----------+ | name | 7/20 | 7/21 | 7/27 | ひとこと | +----------+------+------+------+----------+ |yuuji | ○ | × | ○ | がおー | +----------+------+------+------+----------+ |腹 | ○ | ○ | ○ | ぐおー | +----------+------+------+------+----------+ |ま | ○ | ○ | ○ | ぎょー | +----------+------+------+------+----------+ [登録or修正] uogashi.conf は1行1エントリで、TAB区切りで記述。 最初の項目は表の項目名。TABで区切った第二項目はそのカラムの値となる ものの属性を書く。属性は、 option 選択肢から選ばせる text 任意の文字列 のどれか。optionは後続する括弧内に選択肢をカンマで区切って列挙する。 textは後続する括弧内に最大バイト数を書く。また、実際には uogashi.conf に ページの管理者とか、ちょっとした体裁を決める値の定義を書く必要がある。た とえば、こんなかんじ: maintainer=yuuji@gentei.org title=定例OB会 heading=定例OB会 leader=登録画面に進み,行けそうな日に○をつけてください(10日までに!) bgcolor=yellow # #で始まる行はコメント name 7/20 option(○,×,△):stat 7/21 option(○,×,△):stat 7/27 option(○,×,△):stat ひとこと text(10) ここで初登場した option に対する :stat スイッチは、各選択肢が何人によっ て選ばれたかの表を末尾にまとめて表示することを指示する。これで幹事さんも 楽チン。 - - - - - - - - 【インストール】 まずこのスクリプトを動かすディレクトリを決める。たとえば ~/public_html/uo/ そこでCGIが動くように .htaccess を確認。 [~/public_html/uo/.htaccess] AddHandler cgi-script .cgi DirectoryIndex uogashi.cgi そして、uogashi.rb をコピー。で、実際に集計を取りたい事項の名前を決める。 ここでは、 "OB-kai2000" としよう。これがURLの一部になるのでたっぷり悩み たまへ。では、集計ディレクトリの作成。 % cp uogashi.rb ~/public_html/uo % cd ~/public_html/uo % ./uogashi.rb install OB-kai2000 すると必要な項目を聞いて来るので適当に答えると ~/public_html/uo/OB-kai2000/ に必要なものが揃うのでそのURLを知合いに教えよう。そしてサクっと一番いい 日程を決めて飲み会に行こう。 ただしこのスクリプト、集計という幹事の手間を、出席者自身にやらせようとす る性質上、悪意のある人がアクセスしたら一瞬で集計ディレクトリを壊されてし まう。その辺は覚悟して、あくまでも良く知った仲間うちで利用し、部外者はア クセスできないようにページ全体にパスワードをかける、使い終わったらすぐに 消去する、などの予防策を怠らないこと。 ちなみに、インストーラを使わずに手でインストールするには、 * uogashi.cgi を置くディレクトリに uogashi.conf をおく httpdは読めればOK * uogashi.cgi を置くディレクトリに uogashi.log, uopass.db をおく httpdは書き込み許可が必要 * uogashi.cgi を置くディレクトリに repository/ ディレクトリを掘る httpdは書き込み許可が必要 chmod 1777 repository などが適当 という条件を満たすようにファイル配置する。 さらにちなみに、Webインタフェースのインストーラもあるらしいぞ。 まず一個uogashi.cgiが動くページを作り、管理人のパスワードを設定した後で、 uogashi.cgi?webinstall をアクセスすればいいらしい。パスワードが分かると誰でも作れちゃうので 取扱注意だ。よって、手取り足取り教えないのでがんばりたまへ。動きさえ すればとても簡単に作れてしまう…。 【謝辞】 2003/6/3 YAMAGUCHI Takuya(takuya@yamaguch.sytes.net)さんにはBIND9付属のhostコマンドの 挙動について助言と対処法をいただきました。 感謝致します。 =end $repository = "./repository" $passwd = "./uopass" class TableMaker def initialize @conf = $mybase + ".conf" @ctitle = Array.new @ctype = Array.new @align = Array.new @counter = Hash.new @attr = defaultAttr @cgi = CGI.new("html4Tr") loadconf(@conf) end def defaultAttr { "title" => "Uogashi", "bgcolor" => "white", "heading" => "Table", "leader" => "Uogashi Planning Table", "inputwarning" => "全ての項目を埋めて「GO」", "tablewidth" => "700", "numbering" => "true", "mail" => "/usr/bin/mail", "sendmail" => "/usr/sbin/sendmail", "hostcmd" => "/usr/bin/host", "nslookup" => "/usr/sbin/nslookup", "passwdlength" => 6, "maintainer" => "", "forgotten" => "wasureta", "logfile" => "./#{$mybase}.log" } end def loadconf(file) i = 0 return unless test(?s, file) IO.foreach(file){|line| line.chop! line.sub!(/^\s*#.*/, '') next if /^$/ =~ line case line # title, type = line.split(/\t+/) when /^([a-z]+)=(.*)/oi key, value = $1, $2 case value when /^(no|none|null|nil)$/io @attr[key] = nil else @attr[key] = value end print "#{$1} set to #{$2}\n" if $DEBUG else @ctitle[i], @ctype[i], @align[i] = line.split(/\t+/) @counter[@ctitle[i]] = Hash.new(0) print @ctitle[i], "\n" if $DEBUG i+=1 end } end def cgi() @cgi end def outputTable() if test(?d, $repository) then begin cwd = Dir.pwd rescue cwd = `pwd` end i = -1 trs = @cgi.tr { if /true/ =~ @attr["numbering"] then @cgi.th{"番号"} else "" end + \ @ctitle.collect{|t| next if @align[i+=1] == 'ignore' @cgi.th{t} }.join('') } Dir.open($repository){|dp| Dir.chdir $repository n = 0 dp.select{|x| # should contain @mark /@/ =~ x ### /^\.\.?$/ !~ x }.collect{|e| [e, File.stat(e).mtime]}.sort{|a, b| b[1] <=> a[1] }.each{|f, dummy| trs += @cgi.tr { i = -1 if /true/ =~ @attr["numbering"] then @cgi.td("align" => "center"){(n+=1).to_s} else "" end + "\n" + \ IO.readlines(f).collect{|line| i+=1 next if @align[i] == 'ignore' line.chop! if /^option.*:stat/ =~ @ctype[i] then @counter[@ctitle[i]][line] += 1 end if /^(name|名前|氏名|お?なまえ|御芳名)$/io =~ @ctitle[i] then #line += "
(#{f})" line = @cgi.a("name"=>f){line} end @cgi.td("align" => @align[i]){ if line > "" then line else "
" end } }.join('') } + "\n" } } # Dir.chdir cwd @cgi.out({"charset" => "EUC-JP"}){ @cgi.html{ "\n" + @cgi.head{@cgi.title{@attr["title"]}} + "\n" + \ @cgi.body("bgcolor" => @attr["bgcolor"]) { "\n" + \ @cgi.h1{@attr["heading"]} + "\n" + \ @cgi.p{@attr["leader"]} + "\n" + \ @cgi.a("href" => "./"+$myname+"?entry"){"登録/修正する" }+"\n" + \ @cgi.table("border" => "1", "width" => @attr["tablewidth"]){ "\n" + trs} + "\n" + @cgi.hr + @cgi.a("href" => "./"+$myname+"?entry") {"登録/修正する" } + statinfo() + @cgi.br + @cgi.p{@attr["footer"] } + "\n" } } } end end # def outputTable def statinfo (0..@ctype.length-1).collect{|i| next if @align[i] == 'ignore' if /option\((.*)\).*:stat/ =~ @ctype[i] then optlist = $1.split(',') # p optlist @cgi.table("border" => "1") { "\n" + \ @cgi.tr { @cgi.th{"
"} + \ optlist.collect{|t| @cgi.th{t}}.join('') } + "\n" + \ @cgi.tr { @cgi.td {@ctitle[i]} + \ optlist.collect{|d| @cgi.td{@counter[@ctitle[i]][d]} }.join('') + "\n" } } else "" end }.join("\n") + "\n" end def entry @cgi.out({"charset" => "EUC-JP"}) { @cgi.html { @cgi.head{@cgi.title{@attr["title"]+" Entry"}+"\n"} + "\n" + \ @cgi.body("bgcolor" => @attr["bgcolor"]) {"\n" + \ @cgi.form("POST","./"+$myname+"?entry2") { "\n" + \ @cgi.table{ @cgi.tr { @cgi.td{"あなたのメイルアドレス"} + \ @cgi.td{@cgi.text_field("email", nil, 40)} + "\n" } + \ @cgi.tr { @cgi.td{"パスワード
(初回の場合は無記入)"} + \ @cgi.td{@cgi.password_field("passwd", nil, 40)} + "\n" } } + \ @cgi.submit("LOGIN") + @cgi.br + "\n" } + "\n" } } } end # def entry def entry2 params = @cgi.params mail, passwd = ["email", "passwd"].collect{|x| params[x][0]} pm = PasswdMgr.new($passwd, 0660) userdata = if test(?s, "#{$repository}/#{mail}") then userData("#{$repository}/#{mail}") else [] end if !checkmail(mail) then htmlOut("Invalid Mail address", @cgi.p{"メイルアドレスが無効です: #{mail}"}) elsif pm.userexist?(mail) then if pm.checkpasswd(mail, passwd) then outputForm(mail, passwd, userdata) elsif passwd == @attr["forgotten"] then sendMail(mail, "#{@attr['title']} password", "(#{ENV['REMOTE_ADDR']} からのアクセスによる送信)\n" + "#{@attr['title']} 用の #{mail} さんのパスワードは\n" + (pm.getpasswd(mail)||"未定義") + "\nです。\n") htmlOut("Sent to you", @cgi.p{"#{mail} 宛に送信しておきました"}) else outputError("パスワードが違います") end else # First time registration outputForm(mail, nil, userdata) end # p mail, passwd pm.close() end def outputError(msg) @cgi.out{ @cgi.html{ @cgi.head{@cgi.title{@attr["title"]+" error"}} + \ @cgi.body("bgcolor" => @attr["bgcolor"]){ @cgi.p{msg} } } } end def outputForm(user, passwd, default = []) @cgi.out({"charset" => "EUC-JP"}) { @cgi.html { @cgi.head{@cgi.title{@attr["title"]+" Entry for #{user}"}} + "\n" + \ @cgi.body("bgcolor" => @attr["bgcolor"]){ @cgi.p{"#{user} さんのデータ入力"} + "\n" + \ if passwd == nil passwd = generateNewPasswd pm = PasswdMgr.new($passwd) pm.setpasswd(user, passwd) pm.close() sendMail(user, "Your password for #{@attr['title']}", "あなたの #{@attr['title']} 用パスワードは\n" + passwd + "\nです。保管しておいてください。\n" + "(" + ENV['HTTP_REFERER'].sub(/\?.*/, "") + ")\n" + "もしパスワードを忘れた場合は、本当のパスワードの" + "代わりに\n#{@attr['forgotten']} と入れてください。\n") @cgi.p{ "新規登録です。あなたのパスワードは" } + @cgi.pre{passwd} + \ @cgi.p{"です。大切に保管してください。"} + "\n" else "" end + \ @cgi.p{@attr["inputwarning"]} + "\n" + @cgi.hr + "\n" + \ @cgi.form("POST", "./#{$myname}?register") { "\n" + \ @cgi.hidden("email", user) + "\n" + \ @cgi.hidden("passwd", passwd) + "\n" + \ @cgi.table{ "\n" + \ (0..@ctitle.length-1).select{|i| @align[i]!='ignore'}.collect{|i| title = @ctitle[i] type = @ctype[i] dflt = default[i] @cgi.tr { @cgi.td{title} + \ @cgi.td{ case type when /^text(\((\d+)\))?/ # print title, default[i] @cgi.text_field(title, dflt, $2) when /option\((.*)\)/ @cgi.popup_menu({ "NAME" => title, "VALUES" => popupValues($1, dflt)}) end } } + "\n" }.join('') } + \ @cgi.hr + "\n" + \ @cgi.submit("GO") } + "\n" } + "\n" } } end def popupValues(choice, default) choice.split(",").collect{|elm| if elm == default then [elm, true] else [elm] end } end def userData(file) IO.readlines(file).collect{|l|l.chop!} end def generateNewPasswd srand(Time.now.to_i) length = @attr["passwdlength"].to_i left = "qazxswedcvfrtgb12345" right = "yhnmjuik.lop;/67890-" array = [left, right] (1..length).collect{|i| a = array[i%array.length] a[rand(a.length), 1] }.join('') end def register params = @cgi.params user = params["email"][0].strip pm = PasswdMgr.new($passwd) if !checkAllFilled(params) then outputError("全ての項目を埋めてください") elsif pm.checkpasswd(user, params["passwd"][0]) then uback = File.umask File.umask(002) i = -1 open("#{$repository}/#{user}", "w") {|fp| @ctitle.each{|k| fp.print(if @align[i+=1] == 'ignore' then '
' else params[k][0] end + "\n") } } if /.*\@.*/ =~ @attr["maintainer"] then sendMail(@attr["maintainer"], @attr["title"]+" registration", "#{@attr['title']} registration by #{user}\n" + @ctitle.collect{|k| sprintf "%-20s = #{params[k][0]}", k }.join("\n")) end File.umask(uback) htmlOut(@attr["title"]+" Result", @cgi.p{"完了しました"} + \ @cgi.a("href" => "./#{$myname}"){"確認"}) else outputError("送信エラー") end pm.close() end def checkAllFilled(params) i = -1 @ctitle.each{|x| @align[i+=1] == 'ignore' or params[x][0] or return false } true end def htmlOut(title, body) @cgi.out({"charset" => "EUC-JP"}) { @cgi.html { @cgi.head{@cgi.title{title}}+"\n" + \ @cgi.body("bgcolor" => @attr["bgcolor"]) { body } } } end def setpasswd(user) pm = PasswdMgr.new($passwd) if pm.userexist?(user) then begin system "stty -echo" STDERR.print "New passwd: " p1 = STDIN.gets STDERR.print "\nAgain: " p2 = STDIN.gets ensure system "stty echo" end if (p1 == p2) then pm.setpasswd(user, p1.chop!) end STDERR.print "New password for #{user} set successfully\n" else STDERR.print "User #{user} not found\n" end pm.close() end def adduser(user) pm = PasswdMgr.new($passwd) newpwd = generateNewPasswd pm.setpasswd(user, newpwd) print "#{user}'s password is #{newpwd}\n" pm.close() end def deluser(user) pm = PasswdMgr.new($passwd) pm.delete(user) pm.close() end def sendMail(to, subject, body) body = Kconv::tojis(body) subject = Kconv.tojis(subject) if /\e/ =~ subject # If contains JIS chars... subject = subject.split(//,1).pack('m') subject = "=?iso-2022-jp?B?#{subject}?=" end subject.gsub!(/\n/, '') begin if (m=open("|-", "w")) m.print "To: #{to}\n" m.print "Subject: #{subject}\n" m.print "Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: Text/Plain; charset=iso-2022-jp " m.print body, "\n" m.close else # exec(@attr['mail'], "-s", subject, to) exec(@attr['sendmail'], to) end putLog("Sent '#{subject}' to #{to}\n") rescue putLog("FAILED! - Sent '#{subject}' to #{to}\n") end end def putLog(msg) msg += "\n" unless /\n/ =~ msg open(@attr["logfile"], "a+") {|lp| lp.print Time.now.to_s + " " + msg } end def checkmail(mail) account, domain = mail.scan(/(.*)@(.*)/)[0] return false unless account != nil && domain != nil return false unless /^[-0-9a-z_.]+$/oi =~ domain require 'socket' begin TCPSocket.gethostbyname(domain) return true rescue if test(?x, @attr["hostcmd"]) open("| #{@attr['hostcmd']} -t mx #{domain}.", "r") {|ns| #p ns.readlines.grep(/\d,\s*mail exchanger/) return ! ns.readlines.grep(/is handled .*(by |=)\d+/).empty? } elsif test(?x, @attr["nslookup"]) open("| #{@attr['nslookup']} -type=mx #{domain}.", "r") {|ns| #p ns.readlines.grep(/\d,\s*mail exchanger/) return ! ns.readlines.grep(/\d,\s*mail exchanger/).empty? } end return false end end # checkmail def install(targetdir) @attr = defaultAttr STDERR.print "[] の中にあるのはデフォルト値\n\n" newconfig = Hash.new mailguessed = ENV["USER"]+"@"+`hostname`.chop!.sub!(/[^.]+./, '') STDERR.print "あなた(=管理人)のメイルアドレス(重要) [#{mailguessed}]: " if (l=STDIN.gets.chop!) == "" then l = mailguessed end if !checkmail(l) then STDERR.print "そんなメイルアドレスじゃあ管理させられんな\n" exit 1 end newconfig["maintainer"] = l [ "タイトル:title", "ページ背景色:bgcolor", "見出し:heading", "最初の一行説明文:leader", "表の幅:tablewidth", "表の番号づけ(true/false):numbering", ].each{|item| guide, attr = item.scan(/(.*):(.*)/)[0] default = @attr[attr] STDERR.printf "%s [%s]: ", guide, default value = Kconv::toeuc(STDIN.gets.chop) if value > "" then newconfig[attr] = value end } # Input columns cols = Array.new q = lambda{|n, default| odf = Kconv::toeuc("○,△,×") STDERR.printf "第%d項目名 (もう要らないときは q) [\"%s\"]: ", n, default l = Kconv::toeuc(STDIN.gets.chop) throw :done, true if l == "q" cols[n] = Array.new if l == "" then l = default end cols[n][0] = l STDERR.print "種別 (1=text, 2=option) [2]: " l = STDIN.gets.chop! case l when "1" STDERR.print "text入力最大バイト数 [20]: " if (l=STDIN.gets.chop) == "" then l = "20" end cols[n][1] = "text(#{l})" else STDERR.print "選択肢を半角カンマで区切って入れてください [#{odf}]\n" l = Kconv::toeuc(STDIN.gets.chop!) if l == "" then l = odf end cols[n][1] = "option(#{l})" STDERR.print "この項目を集計する? [no]: " if /y/i =~ STDIN.gets then cols[n][1] += ":stat" end end } #q.call(0, "名前") STDERR.print "勝手ながらインストーラでは第0項目名を「名前」に致します.\n" cols[0] = ["名前", "text(20)"] i=0 catch (:done) { while true q.call(i+=1, "項目#{i}") end } confstr = confdump(newconfig, cols) print "-" * 70 + "\n", confstr, "-"*70, "\n" STDERR.print \ "設定ファイル(#{@conf})に書き出して作業ディレクトリも準備しますか? [y/N]: " if /y/i =~ STDIN.gets then if pid=fork then Process.wait else File.umask(0) Dir.mkdir(targetdir, 01777) unless test(?d, targetdir) #Dir.chdir(targetdir) open(targetdir+"/"+@conf, "w"){|fp| fp.print confstr} repdir = targetdir+"/"+$repository Dir.mkdir(repdir, 0777) unless test(?d, repdir) clone = targetdir+"/"+$mybase+".cgi" File.link($0, clone) unless test(?f, clone) logfile = targetdir+"/"+@attr["logfile"] open(logfile, "a+"){|fp| fp.chmod(0666)} Dir.chdir(targetdir) PasswdMgr.new($passwd, 0666).close() exit 0 end STDERR.print "\nディレクトリ属性とかあま目に設定したので後で直してね.\n" STDERR.print "あと、\n\tDirectoryIndex\tuogashi.cgi\nなんてのを" STDERR.print ".htaccess に書いとくといいかも。\n" end end def webinstall htmlOut("#{$mybase} planner web installer", @cgi.form("POST", "#{$myname}?webinstall_2") { "\n" + @cgi.table{ "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"メイルアドレス"} +\ @cgi.td{@cgi.text_field("email", nil, 40)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"パスワード"} + \ @cgi.td{@cgi.password_field("passwd", nil, 40)} } } + \ @cgi.submit("OK") + @cgi.reset("reset") }) end # webinstall_1 def webinstall_2 params = @cgi.params admin = params["email"][0] passwd = params["passwd"][0] if admin != @attr["maintainer"] htmlOut("#{$mybase} authentication error", @cgi.p{"管理人しかだめよ."}) exit 0 end df = defaultAttr htmlAuth(admin, passwd) # if invalid passwd, exits pm = PasswdMgr.new($passwd) sessionkey = Time.now.to_i.to_s sessionpasswd = generateNewPasswd pm.setpasswd(sessionkey, sessionpasswd.crypt("uo")) pm.close() sendMail(@attr["maintainer"], "uogashi: webinstall notice", < 「ページ背景色」〜「表の番号付け」は任意。
「セッションパスワード」は、今メイルで送ったのでそれを入れる。 EOM } + \ @cgi.form("POST", "#{$myname}?webinstall_3") { "\n" + \ @cgi.table("border" => "1") { "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"セッションパスワード"} + \ @cgi.td{@cgi.password_field("pas", nil, 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"集計ディレクトリ名"} + \ @cgi.td{@cgi.text_field("dir", nil, 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"集計名(タイトル)"} + \ @cgi.td{@cgi.text_field("title", nil, 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"ページ先頭の見出し"} + \ @cgi.td{@cgi.text_field("heading", nil, 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"ページ背景色"} + \ @cgi.td{@cgi.text_field("bgcolor", df["bgcolor"], 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"最初の一行説明文"} + \ @cgi.td{@cgi.text_field("leader", df["leader"], 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"表の幅(nilとすると自由幅)"} + \ @cgi.td{@cgi.text_field("tablewidth", "700", 20)} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{"表の番号付け (true/false)"} + \ @cgi.td{@cgi.popup_menu("numbering", "true", "false")} } + "\n" } + "\n" + \ @cgi.p { <<-GUIDE 続いて項目名を決定。
「種別」 text の場合は「値」に最大バイト数を
\n 「種別」 option の場合は「値」に選択肢文字列をカンマで区切って 入れる
例 晴れ,雨,曇,雪

必要なだけ項目を埋めたらそこから下は空欄のままにする。 GUIDE } + \ @cgi.table("border" => "1") { "\n" + \ @cgi.tr { "\n" + \ @cgi.th{"項目名"}+@cgi.th{"種別"}+@cgi.th{"値"} } + "\n" + \ @cgi.tr { "\n" + \ @cgi.td{@cgi.popup_menu("0,0", "名前", "氏名", "なまえ", "御芳名", "Name")} + "\n" + \ @cgi.td{@cgi.popup_menu("0,1", "text")} + "\n" + \ @cgi.hidden("0,2", "40") + @cgi.td{"40"} } + \ (1..9).collect{|n| @cgi.tr { @cgi.td{@cgi.text_field("#{n},0", n<4 && "項目#{n}", 20)} \ + "\n" + \ @cgi.td{@cgi.popup_menu("#{n},1", "option", "text", "option:stat")} + \ @cgi.td{@cgi.text_field("#{n},2", n<4 && "○,△,×", 30)} } }.join("\n") + "\n" } + \ @cgi.hidden("session", sessionkey) + "\n" + \ @cgi.hidden("adm", admin) + "\n" + \ @cgi.submit("OK") + " " + @cgi.reset("reset") }) end # webinstall_2 def webinstall_3 params = @cgi.params admin = params["adm"][0]; params.delete("adm") sskey = params["session"][0]; params.delete("session") spass = params["pas"][0]; params.delete("pas") dir = params["dir"][0]; params.delete("dir") if admin != @attr["maintainer"] htmlOut("#{$mybase} authentication error", @cgi.p{"管理人しかだめよ."}) exit 0 end if dir == nil || dir == "" htmlOut("#{$mybase} directory error", @cgi.p{"ディレクトリ名は必須."}) exit 0 elsif /^[-0-9a-z_]+$/ !~ dir htmlOut("#{$mybase} directory error", @cgi.p{"ディレクトリ名は一応半角英数字だけにしといて下さい."}) exit 0 end htmlAuth(sskey, spass.crypt("uo")) # if invalid passwd, exits deluser(sskey) # remove session key newconfig = Hash.new newconfig["maintainer"] = admin params.each_key{|key| next unless /^[a-z]/ =~ key newconfig[key] = params[key][0] params.delete(key) } cols = Array.new (0..9).each{|i| break unless params["#{i},0"][0] && params["#{i},0"][0] > "" cols[i] = Array.new cols[i][0] = params["#{i},0"][0] case (type=params["#{i},1"][0]) when /text/ cols[i][1] = "text(" + (params["#{i},2"][0] || "40") + ")" when /option/ cols[i][1] = "option(" + (params["#{i},2"][0] || "○,△,×") + ")" if /:stat/ =~ type cols[i][1] += ":stat" end end } #htmlOut("Result", "

OKおしまい

") # Begin installation begin File.umask(0) ucgi = dir+"/"+$mybase+".cgi" test(?d, dir) || Dir.mkdir(dir, 01777) test(?d, dir+"/repository") || Dir.mkdir(dir+"/repository", 01777) test(?r, ucgi) && File.unlink(ucgi) File.link($0, ucgi) open("#{dir}/#{$mybase}.conf", "w") {|fp| fp.print(confdump(newconfig, cols)) } rescue htmlOut("#{$mybase} installation error at final stage", @cgi.p{ <<-EOM エラー $!
書き込み時にエラーが起きました。おそらく #{$mybase} の置いてあるディレクトリに書き込み権限が 無いのだと思います。webinstallを利用したい場合は wwwサーバに自由に書き込みできる属性設定にしておいて 下さい。 EOM }) exit 0 end htmlOut("#{$mybase} installation done", @cgi.p { <<-EOM 以下の設定を #{dir}/#{$mybase}.conf に書き込みました。 EOM } + \ @cgi.pre{confdump(newconfig, cols)} + \ @cgi.a("href" => "#{dir}/#{$mybase}.cgi"){ "新しく作成されたページ" }) end # webinstall_3 def htmlAuth(user, passwd) pm = PasswdMgr.new($passwd) if pm.getpasswd(user) == nil then htmlOut("#{$mybase} authentication error", @cgi.p{"パスワード設定せよ"}) exit 0 end if !pm.checkpasswd(user, passwd) then htmlOut("#{$mybase} authentication error", @cgi.p{"パスワード違うの."}) exit 0 end end def userdel(user) pm = PasswdMgr.new($passwd) pm.delete(user) pm.close() end def confdump(prop, column) prop.keys.collect{|k| "#{k}=#{prop[k]}" }.join("\n") + "\n" + \ (0..column.length-1).collect{|n| column[n][0] + "\t" + column[n][1] }.join("\n") + "\n" end end class PasswdMgr def initialize(name, mode=0640) require 'dbm' @pdb = DBM.open(name, mode) end def checkpasswd(user, passwd) if @pdb[user] then @pdb[user] == passwd else @pdb[user] = passwd # If empty, then set new passwd true end end def setpasswd(user, passwd) @pdb[user] = passwd end def userexist?(user) @pdb[user] ? true : false end def getpasswd(user) @pdb[user] end def delete(user) @pdb.delete(user) end def close() @pdb.close() end end args = ARGV.dup #ARGV.shift uogashi = TableMaker.new open("uogashi.log", "w") {|lp| lp.print `env|sort` uogashi.cgi.params.each{|k, v| lp.print "#{k}=#{v}\n" } } if !args[0] and ENV["QUERY_STRING"] args[0] = ENV["QUERY_STRING"] end case args[0] when /^(entry2?|register)$/ eval "uogashi.#{args[0]}" when /^(setpasswd|deluser|adduser|checkmail)$/ p (eval "uogashi.#{args[0]}('#{args[1]}')") when "install" if args[1] == nil STDERR.print "Usage: #{$0} install 集計ディレクトリ名\n" STDERR.print "例: #{$0} install uogashi\n" exit 1 end STDERR.print "args1=#{args[1]}\n" uogashi.install(args[1]) when "webinstall" uogashi.webinstall when /webinstall_[23]/ eval "uogashi.#{args[0]}" else uogashi.outputTable end if __FILE__ == $0 end # Local variables: # buffer-file-coding-system: euc-jp # End: