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_get.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_another_thread_uri(const std::string& thread) const {
107 return "http://" + host_ + "/test/read.cgi/" + board_ + "/" + thread + "/";
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();
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;
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();
129 std::string Base::get_board_idx_dir_path() const {
130 boost::filesystem::path dir(get_board_dir_path());
132 return dir.file_string();
135 const std::string& Base::get_encoding() const {
139 const std::string& Base::get_bbs_name() const {
143 void Base::load_thread_from_string(const std::string& dat,
144 text_view::Layoutable& output) const {
146 int resnum = output.get_res_num()+1;
148 std::stringstream ss;
149 ss << dat << std::flush;
152 Glib::IConv iconv("UTF-8", get_encoding());
153 while (std::getline(ss, line)) {
154 dialektos::BufferBuilder builder(output, resnum);
156 dialektos::run_parser<
157 dialektos::DatHtmlParserDriver,
158 dialektos::HtmlParserFunctions>(
160 get_encoding() == "cp932" ?
161 convert::cp932(line) : iconv.convert(line),
164 } catch (const Glib::ConvertError& e) {
166 builder.add_res_num(resnum, false);
167 builder.add_text(e.what(), true, std::string(""));
172 output.set_res_num(resnum-1);
175 void Base::load_thread(text_view::Layoutable& output) const {
176 std::string filepath = get_thread_file_path();
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);
184 void Base::load_subject(std::vector<SubjectItem>& output) const {
185 std::ifstream ifs(get_board_subject_path().c_str());
186 std::stringstream ss;
188 load_subject_from_string(ss.str(), output);
191 void Base::load_subject_from_string(const std::string& subject,
192 std::vector<SubjectItem>& output) const {
194 using namespace boost::xpressive;
195 const sregex regex = (s1=repeat<9,10>(_d)) >> ".dat" >> *_s >> "<>"
196 >> (s2=-+_) >> '(' >> *_s >> (s3=+_d) >> *_s >> ')' >> *_;
198 std::vector<SubjectItem> list;
200 Glib::IConv iconv("UTF-8", get_encoding());
203 std::stringstream ss;
206 while (std::getline(ss, line)) {
208 const std::string utf8 =
209 get_encoding() == "cp932" ? convert::cp932(line) :
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);
223 } catch (const Glib::ConvertError& e) {
224 std::cerr << "convert error!! - " << e.what() << " " << line << std::endl;
231 http::Header Base::get_board_subject_request_header() const {
232 http::Header request_header;
233 request_header["Host"] = host_;
234 return request_header;
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_;
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 >> -*_;
249 if (regex_match(dat, what, regex)) {
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;
261 http::Header Base::get_thread_dat_request_header() const {
262 http::Header request_header;
263 request_header.insert(std::make_pair("Host", host_));
265 if (boost::filesystem::exists(get_thread_file_path())) {
266 const size_t file_size = boost::filesystem::file_size(get_thread_file_path());
268 std::string str = boost::lexical_cast<std::string>(file_size);
269 str = "bytes=" + str + "-";
270 request_header.insert(std::make_pair("Range", str));
273 return request_header;
276 //Base* Base::judge(const std::string& uri) {
279 } // namespace bbs_detail
281 } // namespace dialektos