OSDN Git Service

90aa2f9fc2f8e3019c169fb217014d2a71059428
[fukui-no-namari/dialektos.git] / src / bbs_detail_base.cxx
1 /*
2  * Copyright (C) 2009 by Aiwota Programmer
3  * aiwotaprog@tetteke.tk
4  *
5  * This file is part of Dialektos.
6  *
7  * Dialektos is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Dialektos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Dialektos.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "bbs_detail_base.hxx"
22
23 #include <glibmm/convert.h>
24 #include <glibmm/error.h>
25 #include <boost/filesystem.hpp>
26 #include <boost/format.hpp>
27 #include <boost/xpressive/xpressive.hpp>
28 #include <boost/lambda/lambda.hpp>
29 #include <boost/algorithm/string.hpp>
30 #include <boost/lexical_cast.hpp>
31 #include <fstream>
32 #include <vector>
33 #include <string>
34 #include <iostream>
35 #include <sstream>
36 #include <cstdlib>
37 #include "dat_parser.hxx"
38 #include "html_parser.hxx"
39 #include "buffer_builder.hxx"
40 #include "board_subject_item.hxx"
41 #include "http_get.hxx"
42 #include "convert/cp932.hxx"
43
44
45 namespace dialektos {
46
47 namespace bbs_detail {
48
49
50 const std::string Base::bbs_name = "other";
51 const std::string Base::encoding = "cp932";
52
53
54 Base::Base(const std::string& uri, const std::string& host,
55     const std::string& board, const std::string& thread) :
56       uri_(uri), host_(host), board_(board), thread_(thread) {
57 }
58
59 Base::Base(const Base& rhs) :
60   uri_(rhs.uri_), host_(rhs.host_), board_(rhs.board_), thread_(rhs.thread_) {
61 }
62
63 Base* Base::clone() const {
64   return do_clone();
65 }
66
67 Base* Base::do_clone() const {
68   return new Base(*this);
69 }
70
71 Base::~Base() {}
72
73 bool Base::is_board() const {
74   return thread_.empty();
75 }
76
77 bool Base::is_thread() const {
78   return !thread_.empty();
79 }
80
81 std::string Base::get_board_dir_path() const {
82   std::string homedir = std::getenv("HOME");
83   boost::filesystem::path dir(homedir);
84   dir = dir / ".dialektos" / "logs" / get_bbs_name() / host_ / board_;
85   return dir.file_string();
86 }
87
88 std::string Base::get_thread_file_path() const {
89   boost::filesystem::path dir(get_board_dir_path());
90   std::string filename = thread_ + ".dat";
91   dir = dir / "dat" / filename;
92   return dir.file_string();
93 }
94
95 std::string Base::get_thread_idx_path() const {
96   const boost::filesystem::path dir(get_board_idx_dir_path());
97   const boost::filesystem::path xml = dir / (thread_ + ".xml");
98   return xml.file_string();
99 }
100
101
102 std::string Base::get_thread_dat_uri() const {
103   return "http://" + host_ + "/" + board_ + "/dat/" + thread_ + ".dat";
104 }
105
106 std::string Base::get_another_thread_uri(const std::string& thread) const {
107   return "http://" + host_ + "/test/read.cgi/" + board_ + "/" + thread + "/";
108 }
109
110 std::string Base::get_board_subject_path() const {
111   boost::filesystem::path sbj(get_board_dir_path());
112   sbj = sbj / "subject.txt";
113   return sbj.file_string();
114 }
115
116 std::string Base::get_board_subject_uri() const {
117   std::stringstream ss;
118   ss << boost::format("http://%1%/%2%/%3%")
119     % host_ % board_ % "subject.txt" << std::flush;
120   return ss.str();
121 }
122
123 std::string Base::get_board_subject_idx_path() const {
124   boost::filesystem::path dir(get_board_dir_path());
125   dir = dir / "subject.xml";
126   return dir.file_string();
127 }
128
129 std::string Base::get_board_idx_dir_path() const {
130   boost::filesystem::path dir(get_board_dir_path());
131   dir = dir / "idx";
132   return dir.file_string();
133 }
134
135 const std::string& Base::get_encoding() const {
136   return encoding;
137 }
138
139 const std::string& Base::get_bbs_name() const {
140   return bbs_name;
141 }
142
143 void Base::load_thread_from_string(const std::string& dat,
144     text_view::Layoutable& output) const {
145
146   int resnum = output.get_res_num()+1;
147
148   std::stringstream ss;
149   ss << dat << std::flush;
150
151   std::string line;
152   Glib::IConv iconv("UTF-8", get_encoding());
153   while (std::getline(ss, line)) {
154     dialektos::BufferBuilder builder(output, resnum);
155     try {
156       dialektos::run_parser<
157       dialektos::DatHtmlParserDriver,
158       dialektos::HtmlParserFunctions>(
159           builder,
160           get_encoding() == "cp932" ?
161               convert::cp932(line) : iconv.convert(line),
162           resnum);
163 //      iconv.reset();
164     } catch (const Glib::ConvertError& e) {
165       builder.new_line(1);
166       builder.add_res_num(resnum, false);
167       builder.add_text(e.what(), true, std::string(""));
168     }
169     ++resnum;
170   }
171
172   output.set_res_num(resnum-1);
173 }
174
175 void Base::load_thread(text_view::Layoutable& output) const {
176   std::string filepath = get_thread_file_path();
177
178   std::ifstream ifs(filepath.c_str());
179   std::stringstream ss;
180   ss << ifs.rdbuf() << std::flush;
181   load_thread_from_string(ss.str(), output);
182 }
183
184 void Base::load_subject(std::vector<SubjectItem>& output) const {
185   std::ifstream ifs(get_board_subject_path().c_str());
186   std::stringstream ss;
187   ss << ifs.rdbuf();
188   load_subject_from_string(ss.str(), output);
189 }
190
191 void Base::load_subject_from_string(const std::string& subject,
192     std::vector<SubjectItem>& output) const {
193
194   using namespace boost::xpressive;
195   const sregex regex = (s1=repeat<9,10>(_d)) >> ".dat" >> *_s >> "<>"
196   >> (s2=-+_) >> '(' >> *_s >> (s3=+_d) >> *_s >> ')' >> *_;
197
198   std::vector<SubjectItem> list;
199
200   Glib::IConv iconv("UTF-8", get_encoding());
201   size_t count = 1;
202
203   std::stringstream ss;
204   ss << subject;
205   std::string line;
206   while (std::getline(ss, line)) {
207     try {
208       const std::string utf8 =
209         get_encoding() == "cp932" ? convert::cp932(line) :
210           iconv.convert(line);
211       smatch what;
212       if (regex_match(utf8, what, regex)) {
213         using namespace boost::lambda;
214         using boost::lambda::_1;
215         const std::string id = what[1];
216         std::string title = what[2];
217         boost::algorithm::trim_if(title, _1 == ' ');
218         SubjectItem item(count, id, title,
219             boost::lexical_cast<int>(what[3]));
220         list.push_back(item);
221         ++count;
222       }
223     } catch (const Glib::ConvertError& e) {
224       std::cerr << "convert error!! - " << e.what() << " " << line << std::endl;
225     }
226   }
227
228   output = list;
229 }
230
231 http::Header Base::get_board_subject_request_header() const {
232   http::Header request_header;
233   request_header["Host"] = host_;
234   return request_header;
235 }
236
237 bool Base::operator==(const bbs_detail::Base& rhs) const {
238   if (this == &rhs) return true;
239   // same uri is not need.
240   return host_ == rhs.host_ && board_ == rhs.board_ && thread_ == rhs.thread_;
241 }
242
243 std::string Base::get_title_from_string(const std::string& dat) const {
244   using namespace boost::xpressive;
245   const sregex regex = bos >> -repeat<4>(*(~_n) >> "<>")
246     >> (s1=*(~_n)) >> _n >> -*_;
247
248   smatch what;
249   if (regex_match(dat, what, regex)) {
250     try {
251       return get_encoding() == "cp932" ? convert::cp932(what[1]) :
252         Glib::convert(what[1], "UTF-8", get_encoding());
253     } catch (const Glib::ConvertError& e) {
254       std::cerr << "convert error!! - " << e.what() << " "
255         << what[1] << std::endl;
256     }
257   }
258   return "";
259 }
260
261 http::Header Base::get_thread_dat_request_header() const {
262   http::Header request_header;
263   request_header.insert(std::make_pair("Host", host_));
264
265   if (boost::filesystem::exists(get_thread_file_path())) {
266     const size_t file_size = boost::filesystem::file_size(get_thread_file_path());
267     if (file_size > 0) {
268       std::string str = boost::lexical_cast<std::string>(file_size);
269       str = "bytes=" + str + "-";
270       request_header.insert(std::make_pair("Range", str));
271     }
272   }
273   return request_header;
274 }
275
276 //Base* Base::judge(const std::string& uri) {
277 //}
278
279 } // namespace bbs_detail
280
281 } // namespace dialektos