OSDN Git Service

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