a0300064a77e0c246161bcab6c55c82fe585f442
[citadel.git] / webcit-ng / forum_view.c
1 /*
2  * Forum view (threaded/flat)
3  *
4  * Copyright (c) 1996-2018 by the citadel.org team
5  *
6  * This program is open source software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include "webcit.h"
16
17 struct mthread {
18         long msgnum;
19         time_t datetime;
20         int threadhash;
21         int refhashes[10];
22         char from[64];
23         int parent;
24 };
25
26
27 // Commands we need to send to Citadel Server before we begin rendering forum view.
28 // These are common to flat and threaded views.
29 //
30 void setup_for_forum_view(struct ctdlsession *c)
31 {
32         char buf[1024];
33         ctdl_printf(c, "MSGP text/html|text/plain");    // Declare the MIME types we know how to render
34         ctdl_readline(c, buf, sizeof(buf));             // Ignore the response
35         ctdl_printf(c, "MSGP dont_decode");             // Tell the server we will decode base64/etc client-side
36         ctdl_readline(c, buf, sizeof(buf));             // Ignore the response
37 }
38
39
40 // Fetch a single message and return it in JSON format for client-side rendering
41 //
42 void json_render_one_message(struct http_transaction *h, struct ctdlsession *c, long msgnum)
43 {
44         StrBuf *raw_msg = NULL;
45         StrBuf *sanitized_msg = NULL;
46         char buf[1024];
47         char content_transfer_encoding[1024] = { 0 };
48         char content_type[1024] = { 0 };
49         char author[128] = { 0 };
50         char datetime[128] = { 0 };
51
52         setup_for_forum_view(c);
53
54         ctdl_printf(c, "MSG4 %ld", msgnum);
55         ctdl_readline(c, buf, sizeof(buf));
56         if (buf[0] != '1') {
57                 do_404(h);
58                 return;
59         }
60
61         JsonValue *j = NewJsonObject(HKEY("message"));
62
63         while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "text")) && (strcmp(buf, "000"))) {
64                 // citadel header parsing here
65                 if (!strncasecmp(buf, "from=", 5)) {
66                         JsonObjectAppend(j, NewJsonPlainString(HKEY("from"), &buf[5], -1));
67                 }
68                 if (!strncasecmp(buf, "rfca=", 5)) {
69                         JsonObjectAppend(j, NewJsonPlainString(HKEY("from"), &buf[5], -1));
70                 }
71                 if (!strncasecmp(buf, "time=", 5)) {
72                         time_t tt;
73                         struct tm tm;
74                         tt = atol(&buf[5]);
75                         localtime_r(&tt, &tm);
76                         strftime(datetime, sizeof datetime, "%c", &tm);
77                         JsonObjectAppend(j, NewJsonPlainString(HKEY("time"), datetime, -1));
78                 }
79         }
80
81         if (!strcmp(buf, "text")) {
82                 while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "")) && (strcmp(buf, "000"))) {
83                         // rfc822 header parsing here
84                         if (!strncasecmp(buf, "Content-transfer-encoding:", 26)) {
85                                 strcpy(content_transfer_encoding, &buf[26]);
86                                 striplt(content_transfer_encoding);
87                         }
88                         if (!strncasecmp(buf, "Content-type:", 13)) {
89                                 strcpy(content_type, &buf[13]);
90                                 striplt(content_type);
91                         }
92                 }
93                 raw_msg = ctdl_readtextmsg(c);
94         } else {
95                 raw_msg = NULL;
96         }
97
98         if (raw_msg) {
99
100                 // These are the encodings we know how to handle.  Decode in-place.
101
102                 if (!strcasecmp(content_transfer_encoding, "base64")) {
103                         StrBufDecodeBase64(raw_msg);
104                 }
105                 if (!strcasecmp(content_transfer_encoding, "quoted-printable")) {
106                         StrBufDecodeQP(raw_msg);
107                 }
108                 // At this point, raw_msg contains the decoded message.
109                 // Now run through the renderers we have available.
110
111                 if (!strncasecmp(content_type, "text/html", 9)) {
112                         sanitized_msg = html2html("UTF-8", 0, c->room, msgnum, raw_msg);
113                 } else if (!strncasecmp(content_type, "text/plain", 10)) {
114                         sanitized_msg = text2html("UTF-8", 0, c->room, msgnum, raw_msg);
115                 } else if (!strncasecmp(content_type, "text/x-citadel-variformat", 25)) {
116                         sanitized_msg = variformat2html(raw_msg);
117                 } else {
118                         sanitized_msg = NewStrBufPlain(HKEY("<i>No renderer for this content type</i><br>"));
119                 }
120                 FreeStrBuf(&raw_msg);
121
122                 // If sanitized_msg is not NULL, we have rendered the message and can output it.
123
124                 if (sanitized_msg) {
125                         JsonObjectAppend(j, NewJsonString(HKEY("text"), sanitized_msg, NEWJSONSTRING_SMASHBUF));
126                 }
127         }
128
129         StrBuf *sj = NewStrBuf();
130         SerializeJson(sj, j, 1);        // '1' == free the source object
131
132         add_response_header(h, strdup("Content-type"), strdup("application/json"));
133         h->response_code = 200;
134         h->response_string = strdup("OK");
135         h->response_body_length = StrLength(sj);
136         h->response_body = SmashStrBuf(&sj);
137 }