OSDN Git Service

Session load and save.
[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_header.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_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;
111   return ss.str();
112 }
113
114 std::string Base::get_another_thread_uri(const std::string& thread) const {
115   return "http://" + host_ + "/test/read.cgi/" + board_ + "/" + thread + "/";
116 }
117
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();
122 }
123
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;
128   return ss.str();
129 }
130
131 std::string Base::get_board_uri() const {
132   std::stringstream ss;
133   ss << boost::format("http://%1%/%2%/") % host_ % board_ << std::flush;
134   return ss.str();
135 }
136
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();
141 }
142
143 std::string Base::get_board_idx_dir_path() const {
144   boost::filesystem::path dir(get_board_dir_path());
145   dir = dir / "idx";
146   return dir.file_string();
147 }
148
149 const std::string& Base::get_encoding() const {
150   return encoding;
151 }
152
153 const std::string& Base::get_bbs_name() const {
154   return bbs_name;
155 }
156
157 void Base::load_thread_from_string(const std::string& dat,
158     text_view::Layoutable& output) const {
159
160   int resnum = output.get_res_num()+1;
161
162   std::stringstream ss;
163   ss << dat << std::flush;
164
165   std::string line;
166   Glib::IConv iconv("UTF-8", get_encoding());
167   while (std::getline(ss, line)) {
168     dialektos::BufferBuilder builder(output, resnum);
169     try {
170       dialektos::run_parser<
171       dialektos::DatHtmlParserDriver,
172       dialektos::HtmlParserFunctions>(
173           builder,
174           get_encoding() == "cp932" ?
175               convert::cp932(line) : iconv.convert(line),
176           resnum);
177 //      iconv.reset();
178     } catch (const Glib::ConvertError& e) {
179       builder.new_line(1);
180       builder.add_res_num(resnum, false);
181       builder.add_text(e.what(), true, std::string(""));
182     }
183     ++resnum;
184   }
185
186   output.set_res_num(resnum-1);
187 }
188
189 void Base::load_thread(text_view::Layoutable& output) const {
190   std::string filepath = get_thread_file_path();
191
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);
196 }
197
198 void Base::load_subject(std::vector<SubjectItem>& output) const {
199   std::ifstream ifs(get_board_subject_path().c_str());
200   std::stringstream ss;
201   ss << ifs.rdbuf();
202   load_subject_from_string(ss.str(), output);
203 }
204
205 void Base::load_subject_from_string(const std::string& subject,
206     std::vector<SubjectItem>& output) const {
207
208   using namespace boost::xpressive;
209   const sregex regex = (s1=repeat<9,10>(_d)) >> ".dat" >> *_s >> "<>"
210   >> (s2=-+_) >> '(' >> *_s >> (s3=+_d) >> *_s >> ')' >> *_;
211
212   std::vector<SubjectItem> list;
213
214   Glib::IConv iconv("UTF-8", get_encoding());
215   size_t count = 1;
216
217   std::stringstream ss;
218   ss << subject;
219   std::string line;
220   while (std::getline(ss, line)) {
221     try {
222       const std::string utf8 =
223         get_encoding() == "cp932" ? convert::cp932(line) :
224           iconv.convert(line);
225       smatch what;
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);
235         ++count;
236       }
237     } catch (const Glib::ConvertError& e) {
238       std::cerr << "convert error!! - " << e.what() << " " << line << std::endl;
239     }
240   }
241
242   output = list;
243 }
244
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;
249 }
250
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_;
255 }
256
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 >> -*_;
261
262   smatch what;
263   if (regex_match(dat, what, regex)) {
264     try {
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;
270     }
271   }
272   return "";
273 }
274
275 http::Header Base::get_thread_dat_request_header() const {
276   http::Header request_header;
277   request_header.set_host(host_);
278
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);
282   }
283   return request_header;
284 }
285
286 //Base* Base::judge(const std::string& uri) {
287 //}
288
289 } // namespace bbs_detail
290
291 } // namespace dialektos