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