OSDN Git Service

modieifed setting path only.
[feedblog/feedgenerator.git] / feedgenerator.rb
1 #!/usr/local/bin/ruby
2 # -*- coding: utf-8 -*-
3 #
4 #= Atom Feed 1.0を管理するWEBアプリケーション
5 #
6 #Autohr::    Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
7 #Version::   2.0.0.0
8 #Copyright:: Copyright 2009 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
9 #License::   GPLv3
10
11 require "cgi"
12 require "cgi/session"
13 require "erb"
14 require "rexml/document"
15 require "pstore"
16 require 'time'
17 require "date"
18 require "fileutils"
19
20 # ログインID
21 LOGINID = "login"
22 # ログインパスワード
23 PASSWORD = "password"
24 # インターフェースのテーブルの幅
25 TABLEWIDTH = 1000
26 # XMLファイル格納先までの相対パス
27 XMLPATH = "./../lunardial/xml/"
28 # FeedBlogを設置したディレクトリのURL
29 HOMEBASE = "https://lunardial.sakura.ne.jp/"
30 # 入力されたフルパスURL(HOMEBASE)を置換する文字列
31 RELAYPATH = "./"
32 # loglist.xmlファイルの定義
33 LISTXMLPATH = "#{XMLPATH}loglist.xml"
34 # FeedBlog上の表示ページからログ格納ディレクトリまでのパス
35 FEEDXMLDIR = "./xml/"
36 # デバッガモード
37 DEBUG = false
38 # ファイルマネージャー機能を使用するならtrue
39 USEFILEMANAGER = true
40 # ファイルマネージャー機能スクリプト(filemanager.rb)のパス
41 FILEMANAGER = "./filemanager.rb"
42 # XMLに書き込む際、改行部分を<br>のまま保持するか、改行記号に直すか
43 REPLACEBRTAG = false
44 # ファイルの書き込み時にENTRYのIDおよびURLを、FEEDオブジェクトから自動生成した値に置換するか否か
45 REPLACEENTRYIDANDURL = false
46
47 # EXPERIMENTAL AREA START
48 TO_HTML_ENTRYTEMPLATE = 'htmltemp/diary.html.erb'
49 TO_HTML_MAINTEMPLATE = 'htmltemp/main.html.erb'
50 # EXPERIMENTAL AREA END
51
52 # バージョン情報を示す文字列です
53 APPVERSION = "- FeedGenerator for Ruby version 2.0.0.0 -<br>Copyright(c) 2009 Kureha.H (<a href=\"http://lunardial.sakura.ne.jp/\" target=\"_blank\">http://lunardial.sakura.ne.jp/</a>) & Yui Naruse (<a href=\"http://airemix.com/\" target=\"_blank\">http://airemix.com/</a>)"
54 # タイトル領域に表示される文字列です
55 APPTITLE = "FeedGenerator for Ruby version 2.0.0.0"
56
57 # = Objectクラス
58 #
59 # 基本クラスのオーバーライドを行います
60 class Object
61   # myopenメソッド
62   #
63   # ruby-1.9.x以降ではファイルを開いた際、エンコードの指定を行わないとエラーの原因になります。
64   # ただしruby-1.8.6以前はエンコードの指定に対応していないため、独自メソッドを定義してファイルの入出力を行います。
65   #
66   # _arg[0]_ :: 入出力を行うファイルのパス
67   # _arg[1]_ :: モードの指定。例 : w:utf-8(書き込みモード・UTF-8エンコードでファイルを開く)
68   def myopen(*arg)
69     mode = arg[1]
70     rdonly_p = true
71     case mode
72       when String
73       arg[1] = mode[/[^:]+/] if RUBY_VERSION < "1.8.7" && mode.include?(':')
74       rdonly_p = /\A[^:]*[wa+]/ !~ mode
75       when Numeric
76       rdonly_p = !(mode & (IO::WRONY | IO::RDWR))
77     end
78     open(*arg) do |f|
79       f.flock(rdonly_p ? File::LOCK_SH : File::LOCK_EX)
80       return yield(f)
81     end
82   end
83 end
84
85 class NilClass
86   def blank?
87     nil?
88   end
89 end
90
91 class Array
92   def blank?
93     empty?
94   end
95 end
96
97 class String
98   def blank?
99     empty?
100   end
101 end
102
103 # = Feed/Entryのスーパークラス
104
105 # 入出力用のメソッドなど、共通する機能を提供します
106 class AbstractEntry
107   # 初期化メソッドです
108   #
109   # _hash_ :: 値を格納したhash配列。superfeed.new(CGI::Session.new(new CGI).params)のようにして使う。
110   def initialize(hash)
111     # 内部データ保持用のハッシュ配列です
112     @attr = {}
113     
114     # 引数を格納します
115     @paramlist.each do |key|
116       val = hash[key.to_sym] || hash[key.to_s]
117       if val
118         val.strip!
119         val.gsub!(/\r\n|\r/, "\n")
120         @attr[key.to_sym] = CGI.escapeHTML(val)
121       else
122         # 空の場合の対策
123         @attr[key.to_sym] = ""
124       end
125     end
126     
127     # 可視・不可視を示すハッシュキーを格納する配列です
128     @display = {}
129     
130     # ハッシュキーの日本語説明を格納する配列です
131     @name = []
132   end
133   
134   # Accessor
135   attr_reader :attr, :paramlist, :name, :display
136   
137   # 内部の@attrハッシュにアクセスする手段を提供するメソッドです
138   #
139   # AbstractEntry.attr[:title]にアクセスしたい場合はAbstractEntry.titleで可能になります。
140   # AbstractEntry.send("title")という方法でもアクセス可能です。
141   def method_missing(methname, *args)
142     methname = methname.to_s
143     
144     if methname[-1] == ?=
145       # setter
146       raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" unless args.length == 1
147       methname.chop!
148       methname = @paramlist.find{|par|par == methname}
149       return @attr[methname.to_sym] = args[0] if methname
150     else
151       # getter
152       raise ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
153       return @attr[methname.to_sym] if @attr.key?(methname.to_sym)
154     end
155     # attr上にキーがない値を入れようとした場合はNoMethodError
156     raise NoMethodError
157   end
158   
159   def [](key)
160     @attr[key.to_sym]
161   end
162   
163   def []=(key, value)
164     @attr[key.to_sym] = value
165   end
166 end
167
168 # = Feedクラス
169 #
170 # Feedの基礎情報を保有するクラスです
171 class Feed < AbstractEntry
172   # 初期化メソッドです
173   #
174   # _hash_ :: 値を格納したhash配列。feed.new(CGI::Session.new(new CGI).params)のようにして使います。
175   def initialize(hash)
176     # 内部データ保持用のハッシュ配列です
177     @attr = {}
178     
179     # 内部データの項目名を格納する配列です
180     @paramlist = ["feedattr", "title", "subtitle", "self", "url", "updated", "feedid", "rights", "aname", "amail", "others"]
181     
182     # AbstractEntryのinitializeメソッドを呼び出し、値を@attr配列に格納します
183     super(hash)
184     
185     # 可視・不可視を示すハッシュキーを格納する配列です
186     @display = {"feedattr" => "none", "title" => "", "subtitle" => "", 
187       "self" => "", "url" => "", 
188       "updated" => "none", "feedid" => "", 
189       "rights" => "", "aname" => "", 
190       "amail" => "", "others" => "none"}
191     
192     # デバッグモードの場合、全ての入力要素を表示します
193     if DEBUG == true
194       @display.each do |key, val|
195         @display[key] = ""
196       end
197     end
198     
199     # ハッシュキーの日本語説明を格納する配列です
200     @name = {"feedattr" => "feedの保持している属性", "title" => "ウェブページのタイトル", "subtitle" => "ウェブページの簡単な説明", 
201       "self" => "このXMLファイルのURL", "url" => "ウェブページのURL", 
202       "updated" => "XMLファイルの最終更新日", "feedid" => "あなたのページ独自のID", 
203       "rights" => "ページの著作権表記", "aname" => "ページの製作者", 
204       "amail" => "ページ製作者のメールアドレス", "others" => "その他の要素"}
205     
206   end
207   
208   # Atom XMLファイルを読み込んで解析し、等価なFeedオブジェクトを返却するメソッドです
209   #
210   # _path_ :: Atom XMLファイルのパス
211   def self.readxml(path)
212     
213     # ファイルを読み込みます
214     doc = REXML::Document.new(myopen(path, "r:utf-8"){|f|f.read})
215     xml = {}
216     others = []
217     
218     # Feedの属性値を取得します
219     xmlattr = []
220     doc.elements["feed"].attributes.each_attribute do |attr|
221       xmlattr.push("#{attr.to_string} ")
222     end
223     xml[:feedattr] = xmlattr.join("\n").gsub(/"/, "'")
224     
225     # XML解析部分です。各element毎に判定を行います
226     doc.elements.each("feed") do |elm|
227       elm.elements.each { |child|
228         begin
229           case child.name
230             when "id"
231             xml[:feedid] = child.text
232             when "title", "subtitle", "updated", "rights"
233             xml[child.name.to_sym] = child.text
234             when "author"
235             child.elements.each do |gchild|
236               case gchild.name
237                 when "name"
238                 xml[:aname] = gchild.text
239                 when "email"
240                 xml[:amail] = gchild.text
241               end
242             end
243             when "link"
244             child.attributes.each do |k, v|
245               if k == "rel"
246                 if v == "self"
247                   xml[:self] = child.attributes["href"]
248                 elsif v == "alternate"
249                   xml[:url] = child.attributes["href"]
250                 end
251               end
252             end
253             when "entry"
254             # Entry要素は無視します
255           else
256             # 上記判定以外の全要素は配列に格納します
257             others.push(child.to_s)
258           end
259         rescue NoMethodError
260         end
261         
262       }
263     end
264     
265     # Others要素を結合して代入します
266     xml[:others] = others.join("\n")
267     feed = Feed.new(xml)
268     return feed
269   end
270   
271   # 内部に保持している情報を、Atom Feed1.0形式の文字列に出力するメソッドです
272   def to_s
273     buf = []
274     
275     # buf.push("<feed #{@attr[:feedattr]}>")
276     buf.push("<feed xml:lang='ja-jp' xmlns='http://www.w3.org/2005/Atom'>");
277     buf.push("<title type=\"text\">#{@attr[:title]}</title>")
278     buf.push("<subtitle type=\"text\">#{@attr[:subtitle]}</subtitle>")
279     buf.push("<link rel=\"self\" type=\"application/atom+xml\" href=\"#{@attr[:self]}\" />")
280     buf.push("<link rel=\"alternate\" type=\"text/html\" href=\"#{@attr[:url]}\" />")
281     buf.push("<updated>#{Time.now.iso8601}</updated>")
282     buf.push("<id>#{@attr[:feedid]}</id>")
283     buf.push("<rights type=\"text\">#{@attr[:rights]}</rights>")
284     buf.push("<author>")
285     buf.push("\t<name>#{@attr[:aname]}</name>")
286     buf.push("\t<email>#{@attr[:amail]}</email>")
287     buf.push("</author>")
288     buf.push("#{CGI.unescapeHTML(@attr[:others])}") if @attr[:others] != ""
289     
290     return buf.join("\n")
291   end
292   
293   # Feed情報更新メソッド
294   def self.update(path, feed)
295     entrylist = Entry.readxml(path)
296     Feed.to_xml(path, feed, entrylist)
297     
298     true
299   end
300   
301   # XMLファイル出力用メソッドです
302   #
303   # _feed_ :: Feedオブジェクト
304   # _entry_ :: Entryオブジェクトの配列
305   def self.to_xml(path, feed, entrylist_tmp)
306     buf = []
307     entrylist = entrylist_tmp.dup
308     buf.push("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
309     buf.push("#{feed.to_s}\n")
310     entrylist.each { |entry|
311       if REPLACEENTRYIDANDURL
312         entry.entryid.gsub!(/^[^\?]*\?/, "")
313         entry.entryid = feed.url + "?" + entry.entryid
314         entry.url = feed.url + "#" + entry.entryid
315       end
316       buf.push("#{entry.to_s}\n")
317     }
318     buf.push("</feed>")
319     
320     myopen(path, "w") do |f|
321       f.print buf.join("\n")
322     end
323   end
324   
325   # XMLファイル出力用メソッドです
326   #
327   # _feed_ :: Feedオブジェクト
328   # _entry_ :: Entryオブジェクトの配列
329   def self.to_xml_plain(path, feed, entrylist)
330     buf = []
331     buf.push("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
332     buf.push("#{feed.to_s}\n")
333     entrylist.each { |entry|
334       buf.push("#{entry.to_s}\n")
335     }
336     buf.push("</feed>")
337     
338     myopen(path, "w") do |f|
339       f.print buf.join("\n")
340     end
341   end
342   
343 end
344
345 # = Entryクラス
346 #
347 # Entryの基礎情報を保有するクラスです
348 class Entry < AbstractEntry
349   # 初期化メソッドです
350   #
351   # _hash_ :: 値を格納したhash配列。entry.new(CGI::Session.new(new CGI).params)のようにして使います。
352   def initialize(hash)
353     # 内部データ保持用のハッシュ配列です
354     @attr = {}
355     
356     # 内部データの項目名を格納する配列です
357     @paramlist = ["entryid", "title", "summary", "published", "updated", "url", "content", "others"]
358     
359     # AbstractEntryのinitializeメソッドを呼び出し、値を@attr配列に格納します
360     super(hash)
361     
362     # 可視・不可視を示すハッシュキーを格納する配列です
363     @display = {"entryid" => "none", "title" => "",
364       "summary" => "", "published" => "none",
365       "updated" => "none", "url" => "",
366       "content" => "", "others"=>"none"}
367     
368     # デバッグモードの場合、全ての入力要素を表示します
369     if DEBUG == true
370       @display.each do |key, val|
371         @display[key] = ""
372       end
373     end
374     
375     # ハッシュキーの日本語説明を格納する配列です
376     @name = {"entryid" => "記事固有のID", "title" => "記事のタイトル",
377       "summary" => "記事の簡単な説明", "published" => "記事の出版時刻",
378       "updated" => "記事の更新時刻", "url" => "記事へのURLアドレス",
379       "content" => "記事の本文", "others"=>"その他の項目"}
380   end
381   
382   # Atom XMLファイルを読み込んで解析し、等価なEntryオブジェクト配列を返却するメソッドです
383   #
384   # _path_ :: Atom XMLファイルのパス
385   def self.readxml(path)
386     
387     # ファイルを読み込みます
388     doc = REXML::Document.new(myopen(path, "r:utf-8"){|f|f.read})
389     entrylist = []
390     xml = {}
391     
392     # XML解析部分です。各element毎に判定を行います
393     doc.elements.each("feed/entry") do |elm|
394       xml = {}
395       others = []
396       elm.elements.each do |child|
397         begin
398           case child.name
399             when "id"
400             xml[:entryid] = child.text
401             when "link"
402             xml[:url] = child.attributes["href"]
403             when "title", "summary", "summary", "published", "updated", "content"
404             xml[child.name.to_sym] = child.text
405           else
406             # 上記判定以外の全要素は配列に格納します
407             others.push(child.to_s)
408           end
409         rescue NoMethodError
410         end
411       end
412       # Others要素を結合して代入します
413       xml[:others] = others.join("\n")
414       entrylist.push(Entry.new(xml))
415     end
416     
417     return entrylist
418   end
419   
420   # Atom XMLファイルを読み込んで解析し、テンプレートファイルにしたがってHTMLに変換するメソッドです
421   def self.to_html(xmlpath, destpath, entry_temppath, html_temppath)
422     # 引数チェック - 全必須
423     if xmlpath.empty? or destpath.empty? or entry_temppath.empty? or html_temppath.empty?
424       raise ArgumentError
425     end
426     
427     # 必須ファイル存在チェック
428     unless File.exist?(xmlpath) and File.exist?(entry_temppath) and File.exist?(html_temppath)
429       raise IOError
430     end
431     
432     # XML読み込み
433     entrylist = Entry.readxml(xmlpath)
434     
435     body = ''
436     entrylist.each { |e|
437       # Entry毎のHTML表示部分を生成
438       body << e.to_template(entry_temppath)
439     }
440     
441     # HTML全体のテンプレートを生成
442     html_temp = HtmlWriter.new(html_temppath, binding)
443     
444     # HTMLに書き込み
445     myopen(destpath, 'w:utf-8') { |f|
446       f.write(CGI.pretty(html_temp.to_code))
447     }
448   end
449   
450   # Entryをテンプレートに沿って変形するメソッド
451   def to_template(temppath)
452     erb = HtmlWriter.new(temppath, binding)
453     title = CGI.unescapeHTML(@attr[:title])
454     date = @attr[:published]
455     content = CGI.unescapeHTML(@attr[:content])
456     erb.to_code
457   end
458   
459   # Entry挿入メソッド
460   def self.insert(path, entry)
461     feed = Feed.readxml(path)
462     entrylist = Entry.readxml(path)
463     entrylist.unshift entry
464     
465     Feed.to_xml(path, feed, entrylist)
466     
467     true
468   end
469   
470   # Entry更新メソッド
471   def self.update(path, entry)
472     feed = Feed.readxml(path)
473     entrylist = Entry.readxml(path)
474     
475     successed = false
476     entrylist.each_with_index { |e, i|
477       if e.entryid == entry.entryid
478         entrylist[i] = entry 
479         successed = true
480       end
481     }
482     Feed.to_xml(path, feed, entrylist) if successed
483     
484     successed
485   end
486   
487   # Entryロードメソッド
488   def self.select(path, entryid)
489     feed = Feed.readxml(path)
490     entrylist = Entry.readxml(path)
491     
492     entry = nil
493     entrylist.each_with_index { |e, i|
494       entry = entrylist[i].dup if e.entryid == entryid
495     }
496     
497     entry
498   end
499   
500   # Entry消去メソッド
501   def self.delete(path, entryid)
502     feed = Feed.readxml(path)
503     entrylist = Entry.readxml(path)
504     
505     successed = false
506     delete_index = -1
507     entrylist.each_with_index { |e, i|
508       if e.entryid == entryid
509         delete_index = i
510         successed = true
511       end
512     }
513     
514     if successed
515       entrylist.delete_at delete_index
516       Feed.to_xml(path, feed, entrylist)
517     end
518     
519     successed
520   end
521   
522   # データソースから読み取ったHTMLを、エディタで編集可能な形式に変換するメソッドです
523   def content_for_generator
524     str = @attr[:content].dup
525     str.strip!
526     str.gsub!(/(&lt;\/(?:p|h\d|div)(?:&gt;|>))\n/i, '\1')
527     str.gsub!(/\n/, '&lt;br&gt;') if REPLACEBRTAG
528     str.gsub!(/(&lt;(?:(?!&gt;).)*?)#{Regexp.escape(RELAYPATH)}/) { "#$1#{HOMEBASE}" }
529     str
530   end
531   
532   # エディタで編集されたCONTENT要素を、データソースに書き込める形式に変換するメソッドです
533   def content_for_blog
534     str = @attr[:content].dup
535     str = CGI.unescapeHTML(str)
536     str.strip!
537     str.gsub!(/(\r\n|\n)/, "")
538     str.gsub!(/<br>|<br[ ]*\/>/i, "\n") if REPLACEBRTAG
539     str.gsub!(/(<br>|<br[ ]*\/>|<\/p>|<\/h\d>|<\/div>)(?=[^\n])/i) { "#$1\n" } unless REPLACEBRTAG
540     str.gsub!(/(<[^>]*?)#{Regexp.escape(HOMEBASE)}/) { "#$1#{RELAYPATH}" }
541     CGI.escapeHTML(str)
542   end
543   
544   # 確認画面で表示されるCONTENT要素を生成するメソッドです
545   def content_for_view
546     str = @attr[:content].dup
547     str = CGI.unescapeHTML(str)
548     str.strip!
549     str.gsub!(/<br>|<br[ ]*\/>/i, "\n") if REPLACEBRTAG
550     str.gsub!(/(<[^>]*?)#{Regexp.escape(RELAYPATH)}/) { "#$1#{HOMEBASE}" }
551     str
552   end
553   
554   # 内部に保持している情報を、Atom Feed1.0形式の文字列に出力するメソッドです
555   def to_s
556     buf = []
557     buf.push("<entry>")
558     buf.push("<id>#{@attr[:entryid]}</id>")
559     buf.push("<title>#{@attr[:title]}</title>")
560     buf.push("<summary>#{@attr[:summary]}</summary>")
561     buf.push("<published>#{@attr[:published]}</published>")
562     buf.push("<updated>#{@attr[:updated]}</updated>")
563     buf.push("<link href=\"#{@attr[:url]}\" />")
564     buf.push("<content type=\"html\">#{@attr[:content]}</content>")
565     buf.push("#{CGI.unescapeHTML(@attr[:others])}") if @attr[:others] != ""
566     buf.push("</entry>")
567     
568     return buf.join("\n")
569   end
570 end
571
572 # = HtmlWriterクラス
573
574 # テンプレートファイル(*.erb)を読み込み、管理するクラスです
575 class HtmlWriter
576   # 初期化メソッドです
577   #
578   # _template_ :: テンプレートファイル(*.erb)のパス
579   # _binding_ :: binding変数
580   def initialize(template, binding)
581     @erb = ERB.new(myopen(template, "r:utf-8") {|f| f.read}, nil, "-")
582     @binding = binding
583   end
584   
585   # テンプレートファイルの文字列を返却するメソッドです
586   def to_code
587     @erb.result(@binding)
588   end
589 end
590
591 # = LogListクラス
592 #
593 # loglist.xmlにかかわる入出力を行います
594 class LogList
595   # 初期化メソッドです
596   #
597   # _display_ :: 画面表示用文字の配列
598   # _path_ :: XMLファイルパスの配列
599   # _logpath_ :: loglist.xmlのパス
600   def initialize(display, path, logpath)
601     @display = display
602     @path = path
603     @logpath = logpath
604   end
605   
606   attr_accessor :display, :path, :logpath
607   
608   # loglist.xmlファイルを読み込んで解析し、LogListオブジェクトを返却するメソッドです
609   #
610   # _logpath_ :: loglist.xmlへのパス
611   def LogList.readxml(logpath)
612     
613     # ファイルを読み込みます
614     lines = []
615     myopen(logpath, "r:utf-8") { |f|
616       lines = f.readlines
617     }
618     
619     doc = REXML::Document.new(lines.join("\n"))
620     @display = []
621     @path = []
622     
623     doc.elements.each("list/file") { |elm|
624       elm.elements.each {|child|
625         case child.name
626           when "display"
627           @display.push(child.text)
628           when "path"
629           @path.push(child.text)
630         else 
631           # With no action
632         end
633       }
634     }
635     
636     return LogList.new(@display, @path, logpath)
637   end
638   
639   # loglist.xmlにオブジェクトの内容を反映するメソッドです
640   def to_xml
641     buf = []
642     buf.push("<list>")
643     path.each_with_index do |path, i|
644       buf.push("<file>")
645       buf.push("<display>#{@display[i]}</display>")
646       buf.push("<path>#{@path[i]}</path>")
647       buf.push("</file>")
648     end
649     buf.push("</list>")
650     
651     myopen(@logpath, "w") do |f|
652       f.print buf.join("\n")
653     end
654   end
655   
656 end
657
658 # = FileUploaderクラス
659 #
660 # 画像の管理を行うクラスです
661 class FileUploader
662   # 初期化メソッドです
663   def initialize
664   end
665   
666   # ファイルの一覧を取得し、ファイル名称を格納した配列を返却します
667   def filelist
668     arr = Dir::entries(XMLPATH).sort
669     arr.delete(".")
670     arr.delete("..")
671     
672     return arr
673   end
674   
675   # ファイルの消去を実行します
676   #
677   # _name_ :: 消去するファイル名
678   def delete(name)
679     File.delete(XMLPATH + name.match(/[^\/]*?$/).to_a[0])
680   end
681   
682   # ファイルのアップロードを実行します
683   #
684   # _name_ :: アップロードファイルの名称
685   # _img_ :: アップロードファイル
686   def upload(name, img)
687     open(XMLPATH + File.basename(name), "w") do |f|
688       f.binmode
689       f.write img
690     end
691   end
692 end
693
694 # = Controllerクラス
695 #
696 # コントローラ部分に相当する処理を受け持つクラスです
697 class Controller
698   def Controller.NormalForm(cgi, session, params, db)
699     db.transaction do
700       # modeとactionの相関図は以下のようになります。
701       # [mode] + [action]
702       #        + [action]
703       #        + [action]
704       #        + ... and more
705       case params["mode"]
706         # ログ選択画面
707         when "logselect"
708         session["filepath"] = params["logpath"]
709         db["loglist"] = LogList.readxml(LISTXMLPATH)
710         # 初期状態で選択されるログは「loglist.xml」の最上に位置するログになります
711         session["filepath"] = db["loglist"].path[0] if session["filepath"] == nil
712         db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
713         db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
714         
715         # 新規記事追加部分
716         when "newentry"
717         case params["action"]
718           # 確認画面
719           when "confirm"
720           session["target_filepath"] = params["target_filepath"]
721           db["newentry"] = Entry.new(params)
722           db["newentry"].content = db["newentry"].content_for_blog
723           # 記事の追記を実際にファイルに反映
724           when "exec"
725           session["target_filepath"] = params["target_filepath"]
726           successed = Entry.insert(XMLPATH + File.basename(params["target_filepath"]), Entry.new(params))
727           unless successed
728             db["error"] = "日記の新規追加に失敗しました。" 
729             params["mode"] = "error"
730           end
731           # 画面を戻った際の処理
732           when "back"
733           session["target_filepath"] = params["target_filepath"]
734           db["newentry"] = Entry.new(params)
735         else 
736           # New Diary - Default
737           session["target_filepath"] = session["filepath"]
738           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
739           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
740         end
741         
742         # 記事編集部分
743         when "editentry"
744         case params["action"]
745           # 編集画面
746           when "edit"
747           session["target_filepath"] = params["target_filepath"]
748           session["editid"] = cgi["editid"].to_s
749           db["editentry"] = Entry.select(XMLPATH + File.basename(session["target_filepath"]), session["editid"])
750           # 確認画面
751           when "confirm"
752           session["target_filepath"] = params["target_filepath"]
753           session["editid"] = cgi["editid"].to_s
754           db["editentry"] = Entry.new(params)
755           db["editentry"].content = db["editentry"].content_for_blog
756           # 記事の変更を実際にファイルに反映
757           when "exec"
758           session["target_filepath"] = params["target_filepath"]
759           successed = Entry.update(XMLPATH + File.basename(params["target_filepath"]), Entry.new(params))
760           unless successed
761             db["error"] = "日記の編集処理に失敗しました。<br>該当の日記が既に存在しない可能性があります。" 
762             params["mode"] = "error"
763           end
764           when "back"
765           session["target_filepath"] = params["target_filepath"]
766           db["editentry"] = Entry.new(params)
767         else
768           # Edit Diary - Default
769           session["target_filepath"] = session["filepath"]
770           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
771           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
772         end
773         
774         # 記事削除部分
775         when "delentry"
776         case params["action"]
777           # 確認画面
778           when "confirm"
779           session["target_filepath"] = params["target_filepath"]
780           session["delid"] = cgi["delid"].to_s
781           db["delentry"] = Entry.select(XMLPATH + File.basename(session["target_filepath"]), session["delid"])
782           # 記事の削除を実際にファイルに反映
783           when "exec"
784           session["target_filepath"] = params["target_filepath"]
785           successed = Entry.delete(XMLPATH + File.basename(params["target_filepath"]), cgi["delid"].to_s)
786           unless successed
787             db["error"] = "日記の編集処理に失敗しました。<br>該当の日記が既に存在しない可能性があります。" 
788             params["mode"] = "error"
789           end
790           when "back"
791           session["target_filepath"] = params["target_filepath"]
792           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["target_filepath"]))
793           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["target_filepath"]))
794         else
795           # Delete Diary - Default
796           session["target_filepath"] = session["filepath"]
797           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
798           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
799         end
800         
801         # Feed情報変更部分
802         when "editfeed"
803         case params["action"]
804           # 確認画面
805           when "confirm"
806           session["target_filepath"] = params["target_filepath"]
807           db["feed"] = Feed.new(params)
808           # 実際にFeed情報の変更をファイルに反映
809           when "back"
810           session["target_filepath"] = params["target_filepath"]
811           db["feed"] = Feed.new(params)
812           when "exec"
813           session["target_filepath"] = params["target_filepath"]
814           Feed.update(XMLPATH + File.basename(params["target_filepath"]), Feed.new(params))
815         else
816           session["target_filepath"] = session["filepath"]
817           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
818         end
819         
820         # ログ編集モード
821         when "log"
822         # 必ず内部データをリフレッシュする
823         db["loglist"] = LogList.readxml(LISTXMLPATH)
824         case params["action"]
825           # ログファイルの編集を実際にファイルに反映
826           when "addexec"
827           # エラーチェック。この段階のエラーは強度のエラーを発する。
828           db["loglist"].path.each do |val|
829             if val == cgi["logpath"]
830               # 重複していた場合エラーメッセージを表示し、処理を行わない
831               params["action"] = ""
832               params["mode"] = "error"
833               db["error"] = "ログファイルの追加中に重大なエラーが発生しました。<br>環境を見直してください。"
834               return
835             end
836           end
837           
838           # 入力された内容を保持する配列に追加
839           db["loglist"].path[1, 0] = cgi["logpath"]
840           db["loglist"].display[1, 0] = cgi["logdisplay"]
841           db["loglist"].to_xml
842           # 既存のdiary.xmlを指定された名称でコピーして保存
843           FileUtils.copy_file(XMLPATH + File.basename(db["loglist"].path[0]), XMLPATH + File.basename(db["logpath"]), true)
844           # 保持している情報を更新する
845           db["loglist"] = LogList.readxml(LISTXMLPATH)
846           db["entry"] = []
847           # 新たなdiary.xmlを生成。この際保持する情報は同一のFeedオブジェクトnew()
848           Feed.to_xml(XMLPATH + File.basename(db["loglist"].path[0]), db["feed"], [])
849           # 確認画面
850           when "addconfirm"
851           # 入力されたログが既に存在するかを確認
852           db["loglist"].path.each do |val|
853             if val == cgi["logpath"]
854               # 重複していた場合エラーメッセージを表示し、処理を行わない
855               params["action"] = ""
856               db["error"] = "<span style='color: #ff0000'>同一のファイルが存在します!別の名前を指定してください。</span><br>"
857               return
858             end
859           end
860           
861           db["logpath"] = cgi["logpath"]
862           db["logdisplay"] = cgi["logdisplay"]
863           
864           if db["logpath"].blank? || db["logdisplay"].blank?
865             params["action"] = ""
866           end
867           when "back"
868           
869           # 削除確認画面
870           when "delconfirm"
871           db["logdelindex"] = params["logdelindex"].to_i
872           
873           if db["logdelindex"] < 1
874             db["error"] = "<span style='color: #ff0000'>ログファイルの削除パラメタが不正です。</span><br>"
875             params["action"] = ""
876           end
877           # 削除処理
878           when "delexec"
879           if cgi["logdelindex"].to_i < 1
880             params["action"] = ""
881             params["mode"] = "error"
882             db["error"] = "ログファイルの削除中に重大なエラーが発生しました。<br>環境を見直してください。"
883             return
884           else
885             # 記事ファイルを削除します
886             File.delete(XMLPATH + File.basename(db["loglist"].path[db["logdelindex"]]))
887             # ログリストから削除します
888             db["loglist"].path.delete_at(cgi["logdelindex"].to_i)
889             db["loglist"].display.delete_at(cgi["logdelindex"].to_i)
890             db["loglist"].to_xml
891             # 保持している情報を更新する
892             db["loglist"] = LogList.readxml(LISTXMLPATH)
893             db["entry"] = []
894           end
895           
896           # 編集画面
897           when "edit"
898           db["logeditindex"] = params["logdelindex"].to_i
899           
900           db["logpath"] = db["loglist"].path[db["logeditindex"]]
901           db["logdisplay"] = db["loglist"].display[db["logeditindex"]]
902           
903           if db["logeditindex"] == 0
904             db["error"] = "<span style='color: #ff0000'>ログファイルの編集パラメタが不正です。</span><br>"
905             params["action"] = ""
906           end
907           # 編集確認画面
908           when "editconfirm"
909           checkflag = true
910           db["loglist"].path.each_with_index do |val, i|
911             if db["logeditindex"] != i
912               if params["logpath"].to_s == db["loglist"].path[i].to_s
913                 checkflag = false
914               end
915             end
916           end
917           
918           if checkflag == false
919             params["action"] = "edit"
920             db["error"] = "<span style='color: #ff0000'>同一のファイルが存在します!別の名前を指定してください。</span><br>"
921           else
922             db["loginsertindex"] = params["loginsertindex"].to_i
923             
924             db["logpath"] = params["logpath"].to_s
925             db["logdisplay"] = params["logdisplay"].to_s
926           end
927           # 編集実行
928           when "editexec"
929           checkflag = true
930           db["loglist"].path.each_with_index do |val, i|
931             if db["logeditindex"] != i
932               if params["logpath"].to_s == db["loglist"].path[i].to_s
933                 checkflag = false
934               end
935             end
936           end
937           
938           if checkflag == false
939             params["action"] = ""
940             params["mode"] = "error"
941             db["error"] = "ログファイルの編集中に重大なエラーが発生しました。<br>環境を見直してください。"
942             return
943           else
944             db["loginsertindex"] = params["loginsertindex"].to_i
945             
946             db["logpath"] = params["logpath"].to_s
947             db["logdisplay"] = params["logdisplay"].to_s
948             
949             # ファイルを移動します
950             if XMLPATH + File.basename(db["loglist"].path[db["logeditindex"]]) != XMLPATH + File.basename(db["logpath"])
951               FileUtils.move(XMLPATH + File.basename(db["loglist"].path[db["logeditindex"]]), XMLPATH + File.basename(db["logpath"]))
952               # ログリストを更新します
953               db["loglist"].path.delete_at(db["logeditindex"])
954               db["loglist"].display.delete_at(db["logeditindex"])
955               db["loglist"].path.insert(db["loginsertindex"] + 1, db["logpath"])
956               db["loglist"].display.insert(db["loginsertindex"] + 1, db["logdisplay"])
957               db["loglist"].to_xml
958             end
959           end
960           
961           # 初期表示画面
962         else
963           # 現在編集中のデータを強制的に最上のファイルパスに変更
964           session["filepath"] = db["loglist"].path[0]
965           
966           # 前月の時刻を作成します
967           prevmonth = (DateTime.now << 1)
968           
969           # 前月の時刻を元に、ディフォルト書式を生成します
970           db["logpath"] = FEEDXMLDIR + prevmonth.strftime("%Y%m") + ".xml"
971           db["logdisplay"] = prevmonth.strftime("%Y年%m月").gsub("年0", "年")
972         end
973         
974         # インポートモードの場合の処理
975         when "import"
976         db["loglist"] = LogList.readxml(LISTXMLPATH)
977         
978         # リセットモードの場合の処理
979         when "reset"
980         case params["action"]
981           # リセット実行時の処理
982           when "exec"
983           file = FileUploader.new
984           file.filelist().each { |fname|
985             file.delete(fname) if File.ftype(XMLPATH + fname) == "file"
986           }
987           
988           # 全ファイルの初期化を実行する
989           # loglist.xmlの初期化
990           loglist = LogList.new(["最新の記事"], ["#{FEEDXMLDIR}diary.xml"], LISTXMLPATH)
991           loglist.to_xml
992           
993           db["loglist"] = LogList.readxml(LISTXMLPATH)
994           
995           # diary.xmlの初期化
996           Feed.to_xml(XMLPATH + db["loglist"].path[0].match(/[^\/]*?$/).to_a[0], Feed.new({}), [])
997           
998           # 初期の編集ファイルはloglist.xml上の最も上のファイル
999           session["filepath"] = db["loglist"].path[0]
1000           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
1001           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
1002           
1003           # 画面の遷移先をトップページにする
1004           params["mode"] = ""
1005           params["action"] = ""
1006           # パラメタ無しの処理
1007         else
1008           # ファイル一覧を取得する
1009           filelist = FileUploader.new.filelist()
1010           
1011           # タイプがファイルのみリストとして取得する
1012           db["filelist"] = []
1013           filelist.each { |fname| db["filelist"] << fname if File.ftype(XMLPATH + fname) == "file"}
1014         end
1015         
1016         # ログイン時の画面
1017       else
1018         # loglist.xmlが存在するかチェック
1019         if File.exist?(LISTXMLPATH) == false
1020           # なかった場合はloglist.xmlを自動生成
1021           loglist = LogList.new(["最新の記事"], ["#{FEEDXMLDIR}diary.xml"], LISTXMLPATH)
1022           loglist.to_xml
1023           Feed.to_xml(XMLPATH + File.basename(loglist.path[0]), Feed.new({}), [])
1024         end
1025         
1026         db["loglist"] = LogList.readxml(LISTXMLPATH)
1027         
1028         # diary.xmlが存在するかチェック
1029         if File.exist?(XMLPATH + File.basename(db["loglist"].path[0])) == false
1030           # なかった場合はdiary.xmlを自動生成
1031           Feed.to_xml(XMLPATH + File.basename(db["loglist"].path[0]), Feed.new({}), [])
1032         end
1033         
1034         # 初期の編集ファイルはloglist.xml上の最も上のファイル
1035         session["filepath"] = db["loglist"].path[0] if session["filepath"] == nil
1036         db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
1037         db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
1038       end
1039     end
1040   end
1041   
1042   # マルチパートフォームの場合の処理です
1043   def Controller.MultiForm(cgi, session, params, db)
1044     db.transaction do
1045       # loglist.xmlをロードします
1046       db["loglist"] = LogList.readxml(LISTXMLPATH)
1047       case params["mode"]
1048         # 特定位置に挿入する場合の処理
1049         when "insert"
1050         case params["action"]
1051           when "exec"
1052           # この段階のエラーに対しては強度のエラーを発する
1053           checkflag = true
1054           db["logpath"] = Controller.get_mpart_value(cgi["logpath"])
1055           db["loglist"].path.each do |val|
1056             if val == db["logpath"]
1057               # 重複していた場合エラーメッセージを表示し、処理を行わない
1058               db["logpath"] = ""
1059               params["action"] = ""
1060               params["mode"] = "error"
1061               db["error"] = "ログファイルの追加中に重大なエラーが発生しました。"
1062               return
1063             end
1064           end
1065           
1066           db["loginsertindex"] = cgi["loginsertindex"].read.to_i
1067           db["logdisplay"] = Controller.get_mpart_value(cgi["logdisplay"])
1068           
1069           # 0位置への挿入防止
1070           if db["loginsertindex"] == 0
1071             params["action"] = ""
1072             params["mode"] = "error"
1073             db["error"] = "ログファイルの追加中に重大なエラーが発生しました。"
1074             return
1075           end
1076           
1077           if File.basename(db["logpath"]).blank? || db["logdisplay"].blank?
1078             params["action"] = ""
1079             params["mode"] = "error"
1080             db["error"] = "ログファイルの追加中に重大なエラーが発生しました。"
1081             return
1082           end
1083           
1084           # ファイルを実際にアップロードします
1085           file = FileUploader.new
1086           file.upload(db["logpath"], db["importxml"])
1087           
1088           # loglist.xmlを更新します
1089           db["loglist"].path[db["loginsertindex"], 0] = db["logpath"]
1090           db["loglist"].display[db["loginsertindex"], 0] = db["logdisplay"]
1091           db["loglist"].to_xml
1092           
1093           # 情報を更新します
1094           db["loglist"] = LogList.readxml(LISTXMLPATH)
1095           session["filepath"] = db["loglist"].path[0] if session["filepath"] == nil
1096           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
1097           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
1098           
1099           when "confirm"
1100           # 入力されたログファイルパスが既に存在するかを確認
1101           checkflag = true
1102           db["logpath"] = Controller.get_mpart_value(cgi["logpath"])
1103           db["loglist"].path.each do |val|
1104             if val == db["logpath"]
1105               # 重複していた場合エラーメッセージを表示し、処理を行わない
1106               db["logpath"] = ""
1107               params["action"] = ""
1108               db["error"] = "<br><span style='color: #ff0000'>同一のファイルが存在します!別の名前を指定してください。</span><br>"
1109               checkflag = false
1110               return
1111             end
1112           end
1113           
1114           if checkflag
1115             db["loginsertindex"] = cgi["loginsertindex"].read.to_i
1116             db["logdisplay"] = Controller.get_mpart_value(cgi["logdisplay"])
1117             db["importxml"] = cgi["updata"].read
1118             
1119             # XMLの整合性をチェックします
1120             begin
1121               REXML::Document.new(Controller.fix_updata_enc(db["importxml"].to_s))
1122             rescue => exception
1123               db["error"] = "<br><span style='color: #ff0000'>不正な整形のXMLです!ファイルを見直してください。</span><br>"
1124               db["error"] << "<div class='divstyle' style='width: 560px; color: #ff0000; text-align: left;'>"
1125               db["error"] << CGI.escapeHTML(exception.to_s).gsub("\n", "<br>")
1126               db["error"] << "</div>"
1127               params["action"] = ""
1128               return
1129             end
1130           end
1131           
1132           # 0位置への挿入防止
1133           if db["loginsertindex"] == 0
1134             params["action"] = ""
1135             db["error"] = "<br><span style='color: #ff0000'>ラジオボックスでログの挿入位置を選択してください!</span><br>"
1136             return
1137           end
1138           
1139           if db["logpath"] == FEEDXMLDIR || db["logdisplay"].blank?
1140             params["action"] = ""
1141             db["error"] = "<br><span style='color: #ff0000'>インポートファイル、及び、ログの表示名は空欄にできません。</span><br>"
1142             return
1143           end
1144           
1145         else
1146         end
1147         
1148         # diary.xmlを入れ替える処理
1149         when "replace"
1150         case params["action"]
1151           when "exec"
1152           # この段階のエラーに対しては強度のエラーを発する
1153           checkflag = true
1154           db["logpath"] = Controller.get_mpart_value(cgi["logpath"])
1155           db["loglist"].path.each do |val|
1156             if val == db["logpath"]
1157               # 重複していた場合エラーメッセージを表示し、処理を行わない
1158               params["action"] = ""
1159               params["mode"] = "error"
1160               db["error"] = "ログファイルの追加中に重大なエラーが発生しました。"
1161               return
1162             end
1163           end
1164           
1165           db["logdisplay"] = Controller.get_mpart_value(cgi["logdisplay"])
1166           
1167           if File.basename(db["logpath"]).blank? || db["logdisplay"].blank? || db["importxml"].blank?
1168             params["action"] = ""
1169             params["mode"] = "error"
1170             db["error"] = "ログファイルの追加中に重大なエラーが発生しました。"
1171             return
1172           end
1173           
1174           # diary.xmlを移動します
1175           FileUtils.move(XMLPATH + "diary.xml", XMLPATH + File.basename(db["logpath"]))
1176           # ファイルをアップロードします
1177           file = FileUploader.new
1178           file.upload("diary.xml", db["importxml"])
1179           
1180           # loglist.xmlを更新します
1181           db["loglist"].path[1, 0] = db["logpath"]
1182           db["loglist"].display[1, 0] = db["logdisplay"]
1183           db["loglist"].to_xml
1184           
1185           # 情報を更新します
1186           db["loglist"] = LogList.readxml(LISTXMLPATH)
1187           session["filepath"] = db["loglist"].path[0] if session["filepath"] == nil
1188           db["feed"] = Feed.readxml(XMLPATH + File.basename(session["filepath"]))
1189           db["entry"] = Entry.readxml(XMLPATH + File.basename(session["filepath"]))
1190           
1191           when "confirm"
1192           # 入力されたログファイルパスが既に存在するかを確認
1193           checkflag = true
1194           db["logpath"] = Controller.get_mpart_value(cgi["logpath"])
1195           db["loglist"].path.each do |val|
1196             if val == db["logpath"]
1197               # 重複していた場合エラーメッセージを表示し、処理を行わない
1198               params["action"] = ""
1199               db["error"] = "<br><span style='color: #ff0000'>同一のファイルが存在します!別の名前を指定してください。</span><br>"
1200               checkflag = false
1201               return
1202             end
1203           end
1204           
1205           if checkflag == true
1206             db["logdisplay"] = Controller.get_mpart_value(cgi["logdisplay"])
1207             db["importxml"] = cgi["updata"].read
1208             
1209             # XMLの整合性をチェックします
1210             begin
1211               REXML::Document.new(Controller.fix_updata_enc(db["importxml"].to_s))
1212             rescue => exception
1213               db["error"] = "<br><span style='color: #ff0000'>不正な整形のXMLです!ファイルを見直してください。</span><br>"
1214               db["error"] << "<div class='divstyle' style='width: 560px; color: #ff0000; text-align: left;'>"
1215               db["error"] << CGI.escapeHTML(exception.to_s).gsub("\n", "<br>")
1216               db["error"] << "</div>"
1217               params["action"] = ""
1218               return
1219             end
1220           end
1221           
1222           if db["logpath"].blank? || db["logdisplay"].blank? || db["importxml"].blank?
1223             params["action"] = ""
1224             db["error"] = "<br><span style='color: #ff0000'>インポートファイル、及び、ログの表示名、ログのパスは空欄にできません。</span><br>"
1225             return
1226           end
1227           
1228         else
1229         end
1230         
1231       else
1232       end
1233     end
1234   end
1235   
1236   # Formのenctypeがmultypartだった場合、入力された値をrubyバージョンに左右されずに読み取るメソッドです。
1237   def Controller.get_mpart_value(cgi_param)
1238     if RUBY_VERSION >= "1.9.0"
1239       cgi_param[0..cgi_param.length].to_s
1240     else
1241       cgi_param.read.to_s
1242     end
1243   end
1244   
1245   # アップロードされたXMLをバージョンに左右されずに読み取るために、ruby-1.9.1以上ではエンコーディングを強制指定します
1246   def Controller.fix_updata_enc(file_to_s)
1247     if RUBY_VERSION >= "1.9.0"
1248       file_to_s.force_encoding("UTF-8")
1249     else
1250       file_to_s
1251     end
1252   end
1253   
1254 end
1255
1256 def main
1257   # SESSION変数、パラメータなどを取得します
1258   cgi = CGI.new
1259   session = CGI::Session.new(cgi)
1260   params = Hash[*cgi.params.to_a.map{|k, v| [k, v[0].to_s]}.flatten]
1261   
1262   # コントローラー部分
1263   # セッション管理
1264   if session["login"] != "true"
1265     if (cgi["loginid"] == LOGINID && cgi["password"] == PASSWORD)
1266       session["login"] = "true"
1267       
1268       # ワークフォルダの中をクリーンアップします
1269       filelist = Dir::entries("./work")
1270       # 削除条件 : 最終変更日時から1日(60*60*24sec)かつ、ファイルタイプがファイルの場合
1271       filelist.each do |file|
1272         File.delete("./work/#{file}") if Time.now - File.ctime("./work/#{file}") > 86400 && File.ftype("./work/#{file}") == "file"
1273       end
1274     end
1275   end
1276   
1277   # ログアウト処理
1278   if params["mode"] == "logout"
1279     session["login"] = nil
1280     session["logini"] = nil
1281     session["password"] = nil
1282     session.delete
1283   end
1284   
1285   begin
1286     # メインコントローラー
1287     # セッションが有効な場合のも実行します
1288     if session["login"] == "true"
1289       # PStore破損チェック!
1290       begin
1291         db = PStore.new("./work/#{session.session_id}.dat")
1292         db.transaction do
1293           db["error"] = ""
1294         end
1295       rescue
1296         # PStoreファイルを破棄する
1297         File.delete("./work/#{session.session_id}.dat")
1298         # PStoreが破損していた場合はセッション情報を破棄する
1299         session["login"] = nil
1300         session["logini"] = nil
1301         session["password"] = nil
1302         session.delete
1303       end
1304       
1305       # フォームによって挙動を変更します
1306       if cgi["mode"].respond_to?(:read) && cgi["action"].respond_to?(:read)
1307         params["mode"] = cgi["mode"].read
1308         params["action"] = cgi["action"].read
1309         Controller.MultiForm(cgi, session, params, db)
1310       else
1311         Controller.NormalForm(cgi, session, params, db)
1312       end
1313       
1314       # エラー画面移行時はセッション情報を破棄する
1315       if params["mode"] == "error"
1316         session["login"] = nil
1317         session["logini"] = nil
1318         session["password"] = nil
1319         session.delete
1320       end
1321     end
1322     
1323     # メニューとして表示されるHTML文字列です
1324     if params["target_filepath"].blank?
1325       menu = "<div class=\"divstyle\" style=\"width: #{TABLEWIDTH}px;\"><div class=\"divstyle\" align=\"center\" style=\"margin-bottom: 5px;\">現在編集中のファイル : #{session["filepath"]} "
1326     else
1327       menu = "<div class=\"divstyle\" style=\"width: #{TABLEWIDTH}px;\"><div class=\"divstyle\" align=\"center\" style=\"margin-bottom: 5px;\">現在編集中のファイル : #{session["target_filepath"]} "
1328     end
1329     if USEFILEMANAGER == true
1330       menu += "[ <a href=\"#{cgi.script_name}?mode=selectlog\">他のファイルを選択</a> ]</div>[ <a href=\"#{cgi.script_name}\">トップページ</a> | 記事管理 ( <a href=\"#{cgi.script_name}?mode=newentry\">作成</a> | <a href=\"#{cgi.script_name}?mode=editentry\">編集</a> | <a href=\"#{cgi.script_name}?mode=delentry\">消去</a> )  | <a href=\"#{cgi.script_name}?mode=editfeed\">XML情報編集</a> | <a href=\"#{cgi.script_name}?mode=log\">ログ管理</a> | <a href=\"#{cgi.script_name}?mode=import\">インポート</a> | <a href=\"#{FILEMANAGER}\" target=\"_blank\">ファイル管理</a> | <a href=\"#{cgi.script_name}?mode=reset\">初期化</a> | <a href=\"#{cgi.script_name}?mode=logout\">ログアウト</a> ]</div>"
1331     else
1332       menu += "[ <a href=\"#{cgi.script_name}?mode=selectlog\">他のファイルを選択</a> ]</div>[ <a href=\"#{cgi.script_name}\">トップページ</a> | 記事管理 ( <a href=\"#{cgi.script_name}?mode=newentry\">作成</a> | <a href=\"#{cgi.script_name}?mode=editentry\">編集</a> | <a href=\"#{cgi.script_name}?mode=delentry\">消去</a> )  | <a href=\"#{cgi.script_name}?mode=editfeed\">XML情報編集</a> | <a href=\"#{cgi.script_name}?mode=log\">ログ管理</a> | <a href=\"#{cgi.script_name}?mode=import\">インポート</a> | <a href=\"#{cgi.script_name}?mode=reset\">初期化</a> | <a href=\"#{cgi.script_name}?mode=logout\">ログアウト</a> ]</div>"
1333     end
1334     
1335     # ビュー部分
1336     # modeとactionの相関図は以下のようになります。
1337     # [mode] + [action]
1338     #        + [action]
1339     #        + [action]
1340     #        + ... and more
1341     if session["login"] != "true"
1342       # セッションが存在しない場合は強制的にトップページに遷移
1343       htmlwriter = HtmlWriter.new("./erbtemp/login.html.erb", binding)
1344     else
1345       case params["mode"]
1346         when "selectlog"
1347         htmlwriter = HtmlWriter.new("./erbtemp/select.html.erb", binding)
1348         when "newentry"
1349         htmlwriter = HtmlWriter.new("./erbtemp/newentry.html.erb", binding)
1350         when "editentry"
1351         htmlwriter = HtmlWriter.new("./erbtemp/editentry.html.erb", binding)
1352         when "delentry"
1353         htmlwriter = HtmlWriter.new("./erbtemp/delentry.html.erb", binding)
1354         when "editfeed"
1355         htmlwriter = HtmlWriter.new("./erbtemp/editfeed.html.erb", binding)
1356         when "log"
1357         htmlwriter = HtmlWriter.new("./erbtemp/log.html.erb", binding)
1358         when "insert"
1359         htmlwriter = HtmlWriter.new("./erbtemp/insertfeed.html.erb", binding)
1360         when "replace"
1361         htmlwriter = HtmlWriter.new("./erbtemp/replacefeed.html.erb", binding)
1362         when "import"
1363         htmlwriter = HtmlWriter.new("./erbtemp/indeximport.html.erb", binding)
1364         when "reset"
1365         htmlwriter = HtmlWriter.new("./erbtemp/reset.html.erb", binding)
1366         when "error"
1367         htmlwriter = HtmlWriter.new("./erbtemp/error.html.erb", binding)
1368       else
1369         htmlwriter = HtmlWriter.new("./erbtemp/index.html.erb", binding)
1370       end
1371     end
1372   rescue => exception
1373     # エラーが発生した場合、それを画面に表示します
1374     htmlwriter = HtmlWriter.new("./erbtemp/exception.html.erb", binding)
1375   end
1376   
1377   # 実際にHTMLを出力します
1378   begin
1379     cgi.out{htmlwriter.to_code}
1380   rescue => exception
1381     # エラーが発生した場合、それを画面に表示します
1382     htmlwriter = HtmlWriter.new("./erbtemp/exception.html.erb", binding)
1383     cgi.out{htmlwriter.to_code}
1384   end
1385 end
1386
1387 begin
1388   main
1389 rescue => evar
1390   # エラーが発生した場合、それを画面に表示します
1391   detail = ("%s: %s (%s)\n" %
1392   [evar.backtrace[0], evar.message, evar.send('class')]) +
1393   evar.backtrace[1..-1].join("\n")
1394   puts "content-type: text/html\n\n<plaintext>\n" + detail
1395 end