X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit-ng%2Fforum_view.c;h=71d7b09116414db01d9ecb98d4d834b009a906e8;hb=91bc31f50a6d93ad0c01d24e29e61a3f5b972cba;hp=7745e019e199c7a5391f9ea92c172ad4fb713ecb;hpb=32fe7887a4fc68e8148f79c4b9ec35ffbb2442d7;p=citadel.git diff --git a/webcit-ng/forum_view.c b/webcit-ng/forum_view.c index 7745e019e..71d7b0911 100644 --- a/webcit-ng/forum_view.c +++ b/webcit-ng/forum_view.c @@ -1,16 +1,17 @@ -/* - * Forum view (threaded/flat) - * - * Copyright (c) 1996-2018 by the citadel.org team - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// +// Forum view (threaded/flat) +// +// Copyright (c) 1996-2020 by the citadel.org team +// +// This program is open source software. It runs great on the +// Linux operating system (and probably elsewhere). You can use, +// copy, and run it under the terms of the GNU General Public +// License version 3. Richard Stallman is an asshole communist. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "webcit.h" @@ -24,42 +25,75 @@ struct mthread { }; -// Renderer for one message in the threaded view -// (This will probably work for the flat view too.) +// Commands we need to send to Citadel Server before we begin rendering forum view. +// These are common to flat and threaded views. +// +void setup_for_forum_view(struct ctdlsession *c) +{ + char buf[1024]; + ctdl_printf(c, "MSGP text/html|text/plain"); // Declare the MIME types we know how to render + ctdl_readline(c, buf, sizeof(buf)); // Ignore the response + ctdl_printf(c, "MSGP dont_decode"); // Tell the server we will decode base64/etc client-side + ctdl_readline(c, buf, sizeof(buf)); // Ignore the response +} + + +// Fetch a single message and return it in JSON format for client-side rendering // -void forum_render_one_message(struct ctdlsession *c, StrBuf *sj, long msgnum) +void json_render_one_message(struct http_transaction *h, struct ctdlsession *c, long msgnum) { StrBuf *raw_msg = NULL; StrBuf *sanitized_msg = NULL; char buf[1024]; char content_transfer_encoding[1024] = { 0 }; char content_type[1024] = { 0 }; - char author[128] = { 0 }; - char datetime[128] = { 0 } ; + char datetime[128] = { 0 }; + char author[1024] = { 0 }; + char emailaddr[1024] = { 0 }; + int message_originated_locally = 0; + + setup_for_forum_view(c); ctdl_printf(c, "MSG4 %ld", msgnum); ctdl_readline(c, buf, sizeof(buf)); if (buf[0] != '1') { - StrBufAppendPrintf(sj, "
ERROR CONDITION FIXME WRITE A BOX
"); + do_404(h); return; } - while ( (ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "text")) && (strcmp(buf, "000")) ) { + JsonValue *j = NewJsonObject(HKEY("message")); + + while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "text")) && (strcmp(buf, "000"))) { + // citadel header parsing here if (!strncasecmp(buf, "from=", 5)) { safestrncpy(author, &buf[5], sizeof author); } - if (!strncasecmp(buf, "time=", 5)) { + else if (!strncasecmp(buf, "rfca=", 5)) { + safestrncpy(emailaddr, &buf[5], sizeof emailaddr); + } + else if (!strncasecmp(buf, "time=", 5)) { time_t tt; struct tm tm; tt = atol(&buf[5]); localtime_r(&tt, &tm); strftime(datetime, sizeof datetime, "%c", &tm); + JsonObjectAppend(j, NewJsonPlainString(HKEY("time"), datetime, -1)); + } + else if (!strncasecmp(buf, "locl=", 5)) { + message_originated_locally = 1; } } + if (message_originated_locally) { + JsonObjectAppend(j, NewJsonPlainString(HKEY("from"), author, -1)); + } + else { + JsonObjectAppend(j, NewJsonPlainString(HKEY("from"), emailaddr, -1)); // FIXME do the compound address string + } + if (!strcmp(buf, "text")) { - while ( (ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "")) && (strcmp(buf, "000")) ) { + while ((ctdl_readline(c, buf, sizeof(buf)) >= 0) && (strcmp(buf, "")) && (strcmp(buf, "000"))) { // rfc822 header parsing here if (!strncasecmp(buf, "Content-transfer-encoding:", 26)) { strcpy(content_transfer_encoding, &buf[26]); @@ -71,26 +105,11 @@ void forum_render_one_message(struct ctdlsession *c, StrBuf *sj, long msgnum) } } raw_msg = ctdl_readtextmsg(c); - } - else { + } else { raw_msg = NULL; } - // begin output - - StrBufAppendPrintf(sj, "
"); // begin message wrapper - StrBufAppendPrintf(sj, "
"); // begin avatar FIXME move the style to a stylesheet - StrBufAppendPrintf(sj, " "); // FIXME temporary avatar - StrBufAppendPrintf(sj, "
"); // end avatar - StrBufAppendPrintf(sj, "
"); // begin content - StrBufAppendPrintf(sj, "
"); // begin header - StrBufAppendPrintf(sj, "%s ", author); // FIXME link to user profile or whatever - StrBufAppendPrintf(sj, "%s ", datetime); - StrBufAppendPrintf(sj, "
"); // end header - StrBufAppendPrintf(sj, "
"); // begin body - if (raw_msg) { - // These are the encodings we know how to handle. Decode in-place. if (!strcasecmp(content_transfer_encoding, "base64")) { @@ -114,181 +133,25 @@ void forum_render_one_message(struct ctdlsession *c, StrBuf *sj, long msgnum) } else { sanitized_msg = NewStrBufPlain(HKEY("No renderer for this content type
")); + syslog(LOG_WARNING, "forum_view: no renderer for content type %s", content_type); } FreeStrBuf(&raw_msg); // If sanitized_msg is not NULL, we have rendered the message and can output it. - if (sanitized_msg) { - StrBufAppendBuf(sj, sanitized_msg, 0); - FreeStrBuf(&sanitized_msg); - } - } - - StrBufAppendPrintf(sj, "
"); // end body - StrBufAppendPrintf(sj, "
"); // end content - StrBufAppendPrintf(sj, "
"); // end wrapper -} - - -// Commands we need to send to Citadel Server before we begin rendering forum view. -// These are common to flat and threaded views. -// -void setup_for_forum_view(struct ctdlsession *c) -{ - char buf[1024]; - ctdl_printf(c, "MSGP text/html|text/plain"); // Declare the MIME types we know how to render - ctdl_readline(c, buf, sizeof(buf)); // Ignore the response - ctdl_printf(c, "MSGP dont_decode"); // Tell the server we will decode base64/etc client-side - ctdl_readline(c, buf, sizeof(buf)); // Ignore the response -} - - -// Threaded view (recursive section) -// -void thread_o_print(struct ctdlsession *c, StrBuf *sj, struct mthread *m, int num_msgs, int where_parent_is, int nesting_level) -{ - int i = 0; - int j = 0; - int num_printed = 0; - - for (i=0; i"); - } - - StrBufAppendPrintf(sj, "
  • ", m[i].msgnum); - forum_render_one_message(c, sj, m[i].msgnum); - StrBufAppendPrintf(sj, "
  • \r\n"); - if (i != 0) { - thread_o_print(c, sj, m, num_msgs, i, nesting_level+1); - } + JsonObjectAppend(j, NewJsonString(HKEY("text"), sanitized_msg, NEWJSONSTRING_SMASHBUF)); } - } - - if (num_printed > 0) { - StrBufAppendPrintf(sj, ""); - } -} - -#if 0 - -// Threaded view (entry point) -// -void threaded_view(struct http_transaction *h, struct ctdlsession *c, char *which) -{ - int num_msgs = 0; - int num_alloc = 0; - struct mthread *m; - char buf[1024]; - char refs[1024]; - int i, j, k; - - ctdl_printf(c, "MSGS ALL|||9"); // 9 == headers + thread references - ctdl_readline(c, buf, sizeof(buf)); - if (buf[0] != '1') { - do_404(h); - return; - } - - StrBuf *sj = NewStrBuf(); - StrBufAppendPrintf(sj, "\r\n"); - - while (ctdl_readline(c, buf, sizeof buf), strcmp(buf,"000")) { - - ++num_msgs; - if (num_msgs > num_alloc) { - if (num_alloc == 0) { - num_alloc = 100; - m = malloc(num_alloc * sizeof(struct mthread)); - } - else { - num_alloc *= 2; - m = realloc(m, (num_alloc * sizeof(struct mthread))); - } - } - - memset(&m[num_msgs-1], 0, sizeof(struct mthread)); - m[num_msgs-1].msgnum = extract_long(buf, 0); - m[num_msgs-1].datetime = extract_long(buf, 1); - extract_token(m[num_msgs-1].from, buf, 2, '|', sizeof m[num_msgs-1].from); - m[num_msgs-1].threadhash = extract_int(buf, 6); - extract_token(refs, buf, 7, '|', sizeof refs); - - char *t; - char *r = refs; - i = 0; - while ((t = strtok_r(r, ",", &r))) { - if (i == 0) { - m[num_msgs-1].refhashes[0] = atoi(t); // always keep the first one - } - else { - memcpy(&m[num_msgs-1].refhashes[1], &m[num_msgs-1].refhashes[2], sizeof(int)*8 ); // shift the rest - m[num_msgs-1].refhashes[9] = atoi(t); - } - ++i; - } - - } - - // 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. - for (i=0; i=0)&&(m[i].parent==0); --j) { - for (k=0; (k 0) { - free(m); - } - - StrBufAppendPrintf(sj, "\r\n"); - - add_response_header(h, strdup("Content-type"), strdup("text/html; charset=utf-8")); - h->response_code = 200; - h->response_string = strdup("OK"); - h->response_body_length = StrLength(sj); - h->response_body = SmashStrBuf(&sj); - return; -} - - -// flat view (entry point) -// -void flat_view(struct http_transaction *h, struct ctdlsession *c, char *which) -{ StrBuf *sj = NewStrBuf(); - StrBufAppendPrintf(sj, "\r\n"); + SerializeJson(sj, j, 1); // '1' == free the source object - setup_for_forum_view(c); - long *msglist = get_msglist(c, "ALL"); - if (msglist) { - int i; - for (i=0; (msglist[i] > 0); ++i) { - forum_render_one_message(c, sj, msglist[i]); - } - free(msglist); - } - - StrBufAppendPrintf(sj, "\r\n"); - - add_response_header(h, strdup("Content-type"), strdup("text/html; charset=utf-8")); + add_response_header(h, strdup("Content-type"), strdup("application/json")); h->response_code = 200; h->response_string = strdup("OK"); h->response_body_length = StrLength(sj); h->response_body = SmashStrBuf(&sj); - return; } - -#endif