OSDN Git Service

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