OSDN Git Service

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