initial work on flat view
authorArt Cancro <ajc@citadel.org>
Tue, 30 Jan 2018 05:20:32 +0000 (00:20 -0500)
committerArt Cancro <ajc@citadel.org>
Tue, 30 Jan 2018 05:20:32 +0000 (00:20 -0500)
webcit-ng/Makefile
webcit-ng/forum_view.c [new file with mode: 0644]
webcit-ng/room_functions.c
webcit-ng/static/index.html
webcit-ng/static/js/views.js
webcit-ng/threaded_view.c [deleted file]
webcit-ng/webcit.h

index d1519e0a777c351a6e860c7cbb032c663ebd88c7..4182603c1fa41a2451b2784764754d0097913918 100644 (file)
@@ -1,4 +1,4 @@
-OBJS := http.o main.o request.o ssl.o static.o tcp_sockets.o webserver.o ctdlclient.o admin_functions.o room_functions.o util.o caldav_reports.o messages.o ctdlfunctions.o ctdl_commands.o threaded_view.o html2html.o text2html.o
+OBJS := http.o main.o request.o ssl.o static.o tcp_sockets.o webserver.o ctdlclient.o admin_functions.o room_functions.o util.o caldav_reports.o messages.o ctdlfunctions.o ctdl_commands.o forum_view.o html2html.o text2html.o
 CFLAGS := -ggdb
 LDFLAGS := 
 
