| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | #include "date_value.hh" |
|---|
| 21 | #include "empty_value.hh" |
|---|
| 22 | #include "group_value.hh" |
|---|
| 23 | #include "header_value.hh" |
|---|
| 24 | #include "lazy_structured_value.hh" |
|---|
| 25 | #include "list_value.hh" |
|---|
| 26 | #include "msg_value.hh" |
|---|
| 27 | #include "user_value.hh" |
|---|
| 28 | #include "basic_sequential_value.hh" |
|---|
| 29 | |
|---|
| 30 | #include "../db/threaded.hh" |
|---|
| 31 | #include "../db/msg.hh" |
|---|
| 32 | #include "../html/util.hh" |
|---|
| 33 | #include "../http/compose.hh" |
|---|
| 34 | #include "../msg/entity.hh" |
|---|
| 35 | #include "../msg/lexutils.hh" |
|---|
| 36 | #include "../uri.hh" |
|---|
| 37 | |
|---|
| 38 | #include <boost/bind.hpp> |
|---|
| 39 | |
|---|
| 40 | namespace |
|---|
| 41 | { |
|---|
| 42 | using namespace tlate; |
|---|
| 43 | using html::quote; |
|---|
| 44 | using msg::decode_unstructured; |
|---|
| 45 | class xref_seq : public sequential_value |
|---|
| 46 | { |
|---|
| 47 | db::msg::const_ptr m; |
|---|
| 48 | db::user::const_ptr u; |
|---|
| 49 | |
|---|
| 50 | class vit : public virtual_iterator |
|---|
| 51 | { |
|---|
| 52 | db::msg::xref_type::const_iterator it; |
|---|
| 53 | mutable value::const_ptr cur; |
|---|
| 54 | db::user::const_ptr u; |
|---|
| 55 | |
|---|
| 56 | vit(db::msg::xref_type::const_iterator it, |
|---|
| 57 | value::const_ptr cur, |
|---|
| 58 | db::user::const_ptr u) |
|---|
| 59 | : it(it) |
|---|
| 60 | , cur(cur) |
|---|
| 61 | , u(u) |
|---|
| 62 | {} |
|---|
| 63 | public: |
|---|
| 64 | vit(db::msg::xref_type::const_iterator it, |
|---|
| 65 | db::user::const_ptr u) |
|---|
| 66 | : it(it) |
|---|
| 67 | , u(u) |
|---|
| 68 | {} |
|---|
| 69 | virtual_iterator *clone() const { |
|---|
| 70 | return new vit(it, cur, u); |
|---|
| 71 | } |
|---|
| 72 | value::const_ptr get() const { |
|---|
| 73 | if (!cur) cur.reset(new group_value(it->first, |
|---|
| 74 | u)); |
|---|
| 75 | return cur; |
|---|
| 76 | } |
|---|
| 77 | void next() { |
|---|
| 78 | it++; |
|---|
| 79 | cur.reset(); |
|---|
| 80 | } |
|---|
| 81 | bool eq(const virtual_iterator &o_) const { |
|---|
| 82 | const vit *o = dynamic_cast<const vit *>(&o_); |
|---|
| 83 | return o ? it == o->it : false; |
|---|
| 84 | } |
|---|
| 85 | }; |
|---|
| 86 | |
|---|
| 87 | public: |
|---|
| 88 | xref_seq(db::msg::const_ptr m, db::user::const_ptr u) |
|---|
| 89 | : m(m) |
|---|
| 90 | , u(u) |
|---|
| 91 | {} |
|---|
| 92 | const_iterator begin() const { |
|---|
| 93 | return const_iterator |
|---|
| 94 | (new vit(m->get_xref().begin(), u)); |
|---|
| 95 | } |
|---|
| 96 | const_iterator end() const { |
|---|
| 97 | return const_iterator |
|---|
| 98 | (new vit(m->get_xref().end(), u)); |
|---|
| 99 | } |
|---|
| 100 | }; |
|---|
| 101 | |
|---|
| 102 | |
|---|
| 103 | value::ptr mk_msg_value(db::thread_node::const_ptr tr, |
|---|
| 104 | db::user::const_ptr u) |
|---|
| 105 | { |
|---|
| 106 | return msg_value::mk(tr, u); |
|---|
| 107 | } |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | namespace tlate |
|---|
| 111 | { |
|---|
| 112 | msg_value::msg_value(db::thread_node::const_ptr tn, |
|---|
| 113 | db::user::const_ptr u) |
|---|
| 114 | : tn(tn) |
|---|
| 115 | , u(u) |
|---|
| 116 | { |
|---|
| 117 | assert(tn); |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | value::ptr msg_value::mk(db::thread_node::const_ptr tr, |
|---|
| 121 | db::user::const_ptr u) |
|---|
| 122 | { |
|---|
| 123 | if (!tr) return value::ptr(); |
|---|
| 124 | structured_value::ptr rv_(new msg_value(tr, u)); |
|---|
| 125 | value::ptr rv(new lazy_structured_value(rv_)); |
|---|
| 126 | return rv; |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | value::const_ptr msg_value::get(std::string var) const |
|---|
| 130 | { |
|---|
| 131 | using html::quote; |
|---|
| 132 | typedef string_value sv; |
|---|
| 133 | db::msg::const_ptr m = tn->get_article(); |
|---|
| 134 | msg::entity::const_ptr e; |
|---|
| 135 | if (m) e = m->get_entity(); |
|---|
| 136 | std::string msgid = tn->get_msgid(); |
|---|
| 137 | bool rauthz = m ? m->reading_authz(u) : false; |
|---|
| 138 | bool show = rauthz && !m->is_censured(); |
|---|
| 139 | bool authn = u; |
|---|
| 140 | value::const_ptr rv; |
|---|
| 141 | if (var == "id") |
|---|
| 142 | rv.reset(new sv(quote(msgid, false))); |
|---|
| 143 | else if (var == "single-path") |
|---|
| 144 | rv.reset(new sv(quote("/id/" + |
|---|
| 145 | uri::percent_encode(msgid), |
|---|
| 146 | false))); |
|---|
| 147 | else if (var == "atom_path") |
|---|
| 148 | rv.reset(new sv(quote("/feed/thread/" + |
|---|
| 149 | uri::percent_encode(msgid), |
|---|
| 150 | false))); |
|---|
| 151 | else if (var == "thread-path") |
|---|
| 152 | rv.reset(new sv(quote("/thread/" + |
|---|
| 153 | uri::percent_encode(msgid), |
|---|
| 154 | false))); |
|---|
| 155 | else if (var == "followup-allowed" && |
|---|
| 156 | m->posting_authz(u) && show) |
|---|
| 157 | rv.reset(new sv(http::compose::get_followup_uri(m))); |
|---|
| 158 | else if (var == "followup-uri" && show) |
|---|
| 159 | rv.reset(new sv(http::compose::get_followup_uri(m))); |
|---|
| 160 | else if (!rauthz && var == "restricted") |
|---|
| 161 | rv.reset(new empty_value); |
|---|
| 162 | else if (show && m && var == "from") |
|---|
| 163 | rv.reset(new sv(quote(decode_unstructured |
|---|
| 164 | (e->get_field("From", false)), |
|---|
| 165 | !authn))); |
|---|
| 166 | else if (show && m && var == "subject") |
|---|
| 167 | rv.reset(new sv(quote(decode_unstructured |
|---|
| 168 | (e->get_field("Subject", false)), |
|---|
| 169 | !authn))); |
|---|
| 170 | else if (rauthz && m && var == "date") |
|---|
| 171 | rv.reset(new date_value(e->parsed_date())); |
|---|
| 172 | else if (rauthz && var == "latest-date" && |
|---|
| 173 | !tn->get_latest_date().is_special()) |
|---|
| 174 | rv.reset(new date_value((tn->get_latest_date()))); |
|---|
| 175 | |
|---|
| 176 | else if (show && m && var == "header") |
|---|
| 177 | rv.reset(new header_value(e,!u)); |
|---|
| 178 | else if (show && m && var == "body") |
|---|
| 179 | rv = e->get_tlate_value(authn); |
|---|
| 180 | else if (rauthz && m && var == "xref") |
|---|
| 181 | rv.reset(new xref_seq(m, u)); |
|---|
| 182 | else if (rauthz && var == "thread-next") |
|---|
| 183 | rv = msg_value::mk(tn->next(), u); |
|---|
| 184 | else if (rauthz && var == "thread-prev") |
|---|
| 185 | rv = msg_value::mk(tn->previous(), u); |
|---|
| 186 | else if (rauthz && var == "followups") |
|---|
| 187 | rv = seqval(tn->get_children(), |
|---|
| 188 | boost::bind(mk_msg_value, _1, u)); |
|---|
| 189 | else if (rauthz && var == "precursors") |
|---|
| 190 | { |
|---|
| 191 | list_value::ptr ps(new list_value); |
|---|
| 192 | for (db::thread_node::const_ptr it = tn->get_parent(); |
|---|
| 193 | it; it = it->get_parent()) |
|---|
| 194 | { |
|---|
| 195 | ps->push_back(msg_value::mk(it, u)); |
|---|
| 196 | } |
|---|
| 197 | if (!ps->empty()) rv = ps; |
|---|
| 198 | } |
|---|
| 199 | else if (rauthz && var == "thread") |
|---|
| 200 | rv.reset(new sv(quote("/thread/" + |
|---|
| 201 | uri::percent_encode(msgid), |
|---|
| 202 | false))); |
|---|
| 203 | else if (rauthz && var == "thread-count") |
|---|
| 204 | rv.reset(new sv(boost::lexical_cast<std::string> |
|---|
| 205 | (tn->cardinality()))); |
|---|
| 206 | else if (u && var == "marked_read" && u->has_read(msgid)) |
|---|
| 207 | rv.reset(new empty_value); |
|---|
| 208 | else if (u && show && m && var == "poster" && m->get_poster()) |
|---|
| 209 | rv.reset(new user_value(m->get_poster())); |
|---|
| 210 | else if (u && rauthz && m && var == "own" && |
|---|
| 211 | m->get_poster() == u) |
|---|
| 212 | rv.reset(new empty_value); |
|---|
| 213 | else if (rauthz && m->is_censured() && var == "moderated") |
|---|
| 214 | rv.reset(new empty_value); |
|---|
| 215 | else if (rauthz && m && var == "moderator") |
|---|
| 216 | { |
|---|
| 217 | db::user::const_ptr u = m->censor(); |
|---|
| 218 | if (u) rv.reset(new user_value(u)); |
|---|
| 219 | } |
|---|
| 220 | else if (u && m && var == "mod-uri" && u->is_moderator(m)) |
|---|
| 221 | rv.reset(new sv(quote("/mod", false))); |
|---|
| 222 | return rv; |
|---|
| 223 | } |
|---|
| 224 | } |
|---|