OSDN Git Service

response html parser.
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / submit_window.py
1 # Copyright (C) 2006 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 import pygtk
19 pygtk.require('2.0')
20 import gtk
21 import gtk.glade
22 import gobject
23 import codecs
24 import urllib
25 import urllib2
26 import cookielib
27 import os.path
28
29 from BbsType import bbs_type_judge_uri
30 from BbsType import bbs_type_exception
31 from HTMLParserEx import HTMLParserEx
32 import datfile
33 import uri_opener
34 from http_sub import HTTPDebugHandler
35
36 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
37                          "..", "data")
38 GLADE_FILENAME = "submit_window.glade"
39
40 cookie_jar = cookielib.CookieJar()
41 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar),
42                               HTTPDebugHandler)
43
44 def open(uri):
45     if not uri:
46         raise ValueError, "parameter must not be empty"
47
48     WinWrap(uri)
49
50
51 class ConfirmationHTMLParser(HTMLParserEx):
52
53     def __init__(self):
54         HTMLParserEx.__init__(self)
55         self.message = ""
56         self.inputs = []
57         self.complete = False
58         self.title = ""
59         self.in_head = False
60         self.in_title = False
61
62     def handle_starttag(self, tag, attr):
63         if tag == "br":
64             self.message += "\n"
65         elif tag == "input":
66             self.inputs.append(dict(attr))
67         elif tag == "title":
68             self.in_title = True
69         elif tag == "head":
70             self.in_head = True
71         elif tag == "meta":
72             attr_dict = dict(attr)
73             if "http-equiv" in attr_dict \
74                and attr_dict["http-equiv"] == "refresh":
75                 self.complete = True
76
77     def handle_endtag(self, tag):
78         if tag == "title":
79             self.in_title = False
80         elif tag == "head":
81             self.in_head = False
82
83     def handle_comment(self, comment):
84         pass
85
86     def handle_data(self, data):
87         if self.in_title:
88             self.title = data
89         elif not self.in_head:
90             self.message += data.rstrip()
91
92     def handle_charref(self, ref):
93         data = None
94         try:
95             data = unichr(int(ref))
96         except:
97             data = "&#"+ref+";"
98         self.message += data
99
100     def handle_entityref(self, name):
101         if name in htmlentitydefs.name2codepoint:
102             codepoint = htmlentitydefs.name2codepoint[name]
103             self.message += unichr(codepoint)
104         else:
105             self.message += "&"+name+";"
106
107
108 class WinWrap:
109
110     def __init__(self, uri):
111         self.uri = uri
112         self.bbs_type = bbs_type_judge_uri.get_type(uri)
113         if not self.bbs_type.is_thread():
114             raise bbs_type_exception.BbsTypeError, \
115                   "the uri does not represent thread: " + uri
116
117         glade_path = os.path.join(GLADE_DIR, GLADE_FILENAME)
118         self.widget_tree = gtk.glade.XML(glade_path)
119         self.window = self.widget_tree.get_widget("submit_window")
120         self.entry_name = self.widget_tree.get_widget("entry_name")
121         self.entry_mail = self.widget_tree.get_widget("entry_mail")
122         self.textbuffer = self.widget_tree.get_widget("textview").get_buffer()
123
124         sigdic = {"on_submit_activate": self.on_submit_activate,
125                   "on_close_activate": self.on_close_activate}
126
127         self.widget_tree.signal_autoconnect(sigdic)
128
129         title = datfile.get_title_from_dat(self.bbs_type)
130         if title:
131             self.window.set_title(title)
132
133     def on_close_activate(self, widget):
134         self.window.destroy()
135
136     def on_submit_activate(self, widget):
137         name = self.entry_name.get_text()
138         mail = self.entry_mail.get_text()
139         msg = self.textbuffer.get_text(
140             self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter())
141
142         self.post_dict = self.bbs_type.build_post_dict(name, mail, msg)
143         self.post_dict = self.bbs_type.set_extra_post(self.post_dict)
144
145         self.do_submit()
146
147     def do_submit(self):
148         for name, value in self.post_dict.iteritems():
149             print "%s: %s" \
150                   % (name, value.decode(self.bbs_type.encoding, "replace"))
151         post_encoded = urllib.urlencode(self.post_dict)
152
153         req = urllib2.Request(self.bbs_type.get_post_uri(), post_encoded)
154         req.add_header("Referer", self.uri)
155
156         res = opener.open(req)
157         self.on_response(res)
158
159     def on_response(self, response):
160         data = response.read()
161         info = response.info()
162         if "Content-Type" in info:
163             import re
164             match = re.search(
165                 "charset=(?P<charset>[a-zA-Z0-9_\-]+)", info["Content-Type"])
166             if match:
167                 charset = match.group("charset").lower()
168
169         if charset in ("x-sjis", "x_sjis", "sjis", "shiftjis", "shift-jis",
170                        "shift_jis", "s-jis", "s_jis"):
171             encoding = "cp932"
172         elif charset in ("euc-jp", "euc_jp", "eucjp"):
173             encoding = "euc-jp"
174
175         if encoding:
176             data = data.decode(encoding, "replace")
177         p = ConfirmationHTMLParser()
178         p.feed(data)
179         p.close()
180
181         print data
182
183         window = gtk.Window()
184         if not p.complete:
185             window.set_default_size(500, 500)
186         if p.title:
187             window.set_title(p.title)
188         textview = gtk.TextView()
189         textview.set_wrap_mode(gtk.WRAP_CHAR)
190         textview.set_editable(False)
191         buf = textview.get_buffer()
192         buf.insert(buf.get_end_iter(), p.message)
193
194         for input in p.inputs:
195             if "type" in input and input["type"] == "submit":
196                 button = gtk.Button(input["value"])
197                 button.connect("clicked",
198                                lambda widget: self.on_button_submit_clicked(
199                     widget, p.inputs, encoding))
200                 anchor = buf.create_child_anchor(buf.get_end_iter())
201                 textview.add_child_at_anchor(button, anchor)
202                 button.grab_focus()
203                 break
204
205         window.add(textview)
206         window.show_all()
207
208         if p.complete:
209
210             def on_timeout(widget):
211                 widget.destroy()
212                 uri_opener.open_uri(self.bbs_type.get_thread_uri(), True)
213
214             gobject.timeout_add(2 * 1000, on_timeout, window)
215
216     def on_button_submit_clicked(self, widget, inputs, encoding):
217         widget.get_toplevel().destroy()
218         self.post_dict = {}
219         for input in inputs:
220             if "name" in input and "value" in input:
221                 name = input["name"]
222                 value = input["value"]
223                 if encoding:
224                     value = value.encode(encoding, "replace")
225                 self.post_dict[name] = value
226
227         self.do_submit()