2 * Threaded message view
4 * Copyright (c) 1996-2017 by the citadel.org team
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.
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.
27 // Renderer for one message in the threaded view
28 void thread_render_one_message(struct ctdlsession *c, StrBuf *sj, 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 };
36 ctdl_printf(c, "MSG4 %ld", msgnum);
37 ctdl_readline(c, buf, sizeof(buf));
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 StrBufAppendPrintf(sj, "<b>From %s</b><br>", &buf[5]); // FIXME that was temporary
44 if (!strncasecmp(buf, "part=", 5)) {
45 //StrBufAppendPrintf(sj, "MIME part: %s<br>", &buf[5]); // FIXME that was temporary
48 if (!strcmp(buf, "text")) {
49 while ( (ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "")) && (strcmp(buf, "000")) ) {
50 // rfc822 header parsing here
51 if (!strncasecmp(buf, "Content-transfer-encoding:", 26)) {
52 strcpy(content_transfer_encoding, &buf[26]);
53 striplt(content_transfer_encoding);
55 if (!strncasecmp(buf, "Content-type:", 13)) {
56 strcpy(content_type, &buf[13]);
57 striplt(content_type);
58 //StrBufAppendPrintf(sj, "Content-type: %s<br>", content_type); // FIXME that was temporary
61 raw_msg = ctdl_readtextmsg(c);
67 if (!strcasecmp(content_transfer_encoding, "base64")) {
68 StrBufDecodeBase64(raw_msg);
70 if (!strcasecmp(content_transfer_encoding, "quoted-printable")) {
71 StrBufDecodeQP(raw_msg);
73 if (!strncasecmp(content_type, "text/html", 9)) {
74 sanitized_msg = html2html("UTF-8", 0, c->room, msgnum, raw_msg);
76 else if (!strncasecmp(content_type, "text/plain", 10)) {
77 sanitized_msg = text2html("UTF-8", 0, c->room, msgnum, raw_msg);
79 else if (!strncasecmp(content_type, "text/x-citadel-variformat", 25)) {
80 sanitized_msg = variformat2html(raw_msg);
83 sanitized_msg = NewStrBufPlain(HKEY("<i>No renderer for this content type</i><br>"));
85 //sanitized_msg = NewStrBufDup(raw_msg);
88 StrBufAppendBuf(sj, sanitized_msg, 0);
89 FreeStrBuf(&sanitized_msg);
96 void thread_o_print(struct ctdlsession *c, StrBuf *sj, struct mthread *m, int num_msgs, int where_parent_is, int nesting_level)
102 for (i=0; i<num_msgs; ++i) {
103 if (m[i].parent == where_parent_is) {
105 if (++num_printed == 1) {
106 StrBufAppendPrintf(sj, "<ul>");
107 StrBufAppendPrintf(sj, "<table style=\"border: 1px solid black;\"><tr><td>"); // temporary, for visualization
110 //for (j=nesting_level; j>0; --j) {
111 //StrBufAppendPrintf(sj, " ");
114 StrBufAppendPrintf(sj, "<li class=\"post\" id=\"post-%ld\">", m[i].msgnum);
115 thread_render_one_message(c, sj, m[i].msgnum);
116 StrBufAppendPrintf(sj, "</li>\r\n");
118 thread_o_print(c, sj, m, num_msgs, i, nesting_level+1);
123 if (num_printed > 0) {
124 StrBufAppendPrintf(sj, "</td></tr></table>"); // temporary, for visualization
125 StrBufAppendPrintf(sj, "</ul>");
131 void threaded_view(struct http_transaction *h, struct ctdlsession *c, char *which)
140 ctdl_printf(c, "MSGS ALL|||9"); // 9 == headers + thread references
141 ctdl_readline(c, buf, sizeof(buf));
147 StrBuf *sj = NewStrBuf();
148 StrBufAppendPrintf(sj, "<html><body>\r\n");
150 while (ctdl_readline(c, buf, sizeof buf), strcmp(buf,"000")) {
153 if (num_msgs > num_alloc) {
154 if (num_alloc == 0) {
156 m = malloc(num_alloc * sizeof(struct mthread));
160 m = realloc(m, (num_alloc * sizeof(struct mthread)));
164 memset(&m[num_msgs-1], 0, sizeof(struct mthread));
165 m[num_msgs-1].msgnum = extract_long(buf, 0);
166 m[num_msgs-1].datetime = extract_long(buf, 1);
167 extract_token(m[num_msgs-1].from, buf, 2, '|', sizeof m[num_msgs-1].from);
168 m[num_msgs-1].threadhash = extract_int(buf, 6);
169 extract_token(refs, buf, 7, '|', sizeof refs);
174 while ((t = strtok_r(r, ",", &r))) {
176 m[num_msgs-1].refhashes[0] = atoi(t); // always keep the first one
179 memcpy(&m[num_msgs-1].refhashes[1], &m[num_msgs-1].refhashes[2], sizeof(int)*8 ); // shift the rest
180 m[num_msgs-1].refhashes[9] = atoi(t);
187 // 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.
188 for (i=0; i<num_msgs; ++i) {
189 for (j=9; (j>=0)&&(m[i].parent==0); --j) {
190 for (k=0; (k<num_msgs)&&(m[i].parent==0); ++k) {
191 if (m[i].refhashes[j] == m[k].threadhash) {
199 ctdl_printf(c, "MSGP text/html|text/plain"); // Declare the MIME types we know how to render
200 ctdl_readline(c, buf, sizeof(buf)); // Ignore the response
201 ctdl_printf(c, "MSGP dont_decode"); // Tell the server we will decode base64/etc client-side
202 ctdl_readline(c, buf, sizeof(buf)); // Ignore the response
203 thread_o_print(c, sj, m, num_msgs, 0, 0); // Render threads recursively and recursively
210 StrBufAppendPrintf(sj, "</body></html>\r\n");
212 add_response_header(h, strdup("Content-type"), strdup("text/html; charset=utf-8"));
213 h->response_code = 200;
214 h->response_string = strdup("OK");
215 h->response_body_length = StrLength(sj);
216 h->response_body = SmashStrBuf(&sj);