1 // Forum view (threaded/flat)
3 // Copyright (c) 1996-2022 by the citadel.org team
5 // This program is open source software. It runs great on the
6 // Linux operating system (and probably elsewhere). You can use,
7 // copy, and run it under the terms of the GNU General Public
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
17 // Commands we need to send to Citadel Server before we begin rendering forum view.
18 // These are common to flat and threaded views.
19 void setup_for_forum_view(struct ctdlsession *c) {
21 ctdl_printf(c, "MSGP text/html|text/plain"); // Declare the MIME types we know how to render
22 ctdl_readline(c, buf, sizeof(buf)); // Ignore the response
23 ctdl_printf(c, "MSGP dont_decode"); // Tell the server we will decode base64/etc client-side
24 ctdl_readline(c, buf, sizeof(buf)); // Ignore the response
28 // Fetch a single message and return it in JSON format for client-side rendering
29 void json_render_one_message(struct http_transaction *h, struct ctdlsession *c, long msgnum) {
30 StrBuf *raw_msg = NULL;
31 StrBuf *sanitized_msg = NULL;
33 char content_transfer_encoding[1024] = { 0 };
34 char content_type[1024] = { 0 };
35 char datetime[128] = { 0 };
36 char author[1024] = { 0 };
37 char emailaddr[1024] = { 0 };
38 int message_originated_locally = 0;
40 setup_for_forum_view(c);
42 ctdl_printf(c, "MSG4 %ld", msgnum);
43 ctdl_readline(c, buf, sizeof(buf));
49 JsonValue *j = NewJsonObject(HKEY("message"));
51 while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "text")) && (strcmp(buf, "000"))) {
53 // citadel header parsing here
54 if (!strncasecmp(buf, "from=", 5)) {
55 safestrncpy(author, &buf[5], sizeof author);
57 else if (!strncasecmp(buf, "rfca=", 5)) {
58 safestrncpy(emailaddr, &buf[5], sizeof emailaddr);
60 else if (!strncasecmp(buf, "time=", 5)) {
64 localtime_r(&tt, &tm);
65 strftime(datetime, sizeof datetime, "%c", &tm);
66 JsonObjectAppend(j, NewJsonPlainString(HKEY("time"), datetime, -1));
68 else if (!strncasecmp(buf, "locl=", 5)) {
69 message_originated_locally = 1;
71 else if (!strncasecmp(buf, "subj=", 5)) {
72 JsonObjectAppend(j, NewJsonPlainString(HKEY("subj"), &buf[5], -1));
74 else if (!strncasecmp(buf, "msgn=", 5)) {
75 JsonObjectAppend(j, NewJsonPlainString(HKEY("msgn"), &buf[5], -1));
77 else if (!strncasecmp(buf, "wefw=", 5)) {
78 JsonObjectAppend(j, NewJsonPlainString(HKEY("wefw"), &buf[5], -1));
82 if (message_originated_locally) {
83 JsonObjectAppend(j, NewJsonPlainString(HKEY("from"), author, -1));
86 JsonObjectAppend(j, NewJsonPlainString(HKEY("from"), emailaddr, -1)); // FIXME do the compound address string
89 if (!strcmp(buf, "text")) {
90 while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "")) && (strcmp(buf, "000"))) {
91 // rfc822 header parsing here
92 if (!strncasecmp(buf, "Content-transfer-encoding:", 26)) {
93 strcpy(content_transfer_encoding, &buf[26]);
94 striplt(content_transfer_encoding);
96 if (!strncasecmp(buf, "Content-type:", 13)) {
97 strcpy(content_type, &buf[13]);
98 striplt(content_type);
101 raw_msg = ctdl_readtextmsg(c);
108 // These are the encodings we know how to handle. Decode in-place.
110 if (!strcasecmp(content_transfer_encoding, "base64")) {
111 StrBufDecodeBase64(raw_msg);
113 if (!strcasecmp(content_transfer_encoding, "quoted-printable")) {
114 StrBufDecodeQP(raw_msg);
117 // At this point, raw_msg contains the decoded message.
118 // Now run through the renderers we have available.
120 if (!strncasecmp(content_type, "text/html", 9)) {
121 sanitized_msg = html2html("UTF-8", 0, c->room, msgnum, raw_msg);
123 else if (!strncasecmp(content_type, "text/plain", 10)) {
124 sanitized_msg = text2html("UTF-8", 0, c->room, msgnum, raw_msg);
126 else if (!strncasecmp(content_type, "text/x-citadel-variformat", 25)) {
127 sanitized_msg = variformat2html(raw_msg);
130 sanitized_msg = NewStrBufPlain(HKEY("<i>No renderer for this content type</i><br>"));
131 syslog(LOG_WARNING, "forum_view: no renderer for content type %s", content_type);
133 FreeStrBuf(&raw_msg);
135 // If sanitized_msg is not NULL, we have rendered the message and can output it.
137 JsonObjectAppend(j, NewJsonString(HKEY("text"), sanitized_msg, NEWJSONSTRING_SMASHBUF));
140 syslog(LOG_WARNING, "forum_view: message %ld of content type %s converted to NULL", msgnum, content_type);
144 StrBuf *sj = NewStrBuf();
145 SerializeJson(sj, j, 1); // '1' == free the source object
147 add_response_header(h, strdup("Content-type"), strdup("application/json"));
148 h->response_code = 200;
149 h->response_string = strdup("OK");
150 h->response_body_length = StrLength(sj);
151 h->response_body = SmashStrBuf(&sj);