diff --git a/webcit-ng/forum_view.c b/webcit-ng/forum_view.c
new file mode 100644 (file)
index 0000000..995a6e1
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+
+#include "webcit.h"
+
+struct mthread {
+       long msgnum;
+       time_t datetime;
+       int threadhash;
+       int refhashes[10];
+       char from[64];
+       int parent;
+};
+
+
+// Renderer for one message in the threaded view
+// (This will probably work for the flat view too.)
+//
+void forum_render_one_message(struct ctdlsession *c, StrBuf *sj, 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 } ;
+
+       ctdl_printf(c, "MSG4 %ld", msgnum);
+       ctdl_readline(c, buf, sizeof(buf));
+       if (buf[0] != '1') {
+               StrBufAppendPrintf(sj, "<div>ERROR CONDITION FIXME WRITE A BOX</div>");
+               return;
+       }
+
+       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)) {
+                       time_t tt;
+                       struct tm tm;
+                       tt = atol(&buf[5]);
+                       localtime_r(&tt, &tm);
+                       strftime(datetime, sizeof datetime, "%c", &tm);
+               }
+       }
+
+       if (!strcmp(buf, "text")) {
+               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]);
+                               striplt(content_transfer_encoding);
+                       }
+                       if (!strncasecmp(buf, "Content-type:", 13)) {
+                               strcpy(content_type, &buf[13]);
+                               striplt(content_type);
+                       }
+               }
+               raw_msg = ctdl_readtextmsg(c);
+       }
+       else {
+               raw_msg = NULL;
+       }
+
+       // begin output
+
+       StrBufAppendPrintf(sj, "<div>");                                                // begin message wrapper
+       StrBufAppendPrintf(sj, "<div style=\"float:left;padding-right:2px\">");         // begin avatar FIXME move the style to a stylesheet
+       StrBufAppendPrintf(sj, "<i class=\"fa fa-user-circle fa-2x\"></i> ");           // FIXME temporary avatar
+       StrBufAppendPrintf(sj, "</div>");                                               // end avatar
+       StrBufAppendPrintf(sj, "<div>");                                                // begin content
+       StrBufAppendPrintf(sj, "<div>");                                                // begin header
+       StrBufAppendPrintf(sj, "<span class=\"ctdl-username\"><a href=\"#\">%s</a></span> ", author);   // FIXME link to user profile or whatever
+       StrBufAppendPrintf(sj, "<span class=\"ctdl-msgdate\">%s</span> ", datetime);
+       StrBufAppendPrintf(sj, "</div>");                                               // end header
+       StrBufAppendPrintf(sj, "<div>");                                                // begin body
+
+       if (raw_msg) {
+
+               // These are the encodings we know how to handle.  Decode in-place.
+
+               if (!strcasecmp(content_transfer_encoding, "base64")) {
+                       StrBufDecodeBase64(raw_msg);
+               }
+               if (!strcasecmp(content_transfer_encoding, "quoted-printable")) {
+                       StrBufDecodeQP(raw_msg);
+               }
+
+               // At this point, raw_msg contains the decoded message.
+               // Now run through the renderers we have available.
+
+               if (!strncasecmp(content_type, "text/html", 9)) {
+                       sanitized_msg = html2html("UTF-8", 0, c->room, msgnum, raw_msg);
+               }
+               else if (!strncasecmp(content_type, "text/plain", 10)) {
+                       sanitized_msg = text2html("UTF-8", 0, c->room, msgnum, raw_msg);
+               }
+               else if (!strncasecmp(content_type, "text/x-citadel-variformat", 25)) {
+                       sanitized_msg = variformat2html(raw_msg);
+               }
+               else {
+                       sanitized_msg = NewStrBufPlain(HKEY("<i>No renderer for this content type</i><br>"));
+               }
+               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, "</div>");                                               // end body
+       StrBufAppendPrintf(sj, "</div>");                                               // end content
+       StrBufAppendPrintf(sj, "</div>");                                               // 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<num_msgs; ++i) {
+               if (m[i].parent == where_parent_is) {
+
+                       if (++num_printed == 1) {
+                               StrBufAppendPrintf(sj, "<ul style=\"list-style-type: none;\">");
+                       }
+
+                       StrBufAppendPrintf(sj, "<li class=\"post\" id=\"post-%ld\">",  m[i].msgnum);
+                       forum_render_one_message(c, sj, m[i].msgnum);
+                       StrBufAppendPrintf(sj, "</li>\r\n");
+                       if (i != 0) {
+                               thread_o_print(c, sj, m, num_msgs, i, nesting_level+1);
+                       }
+               }
+       }
+
+       if (num_printed > 0) {
+               StrBufAppendPrintf(sj, "</ul>");
+       }
+}
+
+
+// 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, "<html><body>\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<num_msgs; ++i) {
+               for (j=9; (j>=0)&&(m[i].parent==0); --j) {
+                       for (k=0; (k<num_msgs)&&(m[i].parent==0); ++k) {
+                               if (m[i].refhashes[j] == m[k].threadhash) {
+                                       m[i].parent = k;
+                               }
+                       }
+               }
+       }
+
+       // Now render it
+       setup_for_forum_view(c);
+       thread_o_print(c, sj, m, num_msgs, 0, 0);               // Render threads recursively and recursively
+
+       // Garbage collection is for people who aren't smart enough to manage their own memory.
+       if (num_msgs > 0) {
+               free(m);
+       }
+
+       StrBufAppendPrintf(sj, "</body></html>\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, "<html><body>\r\n");
+
+       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, "</body></html>\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;
+}
index dc4551ae573cd2c2482a1b17ba88534cd59cfaa6..f49485d475bd92e68fccd8f993438b787344436d 100644 (file)
@@ -136,6 +136,11 @@ void object_in_room(struct http_transaction *h, struct ctdlsession *c)
                return;
        }
 
+       if (!strncasecmp(buf, "flat", 5)) {                     // Client is requesting a flat view (still kind of fuzzy here)
+               flat_view(h, c, &buf[5]);
+               return;
+       }
+
        if (    (c->room_default_view == VIEW_CALENDAR)         // room types where objects are referenced by EUID
                || (c->room_default_view == VIEW_TASKS)
                || (c->room_default_view == VIEW_ADDRESSBOOK)
@@ -382,7 +387,7 @@ void propfind_the_room_itself(struct http_transaction *h, struct ctdlsession *c)
                                                StrBufAppendPrintf(Buf, "</D:getlastmodified>");
                                                free(datestring);
                                        }
-                                       if (enumerate_by_euid) {                // FIXME ajc 2017oct30 should this really be inside the timestamp conditional?
+                                       if (enumerate_by_euid) {                // FIXME ajc 2017oct30 should this be inside the timestamp conditional?
                                                StrBufAppendPrintf(Buf, "<D:getetag>\"%ld\"</D:getetag>", msglist[i]);
                                        }
                                }
index f7f4839adabcde64705b51a8193758bbfaa77499..64f61512dbcbd8405fd401b4b772331861884830 100644 (file)
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <link rel="stylesheet" href="w3.css">
-<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
+<!-- link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway" -->
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
 
 <style>
