OSDN Git Service

Use bbs type globally. support jbbs.
authorAiwota Programmer <aiwotaprog@tetteke.tk>
Sun, 10 Sep 2006 03:48:29 +0000 (12:48 +0900)
committerAiwota Programmer <aiwotaprog@tetteke.tk>
Sun, 10 Sep 2006 03:48:29 +0000 (12:48 +0900)
src/FukuiNoNamari/BbsType/bbs_type_base.py
src/FukuiNoNamari/BbsType/bbs_type_jbbs.py [new file with mode: 0644]
src/FukuiNoNamari/BbsType/bbs_type_judge_uri.py
src/FukuiNoNamari/board_data.py
src/FukuiNoNamari/datfile.py
src/FukuiNoNamari/idxfile.py
src/FukuiNoNamari/submit_window.py
src/FukuiNoNamari/thread_window.py

index 2b135a3..0580cf0 100644 (file)
 import re
 import copy
 import time
+import codecs
 
 from bbs_type_exception import BbsTypeError
 
+subject_reg_expr = re.compile("(?P<id>.*).dat<>(?P<title>.*)\((?P<res>\d*)\)")
+dat_reg_expr = re.compile("(?P<name>.*)<>(?P<mail>.*)<>(?P<date>.*)<>(?P<msg>.*)<>(?P<title>.*)")
+
 
 class BaseType:
     """Base of bbs type. Do not instantiate directly"""
@@ -28,6 +32,9 @@ class BaseType:
     bbs_type = "other"
     _base_reg = None
     _cgi_reg = None
+    subject_reg = subject_reg_expr
+    dat_reg = dat_reg_expr
+    encoding = "cp932"
 
     def __init__(self, uri):
         self.uri = uri
@@ -108,6 +115,17 @@ class BaseType:
     def set_extra_post(self, post_dict):
         return post_dict
 
+    def set_extra_dat_request(self, request, thread):
+        return request
+
+    def get_title_from_dat(self, line):
+        if line:
+            line = line.decode(self.encoding, "replace")
+            m = self.dat_reg.match(line)
+            if m:
+                return m.group("title")
+        return ""
+
     def get_board_dir_path(self):
         """Returns board dir path from logs dir downward, not full path"""
 
