2 // This is some older code for the forum view that does server-side rendering.
3 // We're keeping it around as a reference.
5 // Copyright (c) 1996-2018 by the citadel.org team
7 // This program is open source software. It runs great on the
8 // Linux operating system (and probably elsewhere). You can use,
9 // copy, and run it under the terms of the GNU General Public
12 // This program 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.
19 // Renderer for one message in the threaded view
20 // (This will probably work for the flat view too.)
22 void forum_render_one_message(struct ctdlsession *c, StrBuf * sj, long msgnum)
24 StrBuf *raw_msg = NULL;
25 StrBuf *sanitized_msg = NULL;
27 char content_transfer_encoding[1024] = { 0 };
28 char content_type[1024] = { 0 };
29 char author[128] = { 0 };
30 char datetime[128] = { 0 };
32 ctdl_printf(c, "MSG4 %ld", msgnum);
33 ctdl_readline(c, buf, sizeof(buf));
35 StrBufAppendPrintf(sj, "<div>ERROR CONDITION FIXME WRITE A BOX</div>");
39 while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "text")) && (strcmp(buf, "000"))) {
40 // citadel header parsing here
41 if (!strncasecmp(buf, "from=", 5)) {
42 safestrncpy(author, &buf[5], sizeof author);
44 if (!strncasecmp(buf, "time=", 5)) {
48 localtime_r(&tt, &tm);
49 strftime(datetime, sizeof datetime, "%c", &tm);
53 if (!strcmp(buf, "text")) {
54 while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "")) && (strcmp(buf, "000"))) {
55 // rfc822 header parsing here
56 if (!strncasecmp(buf, "Content-transfer-encoding:", 26)) {
57 strcpy(content_transfer_encoding, &buf[26]);
58 striplt(content_transfer_encoding);
60 if (!strncasecmp(buf, "Content-type:", 13)) {
61 strcpy(content_type, &buf[13]);
62 striplt(content_type);
65 raw_msg = ctdl_readtextmsg(c);
72 StrBufAppendPrintf(sj, "<div>"); // begin message wrapper
73 StrBufAppendPrintf(sj, "<div style=\"float:left;padding-right:2px\">"); // begin avatar FIXME move the style to a stylesheet
74 StrBufAppendPrintf(sj, "<i class=\"fa fa-user-circle fa-2x\"></i> "); // FIXME temporary avatar
75 StrBufAppendPrintf(sj, "</div>"); // end avatar
76 StrBufAppendPrintf(sj, "<div>"); // begin content
77 StrBufAppendPrintf(sj, "<div>"); // begin header
78 StrBufAppendPrintf(sj, "<span class=\"ctdl-username\"><a href=\"#\">%s</a></span> ", author); // FIXME link to user profile or whatever
79 StrBufAppendPrintf(sj, "<span class=\"ctdl-msgdate\">%s</span> ", datetime);
80 StrBufAppendPrintf(sj, "</div>"); // end header
81 StrBufAppendPrintf(sj, "<div>"); // begin body
85 // These are the encodings we know how to handle. Decode in-place.
87 if (!strcasecmp(content_transfer_encoding, "base64")) {
88 StrBufDecodeBase64(raw_msg);
90 if (!strcasecmp(content_transfer_encoding, "quoted-printable")) {
91 StrBufDecodeQP(raw_msg);
93 // At this point, raw_msg contains the decoded message.
94 // Now run through the renderers we have available.
96 if (!strncasecmp(content_type, "text/html", 9)) {
97 sanitized_msg = html2html("UTF-8", 0, c->room, msgnum, raw_msg);
98 } else if (!strncasecmp(content_type, "text/plain", 10)) {
99 sanitized_msg = text2html("UTF-8", 0, c->room, msgnum, raw_msg);
100 } else if (!strncasecmp(content_type, "text/x-citadel-variformat", 25)) {
101 sanitized_msg = variformat2html(raw_msg);
103 sanitized_msg = NewStrBufPlain(HKEY("<i>No renderer for this content type</i><br>"));
105 FreeStrBuf(&raw_msg);
107 // If sanitized_msg is not NULL, we have rendered the message and can output it.
110 StrBufAppendBuf(sj, sanitized_msg, 0);
111 FreeStrBuf(&sanitized_msg);
115 StrBufAppendPrintf(sj, "</div>"); // end body
116 StrBufAppendPrintf(sj, "</div>"); // end content
117 StrBufAppendPrintf(sj, "</div>"); // end wrapper
121 // This code implements the thread display code. The thread sorting algorithm is working nicely but we're trying
122 // not to do rendering in the C server of webcit. Maybe move it into the server as "MSGS threaded" or something like that?
124 // Threaded view (recursive section)
126 void thread_o_print(struct ctdlsession *c, StrBuf * sj, struct mthread *m, int num_msgs, int where_parent_is, int nesting_level)
132 for (i = 0; i < num_msgs; ++i) {
133 if (m[i].parent == where_parent_is) {
135 if (++num_printed == 1) {
136 StrBufAppendPrintf(sj, "<ul style=\"list-style-type: none;\">");
139 StrBufAppendPrintf(sj, "<li class=\"post\" id=\"post-%ld\">", m[i].msgnum);
140 forum_render_one_message(c, sj, m[i].msgnum);
141 StrBufAppendPrintf(sj, "</li>\r\n");
143 thread_o_print(c, sj, m, num_msgs, i, nesting_level + 1);
148 if (num_printed > 0) {
149 StrBufAppendPrintf(sj, "</ul>");
154 // Threaded view (entry point)
156 void threaded_view(struct http_transaction *h, struct ctdlsession *c, char *which)
165 ctdl_printf(c, "MSGS ALL|||9"); // 9 == headers + thread references
166 ctdl_readline(c, buf, sizeof(buf));
172 StrBuf *sj = NewStrBuf();
173 StrBufAppendPrintf(sj, "<html><body>\r\n");
175 while (ctdl_readline(c, buf, sizeof buf), strcmp(buf, "000")) {
178 if (num_msgs > num_alloc) {
179 if (num_alloc == 0) {
181 m = malloc(num_alloc * sizeof(struct mthread));
184 m = realloc(m, (num_alloc * sizeof(struct mthread)));
188 memset(&m[num_msgs - 1], 0, sizeof(struct mthread));
189 m[num_msgs - 1].msgnum = extract_long(buf, 0);
190 m[num_msgs - 1].datetime = extract_long(buf, 1);
191 extract_token(m[num_msgs - 1].from, buf, 2, '|', sizeof m[num_msgs - 1].from);
192 m[num_msgs - 1].threadhash = extract_int(buf, 6);
193 extract_token(refs, buf, 7, '|', sizeof refs);
198 while ((t = strtok_r(r, ",", &r))) {
200 m[num_msgs - 1].refhashes[0] = atoi(t); // always keep the first one
202 memcpy(&m[num_msgs - 1].refhashes[1], &m[num_msgs - 1].refhashes[2], sizeof(int) * 8); // shift the rest
203 m[num_msgs - 1].refhashes[9] = atoi(t);
210 // Sort by thread. I did read jwz's sorting algorithm and it looks pretty good, but jwz is a self-righteous asshole so we do it our way.
211 for (i = 0; i < num_msgs; ++i) {
212 for (j = 9; (j >= 0) && (m[i].parent == 0); --j) {
213 for (k = 0; (k < num_msgs) && (m[i].parent == 0); ++k) {
214 if (m[i].refhashes[j] == m[k].threadhash) {
222 setup_for_forum_view(c);
223 thread_o_print(c, sj, m, num_msgs, 0, 0); // Render threads recursively and recursively
225 // Garbage collection is for people who aren't smart enough to manage their own memory.
230 StrBufAppendPrintf(sj, "</body></html>\r\n");
232 add_response_header(h, strdup("Content-type"), strdup("text/html; charset=utf-8"));
233 h->response_code = 200;
234 h->response_string = strdup("OK");
235 h->response_body_length = StrLength(sj);
236 h->response_body = SmashStrBuf(&sj);
241 // flat view (entry point)
243 void flat_view(struct http_transaction *h, struct ctdlsession *c, char *which)
245 StrBuf *sj = NewStrBuf();
246 StrBufAppendPrintf(sj, "<html><body>\r\n");
248 setup_for_forum_view(c);
249 long *msglist = get_msglist(c, "ALL");
252 for (i = 0; (msglist[i] > 0); ++i) {
253 forum_render_one_message(c, sj, msglist[i]);
258 StrBufAppendPrintf(sj, "</body></html>\r\n");
260 add_response_header(h, strdup("Content-type"), strdup("text/html; charset=utf-8"));
261 h->response_code = 200;
262 h->response_string = strdup("OK");
263 h->response_body_length = StrLength(sj);
264 h->response_body = SmashStrBuf(&sj);
269 // render one message (entire transaction) FIXME EXTERMINATE
271 void html_render_one_message(struct http_transaction *h, struct ctdlsession *c, long msgnum)
273 StrBuf *sj = NewStrBuf();
274 StrBufAppendPrintf(sj, "<html><body>\r\n");
275 setup_for_forum_view(c); // FIXME way too inefficient to do this for every message !!!!!!!!!!!!!
276 forum_render_one_message(c, sj, msgnum);
277 StrBufAppendPrintf(sj, "</body></html>\r\n");
278 add_response_header(h, strdup("Content-type"), strdup("text/html; charset=utf-8"));
279 h->response_code = 200;
280 h->response_string = strdup("OK");
281 h->response_body_length = StrLength(sj);
282 h->response_body = SmashStrBuf(&sj);