-       html,body,h1,h2,h3,h4,h5 {font-family: "Raleway", sans-serif}
+       <!-- html,body,h1,h2,h3,h4,h5 {font-family: "Raleway", sans-serif} -->
 </style>
 
 <body class="w3-light-grey">
index 33da436676fe35ba3e7efcacc5c9058a3aa2c64b..3df8843153a9944bb78130de89f6bcd6e72e96b0 100644 (file)
@@ -37,7 +37,7 @@ function render_room_view() {
        switch(current_view) {
                case views.VIEW_MAILBOX:                                                // FIXME view mail rooms as forums for now
                case views.VIEW_BBS:
-                       threads_readmessages();
+                       forum_readmessages("flat");
                        break;
                default:
                        document.getElementById("main").innerHTML = "The view for " + current_room + " is " + current_view + " but there is no renderer." ;
@@ -47,15 +47,16 @@ function render_room_view() {
 }
 
 
-// bbs "threads" view
+// Forum view -- flat or threaded
 // The inner div exists so that if the user clicks away early, the main div doesn't get clobbered when the load completes.
+// The parameter can be set to "flat" or "threads" which is passed directly to the API
 //
-function threads_readmessages() {
+function forum_readmessages(flat_or_threads) {
        var innerdivname = randomString(5);
        document.getElementById("main").innerHTML = "<div id=\"" + innerdivname + "\"><img src=\"/ctdl/s/throbber.gif\" />" + _("Loading messages from server, please wait") + "</div>" ;
 
        var request = new XMLHttpRequest();
-       request.open("GET", "/ctdl/r/" + escapeHTMLURI(current_room) + "/" + "threads", true);
+       request.open("GET", "/ctdl/r/" + escapeHTMLURI(current_room) + "/" + flat_or_threads, true);
        request.onreadystatechange = function() {
                if (this.readyState === 4) {
                        if ((this.status / 100) == 2) {
diff --git a/webcit-ng/threaded_view.c b/webcit-ng/threaded_view.c
deleted file mode 100644 (file)
index d3e001b..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Threaded message view
- *
- * 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.
- */
-
-#include "webcit.h"
-
-struct mthread {
-       long msgnum;
-       time_t datetime;
-       int threadhash;
-       int refhashes[10];
-       char from[64];
-       int parent;
-};
-
-
-// Renderer for one message in the threaded view
-// (This will probably work for the flat view too.)
-//
-void thread_render_one_message(struct ctdlsession *c, StrBuf *sj, 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 } ;
-
-       ctdl_printf(c, "MSG4 %ld", msgnum);
-       ctdl_readline(c, buf, sizeof(buf));
-       if (buf[0] != '1') {
-               StrBufAppendPrintf(sj, "<div>ERROR CONDITION FIXME WRITE A BOX</div>");
-               return;
-       }
-
-       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)) {
-                       time_t tt;
-                       struct tm tm;
-                       tt = atol(&buf[5]);
-                       localtime_r(&tt, &tm);
-                       strftime(datetime, sizeof datetime, "%c", &tm);
-               }
-       }
-
-       if (!strcmp(buf, "text")) {
-               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]);
-                               striplt(content_transfer_encoding);
-                       }
-                       if (!strncasecmp(buf, "Content-type:", 13)) {
-                               strcpy(content_type, &buf[13]);
-                               striplt(content_type);
-                       }
-               }
-               raw_msg = ctdl_readtextmsg(c);
-       }
-       else {
-               raw_msg = NULL;
-       }
-
-       // begin output
-
-       StrBufAppendPrintf(sj, "<div>");                                                // begin message wrapper
-       StrBufAppendPrintf(sj, "<div style=\"float:left;padding-right:2px\">");         // begin avatar FIXME move the style to a stylesheet
-       StrBufAppendPrintf(sj, "<i class=\"fa fa-user-circle fa-2x\"></i> ");           // FIXME temporary avatar
-       StrBufAppendPrintf(sj, "</div>");                                               // end avatar
-       StrBufAppendPrintf(sj, "<div>");                                                // begin content
-       StrBufAppendPrintf(sj, "<div>");                                                // begin header
-       StrBufAppendPrintf(sj, "<span class=\"ctdl-username\"><a href=\"#\">%s</a></span> ", author);   // FIXME link to user profile or whatever
-       StrBufAppendPrintf(sj, "<span class=\"ctdl-msgdate\">%s</span> ", datetime);
-       StrBufAppendPrintf(sj, "</div>");                                               // end header
-       StrBufAppendPrintf(sj, "<div>");                                                // begin body
-
-       if (raw_msg) {
-
-               // These are the encodings we know how to handle.  Decode in-place.
-
-               if (!strcasecmp(content_transfer_encoding, "base64")) {
-                       StrBufDecodeBase64(raw_msg);
-               }
-               if (!strcasecmp(content_transfer_encoding, "quoted-printable")) {
-                       StrBufDecodeQP(raw_msg);
-               }
-
-               // At this point, raw_msg contains the decoded message.
-               // Now run through the renderers we have available.
-
-               if (!strncasecmp(content_type, "text/html", 9)) {
-                       sanitized_msg = html2html("UTF-8", 0, c->room, msgnum, raw_msg);
-               }
-               else if (!strncasecmp(content_type, "text/plain", 10)) {
-                       sanitized_msg = text2html("UTF-8", 0, c->room, msgnum, raw_msg);
-               }
-               else if (!strncasecmp(content_type, "text/x-citadel-variformat", 25)) {
-                       sanitized_msg = variformat2html(raw_msg);
-               }
-               else {
-                       sanitized_msg = NewStrBufPlain(HKEY("<i>No renderer for this content type</i><br>"));
-               }
-               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, "</div>");                                               // end body
-       StrBufAppendPrintf(sj, "</div>");                                               // end content
-       StrBufAppendPrintf(sj, "</div>");                                               // end wrapper
-}
-
-
-// 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<num_msgs; ++i) {
-               if (m[i].parent == where_parent_is) {
-
-                       if (++num_printed == 1) {
-                               StrBufAppendPrintf(sj, "<ul style=\"list-style-type: none;\">");
-                       }
-
-                       StrBufAppendPrintf(sj, "<li class=\"post\" id=\"post-%ld\">",  m[i].msgnum);
-                       thread_render_one_message(c, sj, m[i].msgnum);
-                       StrBufAppendPrintf(sj, "</li>\r\n");
-                       if (i != 0) {
-                               thread_o_print(c, sj, m, num_msgs, i, nesting_level+1);
-                       }
-               }
-       }
-
-       if (num_printed > 0) {
-               StrBufAppendPrintf(sj, "</ul>");
-       }
-}
-
-
-// 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, "<html><body>\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<num_msgs; ++i) {
-               for (j=9; (j>=0)&&(m[i].parent==0); --j) {
-                       for (k=0; (k<num_msgs)&&(m[i].parent==0); ++k) {
-                               if (m[i].refhashes[j] == m[k].threadhash) {
-                                       m[i].parent = k;
-                               }
-                       }
-               }
-       }
-
-       // Now render it
-       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
-       thread_o_print(c, sj, m, num_msgs, 0, 0);               // Render threads recursively and recursively
-
-       // Garbage collection is for people who aren't smart enough to manage their own memory.
-       if (num_msgs > 0) {
-               free(m);
-       }
-
-       StrBufAppendPrintf(sj, "</body></html>\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;
-}
index 8dfcf71164fba0c1d2ed0512374b2fb5ea504edf..72e40eed8d40fa899a85f48e30a2d1c0a2b883cd 100644 (file)
@@ -147,6 +147,7 @@ void dav_put_message(struct http_transaction *h, struct ctdlsession *c, char *eu
 ssize_t ctdl_write(struct ctdlsession *ctdl, const void *buf, size_t count);
 int login_to_citadel(struct ctdlsession *c, char *auth, char *resultbuf);
 void threaded_view(struct http_transaction *h, struct ctdlsession *c, char *which);
+void flat_view(struct http_transaction *h, struct ctdlsession *c, char *which);
 StrBuf *ctdl_readtextmsg(struct ctdlsession *ctdl);
 StrBuf *html2html(const char *supplied_charset, int treat_as_wiki, char *roomname, long msgnum, StrBuf *Source);
 void download_mime_component(struct http_transaction *h, struct ctdlsession *c, long msgnum, char *partnum);