diff --git a/src/FukuiNoNamari/BbsType/bbs_type_jbbs.py b/src/FukuiNoNamari/BbsType/bbs_type_jbbs.py
new file mode 100644 (file)
index 0000000..bc0252e
--- /dev/null
@@ -0,0 +1,118 @@
+# Copyright (C) 2006 by Aiwota Programmer
+# aiwotaprog@tetteke.tk
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+import re
+import urllib2
+import time
+
+from bbs_type_exception import BbsTypeError
+from bbs_type_base import BaseType
+
+_base_reg_expr = re.compile("http://(?P<host>jbbs\.livedoor\.jp)/(?P<board>(?P<brd_dir>[^/]+)/(?P<brd_bbs>[^/]+))/$")
+_cgi_reg_expr = re.compile("http://(?P<host>jbbs\.livedoor\.jp)/bbs/read\.cgi/(?P<board>(?P<brd_dir>[^/]+)/(?P<brd_bbs>[^/]+))/(?P<thread>[^/]+)/.*")
+subject_reg_expr = re.compile("(?P<id>.*)\.cgi,(?P<title>.*)\((?P<res>\d*)\)")
+dat_reg_expr = re.compile("(?P<num>\d+)<>(?P<name>.*)<>(?P<mail>.*)<>(?P<date>.*)<>(?P<msg>.*)<>(?P<title>.*)<>(?P<id>.*)")
+
+
+class TypeJbbs(BaseType):
+    """Base of bbs type. Do not instantiate directly"""
+
+    bbs_type = "jbbs"
+    _base_reg = _base_reg_expr
+    _cgi_reg = _cgi_reg_expr
+    subject_reg = subject_reg_expr
+    dat_reg = dat_reg_expr
+    encoding = "euc-jp"
+
+    def __init__(self, uri):
+        self.brd_dir = None
+        self.brd_bbs = None
+        BaseType.__init__(self, uri)
+
+    def _parse_uri(self, uri):
+        m = self._base_reg.match(self.uri)
+        if m:
+            self.host = m.group("host")
+            self.board = m.group("board")
+            self.brd_dir = m.group("brd_dir")
+            self.brd_bbs = m.group("brd_bbs")
+        else:
+            m = self._cgi_reg.match(self.uri)
+            if m:
+                self.host = m.group("host")
+                self.board = m.group("board")
+                self.brd_dir = m.group("brd_dir")
+                self.brd_bbs = m.group("brd_bbs")
+                self.thread = m.group("thread")
+            else:
+                raise BbsTypeError, \
+                      "the uri %s does not represent %s" \
+                      % (self.uri, self.bbs_type)
+
+    def get_uri_base(self):
+        return "http://" + self.host + "/" + self.board + "/"
+
+    def get_subject_txt_uri(self):
+        return self.get_uri_base() + "subject.txt"
+
+    def get_dat_uri(self):
+        if not self.thread:
+            raise BbsTypeError, "not specified thread"
+        return "http://" + self.host + "/bbs/rawmode.cgi/" + \
+                  self.board + "/" + self.thread + "/"
+
+    def get_thread_uri(self):
+        if not self.thread:
+            raise BbsTypeError, "not specified thread"
+        return "http://" + self.host + "/bbs/read.cgi/" + \
+                  self.board + "/" + self.thread + "/"
+
+    def get_post_uri(self):
+        return "http://" + self.host + "/bbs/write.cgi/" + self.board \
+               + "/" + self.thread + "/"
+
+    def build_post_dict(self, name, mail, msg):
+        post_dict = {}
+        post_dict["DIR"] = self.brd_dir
+        post_dict["BBS"] = self.brd_bbs
+        post_dict["KEY"] = self.thread
+        post_dict["TIME"] = str(int(time.time()))
+        post_dict["submit"] = u"\u66f8\u304d\u8fbc\u3080".encode(
+            "euc-jp", "replace")
+        post_dict["NAME"] = name.encode("euc-jp", "replace")
+        post_dict["MAIL"] = mail.encode("euc-jp", "replace")
+        post_dict["MESSAGE"] = msg.encode("euc-jp", "replace")
+        return post_dict
+
+    def set_extra_dat_request(self, request, thread):
+        datfile_url = request.get_full_url()
+        if thread.num > 0:
+            datfile_url += str(thread.num+1) + "-"
+        headers = dict(request.header_items())
+        try:
+            del headers["Range".capitalize()]
+            del headers["If-modified-since".capitalize()]
+            del headers["If-none-match".capitalize()]
+        except KeyError:
+            pass
+        request = urllib2.Request(datfile_url, headers=headers)
+        return request
+        
+    def get_board_dir_path(self):
+        """Returns board dir path from logs dir downward, not full path"""
+
+        return self.bbs_type + "/" + self.board
index 6d8fe5b..4452962 100644 (file)
@@ -19,10 +19,11 @@ import traceback
 
 from bbs_type_2ch import Type2ch
 from bbs_type_yy import TypeYY
+from bbs_type_jbbs import TypeJbbs
 from bbs_type_other import TypeOther
 from bbs_type_exception import BbsTypeError
 
-_typelist = [Type2ch, TypeYY, TypeOther]
+_typelist = [Type2ch, TypeYY, TypeJbbs, TypeOther]
 
 def get_type(uri):
     for type_class in _typelist:
index a783d47..cc177e0 100644 (file)
@@ -18,7 +18,6 @@
 import gobject
 import os.path
 import glob
-import re
 import codecs
 import urllib2
 import traceback
@@ -30,7 +29,6 @@ import misc
 from http_sub import HTTPRedirectHandler302, HTTPDebugHandler
 
 BOARD_DATA_INVALID_VALUE = 0
-REG_EXPR = re.compile("(?P<id>.*).dat<>(?P<title>.*)\((?P<res>\d*)\)")
 
 
 class BoardData:
@@ -59,10 +57,16 @@ class BoardData:
 
         if id in datalist:
             item = datalist[id]
