2 * Copyright (C) 2009 by Aiwota Programmer
3 * aiwotaprog@tetteke.tk
5 * This file is part of Dialektos.
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.
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.
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/>.
21 #include "bbs_detail_base.hxx"
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>
37 #include "dat_parser.hxx"
38 #include "html_parser.hxx"
39 #include "buffer_builder.hxx"
40 #include "board_subject_item.hxx"
41 #include "http_header.hxx"
42 #include "convert/cp932.hxx"
47 namespace bbs_detail {
50 const std::string Base::bbs_name = "other";
51 const std::string Base::encoding = "cp932";
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) {
59 Base::Base(const Base& rhs) :
60 uri_(rhs.uri_), host_(rhs.host_), board_(rhs.board_), thread_(rhs.thread_) {
63 Base* Base::clone() const {
67 Base* Base::do_clone() const {
68 return new Base(*this);
73 bool Base::is_board() const {
74 return thread_.empty();
77 bool Base::is_thread() const {
78 return !thread_.empty();
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();
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();
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();
102 std::string Base::get_thread_dat_uri() const {
103 return "http://" + host_ + "/" + board_ + "/dat/" + thread_ + ".dat";
106 std::string Base::get_thread_uri() const {
107 assert(!thread_.empty());
108 std::stringstream ss;
109 ss << boost::format("http://%1%/test/read.cgi/%2%/%3%/")
110 % host_ % board_ % thread_ << std::flush;
114 std::string Base::get_another_thread_uri(const std::string& thread) const {
115 return "http://" + host_ + "/test/read.cgi/" + board_ + "/" + thread + "/";
118 std::string Base::get_board_subject_path() const {
119 boost::filesystem::path sbj(get_board_dir_path());
120 sbj = sbj / "subject.txt";
121 return sbj.file_string();
124 std::string Base::get_board_subject_uri() const {
125 std::stringstream ss;
126 ss << boost::format("http://%1%/%2%/%3%")
127 % host_ % board_ % "subject.txt" << std::flush;
131 std::string Base::get_board_uri() const {
132 std::stringstream ss;
133 ss << boost::format("http://%1%/%2%/") % host_ % board_ << std::flush;
137 std::string Base::get_board_subject_idx_path() const {
138 boost::filesystem::path dir(get_board_dir_path());
139 dir = dir / "subject.xml";
140 return dir.file_string();
143 std::string Base::get_board_idx_dir_path() const {
144 boost::filesystem::path dir(get_board_dir_path());
146 return dir.file_string();
149 const std::string& Base::get_encoding() const {
153 const std::string& Base::get_bbs_name() const {
157 void Base::load_thread_from_string(const std::string& dat,
158 text_view::Layoutable& output) const {
160 int resnum = output.get_res_num()+1;
162 std::stringstream ss;
163 ss << dat << std::flush;
166 Glib::IConv iconv("UTF-8", get_encoding());
167 while (std::getline(ss, line)) {
168 dialektos::BufferBuilder builder(output, resnum);
170 dialektos::run_parser<
171 dialektos::DatHtmlParserDriver,
172 dialektos::HtmlParserFunctions>(
174 get_encoding() == "cp932" ?
175 convert::cp932(line) : iconv.convert(line),
178 } catch (const Glib::ConvertError& e) {
180 builder.add_res_num(resnum, false);
181 builder.add_text(e.what(), true, std::string(""));
186 output.set_res_num(resnum-1);
189 void Base::load_thread(text_view::Layoutable& output) const {
190 std::string filepath = get_thread_file_path();
192 std::ifstream ifs(filepath.c_str());
193 std::stringstream ss;
194 ss << ifs.rdbuf() << std::flush;
195 load_thread_from_string(ss.str(), output);
198 void Base::load_subject(std::vector<SubjectItem>& output) const {
199 std::ifstream ifs(get_board_subject_path().c_str());
200 std::stringstream ss;
202 load_subject_from_string(ss.str(), output);
205 void Base::load_subject_from_string(const std::string& subject,
206 std::vector<SubjectItem>& output) const {
208 using namespace boost::xpressive;
209 const sregex regex = (s1=repeat<9,10>(_d)) >> ".dat" >> *_s >> "<>"
210 >> (s2=-+_) >> '(' >> *_s >> (s3=+_d) >> *_s >> ')' >> *_;
212 std::vector<SubjectItem> list;
214 Glib::IConv iconv("UTF-8", get_encoding());
217 std::stringstream ss;
220 while (std::getline(ss, line)) {
222 const std::string utf8 =
223 get_encoding() == "cp932" ? convert::cp932(line) :
226 if (regex_match(utf8, what, regex)) {
227 using namespace boost::lambda;
228 using boost::lambda::_1;
229 const std::string id = what[1];
230 std::string title = what[2];
231 boost::algorithm::trim_if(title, _1 == ' ');
232 SubjectItem item(count, id, title,
233 boost::lexical_cast<int>(what[3]));
234 list.push_back(item);
237 } catch (const Glib::ConvertError& e) {
238 std::cerr << "convert error!! - " << e.what() << " " << line << std::endl;
245 http::Header Base::get_board_subject_request_header() const {
246 http::Header request_header;
247 request_header.set_host(host_);
248 return request_header;
251 bool Base::operator==(const bbs_detail::Base& rhs) const {
252 if (this == &rhs) return true;
253 // same uri is not need.
254 return host_ == rhs.host_ && board_ == rhs.board_ && thread_ == rhs.thread_;
257 std::string Base::get_title_from_string(const std::string& dat) const {
258 using namespace boost::xpressive;
259 const sregex regex = bos >> -repeat<4>(*(~_n) >> "<>")
260 >> (s1=*(~_n)) >> _n >> -*_;
263 if (regex_match(dat, what, regex)) {
265 return get_encoding() == "cp932" ? convert::cp932(what[1]) :
266 Glib::convert(what[1], "UTF-8", get_encoding());
267 } catch (const Glib::ConvertError& e) {
268 std::cerr << "convert error!! - " << e.what() << " "
269 << what[1] << std::endl;
275 http::Header Base::get_thread_dat_request_header() const {
276 http::Header request_header;
277 request_header.set_host(host_);
279 if (boost::filesystem::exists(get_thread_file_path())) {
280 const size_t file_size = boost::filesystem::file_size(get_thread_file_path());
281 if (file_size > 0) request_header.set_range(file_size);
283 return request_header;
286 //Base* Base::judge(const std::string& uri) {
289 } // namespace bbs_detail
291 } // namespace dialektos