-            item["num"] = num
-            item["title"] = title
-            item["res"] = res
-            item["average"] = average
+            if item["num"]:
+                # already exists in datalist and num is not 0, then this thread
+                # is duplicate in subject.txt.
+                # ignore second.
+                pass
+            else:
+                item["num"] = num
+                item["title"] = title
+                item["res"] = res
+                item["average"] = average
         else:
             datalist[id] = {"num": num, "title": title,
                             "res": res, "lineCount": BOARD_DATA_INVALID_VALUE,
@@ -124,8 +128,9 @@ class BoardData:
                     for name in idxfile.metadata_namelist:
                         datalist[thread_id][name] = dic[name]
 
-    def _split_record(self, line):
-        m = REG_EXPR.match(line)
+    def _split_record(self, line_encoded):
+        line = line_encoded.decode(self.bbs_type.encoding, "replace")
+        m = self.bbs_type.subject_reg.match(line)
         if m:
             id = m.group("id")
             title = m.group("title")
@@ -148,8 +153,7 @@ class BoardData:
             for num, line_encoded \
                     in itertools.izip(itertools.count(1),
                                       file(subjecttxt_path)):
-                result = self._split_record(
-                    line_encoded.decode("cp932", "replace"))
+                result = self._split_record(line_encoded)
                 if result:
                     id, title, res = result
                     try:
@@ -207,8 +211,7 @@ class BoardData:
                             f.write(line_encoded)
                         except IOError:
                             traceback.print_exc()
-                    result = self._split_record(
-                        line_encoded.decode("cp932", "replace"))
+                    result = self._split_record(line_encoded)
                     if result:
                         id, title, res = result
                         try:
index c672196..13334fb 100644 (file)
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-import re
 import os.path
 import codecs
 import fileinput
 
 import misc
 
-REG_EXPR_TITLE = re.compile(".*<>.*<>.*<>.*<>(.*)")
-REG_EXPR_ELEM = re.compile( \
-    "(?P<name>.*)<>(?P<mail>.*)<>(?P<date>.*)<>(?P<msg>.*)<>")
-
 def get_dat_file_size(bbs_type):
     """Returns size of dat file"""
     dat_path = misc.get_thread_dat_path(bbs_type)
@@ -52,13 +47,6 @@ def get_dat_line_count(bbs_type):
     for l in f: -1
     return f.filelineno()
 
-def do_get_title_from_dat(line):
-    if line:
-        m = REG_EXPR_TITLE.match(line.decode("cp932", "replace"))
-        if m:
-            return m.group(1)
-    return ""
-    
 def get_title_from_dat(bbs_type):
     """Returns thread title in dat file
 
@@ -77,28 +65,10 @@ def get_title_from_dat(bbs_type):
     f = open(dat_path, "r")
     try:
         line = f.readline()
-        return do_get_title_from_dat(line)
+        return bbs_type.get_title_from_dat(line)
     finally:
         f.close()
 
-def split_line_to_elems(line, func):
-    """Splits a line to elements and invokes func
-
-    line: represents one res
-
-    func: is invoked after splitting
-    format of user functon is:
-    def some_func(name, mail, date, msg):
-    where parameters represent corresponding elements of the res
-    """
-    m = REG_EXPR_ELEM.match(line)
-    if m:
-        name = m.group("name")
-        mail = m.group("mail")
-        date = m.group("date")
-        msg = m.group("msg")
-        func(name, mail, date, msg)
-
 def load_dat(bbs_type, func):
     """Loads entire dat and invokes func per one res
 
index b559a03..14b58b9 100644 (file)
@@ -36,7 +36,7 @@ def load_idx(bbs_type):
     """
     idxfile_path = misc.get_thread_idx_path(bbs_type)
     if not os.path.exists(idxfile_path):
-        return {"title":None,"lineCount":0,"lastModified":None,"etag":None}
+        return {"title":"","lineCount":0,"lastModified":"","etag":""}
 
     datadic = {}
     f = FileInput(idxfile_path)
index fa06afa..3b2985b 100644 (file)
@@ -143,12 +143,27 @@ class WinWrap:
 
     def on_response(self, response):
         data = response.read()
-
+        info = response.info()
+        if "Content-Type" in info:
+            import re
+            match = re.search(
+                "charset=(?P<charset>[a-zA-Z0-9_\-]+)", info["Content-Type"])
+            if match:
+                charset = match.group("charset").lower()
+
+        if charset in ("x-sjis", "x_sjis", "sjis", "shiftjis", "shift-jis",
+                       "shift_jis", "s-jis", "s_jis"):
+            encoding = "cp932"
+        elif charset in ("euc-jp", "euc_jp", "eucjp"):
+            encoding = "euc-jp"
+
+        if encoding:
+            data = data.decode(encoding, "replace")
         p = ConfirmationHTMLParser()
-        p.feed(data.decode("cp932", "replace"))
+        p.feed(data)
         p.close()
 
-        print data.decode("cp932")
+        print data
 
         window = gtk.Window()
         if not p.complete:
@@ -163,9 +178,11 @@ class WinWrap:
             if "type" in input and input["type"] == "submit":
                 button = gtk.Button(input["value"])
                 button.connect("clicked",
-                               self.on_button_submit_clicked, p.inputs)
+                               lambda widget: self.on_button_submit_clicked(
+                    widget, p.inputs, encoding))
                 anchor = buf.create_child_anchor(buf.get_end_iter())
                 textview.add_child_at_anchor(button, anchor)
+                button.grab_focus()
                 break
 
         window.add(textview)
@@ -179,13 +196,15 @@ class WinWrap:
 
             gobject.timeout_add(2 * 1000, on_timeout, window)
 
-    def on_button_submit_clicked(self, widget, inputs=None):
+    def on_button_submit_clicked(self, widget, inputs, encoding):
         widget.get_toplevel().destroy()
         self.post_dict = {}
         for input in inputs:
             if "name" in input and "value" in input:
                 name = input["name"]
                 value = input["value"]
-                self.post_dict[name] = value.encode("cp932", "replace")
+                if encoding:
+                    value = value.encode(encoding, "replace")
+                self.post_dict[name] = value
 
         self.do_submit()
index a5e2797..c4ce1b3 100644 (file)
@@ -258,6 +258,8 @@ class WinWrap(winwrapbase.WinWrapBase):
         if etag:
             req.add_header("If-None-Match", etag)
 
+        req = self.bbs_type.set_extra_dat_request(req, self)
+
         opener = urllib2.build_opener(HTTPRedirectHandler302, HTTPDebugHandler)
         try:
             res = opener.open(req)
@@ -269,15 +271,13 @@ class WinWrap(winwrapbase.WinWrapBase):
             gobject.idle_add(
                 self.statusbar.set_status, "%d %s" % (res.code, res.msg))
 
-            line = res.readline()
             maybe_incomplete = False
-            while line:
+            for line in res:
                 if not line.endswith("\n"):
                     maybe_incomplete = True
                     print "does not end with \\n. maybe incomplete"
                     break
                 on_get_res(line)
-                line = res.readline()
 
             res.close()
 
@@ -291,11 +291,6 @@ class WinWrap(winwrapbase.WinWrapBase):
                     etag = headers["Etag"]
 
             if self.num > 0:
-                if not self.title:
-                    title = datfile.get_title_from_dat(self.bbs_type)
-                    if title:
-                        self.title = title
-                        gobject.idle_add(self.window.set_title, title)
                 # save idx
                 idx_dic = {"title": self.title, "lineCount": self.num,
                        "lastModified": lastmod, "etag": etag}
@@ -408,16 +403,40 @@ class WinWrap(winwrapbase.WinWrapBase):
         self.num += 1
 
         if not self.title and self.num == 1:
-            title = datfile.do_get_title_from_dat(line)
+            title = self.bbs_type.get_title_from_dat(line)
             if title:
                 self.title = title
                 gobject.idle_add(self.window.set_title, title)
 
-        h = lambda name,mail,date,msg: self.reselems_to_buffer(
-            self.num, name, mail, date, msg)
-
         self.res_queue = []
-        datfile.split_line_to_elems(line.decode("cp932", "replace"), h)
+
+        line = line.decode(self.bbs_type.encoding, "replace")
+        m = self.bbs_type.dat_reg.match(line)
+        if m:
+            name = m.group("name")
+            mail = m.group("mail")
+            date = m.group("date")
+            msg = m.group("msg")
+            try:
+                num = int(m.group("num"))
+            except IndexError:
+                # use simple counter num
+                num = self.num
+            else:
+                # use num in dat
+                self.num = num
+            try:
+                id = m.group("id")
+            except IndexError:
+                pass
+            else:
+                if id:
+                    date += " ID:" + id
+            self.reselems_to_buffer(num, name, mail, date, msg)
+        else:
+            self.res_queue.append((str(self.num)+"\n", False, None, False))
+            self.res_queue.append((line, False, None, True))
+            print "maybe syntax error.", self.num, line
 
         def process_res_queue(res_queue, num):
             self.process_queue(res_queue)