* Removed all of the absolute URL's.
[citadel.git] / webcit / messages.c
index e86ea2f0bf3bf1380526b70e72a35edbf6e6e9e8..190f6061e4d4772689aa7173dfd996c6191bc2a1 100644 (file)
@@ -162,7 +162,7 @@ char buf[];
        urlbuf[end - start] = 0;
 
        strncpy(outbuf, buf, start);
-       sprintf(&outbuf[start], "%cA HREF=%c%s%c TARGET=%c%s%c%c%s%c/A%c",
+       sprintf(&outbuf[start], "%ca href=%c%s%c TARGET=%c%s%c%c%s%c/A%c",
                LB, QU, urlbuf, QU, QU, TARGET, QU, RB, urlbuf, LB, RB);
        strcat(outbuf, &buf[end]);
        if ( strlen(outbuf) < 250 )
@@ -342,7 +342,7 @@ void display_parsed_vcard(struct vCard *v, int full) {
                        else if (!strcasecmp(firsttoken, "email")) {
                                if (strlen(mailto) > 0) strcat(mailto, "<br />");
                                strcat(mailto,
-                                       "<A HREF=\"/display_enter"
+                                       "<a href=\"display_enter"
                                        "?force_room=_MAIL_?recp=");
 
                                urlesc(&mailto[strlen(mailto)], displayname);
@@ -419,7 +419,7 @@ void display_parsed_vcard(struct vCard *v, int full) {
                if (pass == 1) {
                        wprintf("<TR BGCOLOR=\"#AAAAAA\">"
                        "<TD COLSPAN=2 BGCOLOR=\"#FFFFFF\">"
-                       "<IMG ALIGN=CENTER SRC=\"/static/viewcontacts_48x.gif\">"
+                       "<IMG ALIGN=CENTER src=\"static/viewcontacts_48x.gif\">"
                        "<FONT SIZE=+1><B>");
                        escputs(displayname);
                        wprintf("</B></FONT>");
@@ -491,9 +491,9 @@ void display_vcard(char *vcard_source, char alpha, int full, char *storename) {
 
 
 /*
- * I wanna SEE that message!
+ * I wanna SEE that message!  (Optional 'section' for encapsulated message/rfc822 submessage)
  */
-void read_message(long msgnum, int printable_view) {
+void read_message(long msgnum, int printable_view, char *section) {
        char buf[SIZ];
        char mime_partnum[256];
        char mime_filename[256];
@@ -502,6 +502,7 @@ void read_message(long msgnum, int printable_view) {
        char mime_disposition[256];
        int mime_length;
        char mime_http[SIZ];
+       char mime_submessages[256];
        char m_subject[256];
        char m_cc[1024];
        char from[256];
@@ -536,8 +537,9 @@ void read_message(long msgnum, int printable_view) {
        strcpy(mime_http, "");
        strcpy(mime_content_type, "text/plain");
        strcpy(mime_charset, "us-ascii");
+       strcpy(mime_submessages, "");
 
-       serv_printf("MSG4 %ld", msgnum);
+       serv_printf("MSG4 %ld|%s", msgnum, section);
        serv_getln(buf, sizeof buf);
        if (buf[0] != '1') {
                wprintf("<STRONG>");
@@ -578,7 +580,7 @@ void read_message(long msgnum, int printable_view) {
                if (!strncasecmp(buf, "from=", 5)) {
                        strcpy(from, &buf[5]);
                        wprintf(_("from "));
-                       wprintf("<A HREF=\"/showuser?who=");
+                       wprintf("<a href=\"showuser?who=");
 #ifdef HAVE_ICONV
                        utf8ify_rfc822_string(from);
 #endif
@@ -647,26 +649,33 @@ void read_message(long msgnum, int printable_view) {
                        extract_token(mime_content_type, &buf[5], 4, '|', sizeof mime_content_type);
                        mime_length = extract_int(&buf[5], 5);
 
-                       if ((!strcasecmp(mime_disposition, "inline"))
+                       if (!strcasecmp(mime_content_type, "message/rfc822")) {
+                               if (strlen(mime_submessages) > 0) {
+                                       strcat(mime_submessages, "|");
+                               }
+                               strcat(mime_submessages, mime_partnum);
+                       }
+                       else if ((!strcasecmp(mime_disposition, "inline"))
                           && (!strncasecmp(mime_content_type, "image/", 6)) ){
                                snprintf(&mime_http[strlen(mime_http)],
                                        (sizeof(mime_http) - strlen(mime_http) - 1),
-                                       "<IMG SRC=\"/mimepart/%ld/%s/%s\">",
+                                       "<img src=\"mimepart/%ld/%s/%s\">",
                                        msgnum, mime_partnum, mime_filename);
                        }
                        else if ( (!strcasecmp(mime_disposition, "attachment")) 
                             || (!strcasecmp(mime_disposition, "inline")) ) {
                                snprintf(&mime_http[strlen(mime_http)],
                                        (sizeof(mime_http) - strlen(mime_http) - 1),
-                                       "<A HREF=\"/mimepart/%ld/%s/%s\" "
+                                       "<a href=\"mimepart/%ld/%s/%s\" "
                                        "TARGET=\"wc.%ld.%s\">"
-                                       "<IMG SRC=\"/static/diskette_24x.gif\" "
+                                       "<img src=\"static/diskette_24x.gif\" "
                                        "BORDER=0 ALIGN=MIDDLE>\n"
-                                       "Part %s: %s (%s, %d bytes)</A><br />\n",
+                                       "%s (%s, %d bytes)</A><br />\n",
                                        msgnum, mime_partnum, mime_filename,
                                        msgnum, mime_partnum,
-                                       mime_partnum, mime_filename,
-                                       mime_content_type, mime_length);
+                                       mime_filename,
+                                       mime_content_type, mime_length
+                               );
                        }
 
                        /*** begin handler prep ***/
@@ -733,7 +742,7 @@ void read_message(long msgnum, int printable_view) {
 
                /* Reply */
                if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) {
-                       wprintf("<a href=\"/display_enter");
+                       wprintf("<a href=\"display_enter");
                        if (WC->is_mailbox) {
                                wprintf("?replyquote=%ld", msgnum);
                        }
@@ -748,7 +757,7 @@ void read_message(long msgnum, int printable_view) {
                /* ReplyQuoted */
                if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) {
                        if (!WC->is_mailbox) {
-                               wprintf("<a href=\"/display_enter");
+                               wprintf("<a href=\"display_enter");
                                wprintf("?replyquote=%ld", msgnum);
                                wprintf("?recp=");
                                urlescputs(reply_to);
@@ -761,21 +770,23 @@ void read_message(long msgnum, int printable_view) {
 
                /* ReplyAll */
                if (WC->wc_view == VIEW_MAILBOX) {
-                       wprintf("<a href=\"/display_enter");
+                       wprintf("<a href=\"display_enter");
                        wprintf("?replyquote=%ld", msgnum);
                        wprintf("?recp=");
                        urlescputs(reply_to);
                        wprintf("?cc=");
                        urlescputs(reply_all);
-                       wprintf("?subject=");
-                       if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20");
-                       urlescputs(m_subject);
+                       if (strlen(m_subject) > 0) {
+                               wprintf("?subject=");
+                               if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20");
+                               urlescputs(m_subject);
+                       }
                        wprintf("\">[%s]</a> ", _("ReplyAll"));
                }
 
                /* Forward */
                if (WC->wc_view == VIEW_MAILBOX) {
-                       wprintf("<a href=\"/display_enter?fwdquote=%ld?subject=", msgnum);
+                       wprintf("<a href=\"display_enter?fwdquote=%ld?subject=", msgnum);
                        if (strncasecmp(m_subject, "Fwd:", 4)) wprintf("Fwd:%20");
                        urlescputs(m_subject);
                        wprintf("\">[%s]</a> ", _("Forward"));
@@ -784,17 +795,17 @@ void read_message(long msgnum, int printable_view) {
                /* If this is one of my own rooms, or if I'm an Aide or Room Aide, I can move/delete */
                if ( (WC->is_room_aide) || (WC->is_mailbox) ) {
                        /* Move */
-                       wprintf("<a href=\"/confirm_move_msg?msgid=%ld\">[%s]</a> ",
+                       wprintf("<a href=\"confirm_move_msg?msgid=%ld\">[%s]</a> ",
                                msgnum, _("Move"));
        
                        /* Delete */
-                       wprintf("<a href=\"/delete_msg?msgid=%ld\" "
+                       wprintf("<a href=\"delete_msg?msgid=%ld\" "
                                "onClick=\"return confirm('%s');\">"
                                "[%s]</a> ", msgnum, _("Delete this message?"), _("Delete")
                        );
                }
 
-               wprintf("<a href=\"#\" onClick=\"window.open('/printmsg?msgnum=%ld', 'print%ld', 'toolbar=no,location=no,directories=no,copyhistory=no,status=yes,scrollbars=yes,resizable=yes,width=600,height=400'); \" >"
+               wprintf("<a href=\"#\" onClick=\"window.open('/printmsg/%ld', 'print%ld', 'toolbar=no,location=no,directories=no,copyhistory=no,status=yes,scrollbars=yes,resizable=yes,width=600,height=400'); \" >"
                        "[%s]</a>", msgnum, msgnum, _("Print"));
 
                wprintf("</td>");
@@ -836,11 +847,15 @@ void read_message(long msgnum, int printable_view) {
 
        /* Set up a character set conversion if we need to (and if we can) */
 #ifdef HAVE_ICONV
+       if (strchr(mime_charset, ';')) strcpy(strchr(mime_charset, ';'), "");
        if ( (strcasecmp(mime_charset, "us-ascii"))
-          && (strcasecmp(mime_charset, "UTF-8")) ) {
+          && (strcasecmp(mime_charset, "UTF-8"))
+          && (strcasecmp(mime_charset, ""))
+       ) {
                ic = iconv_open("UTF-8", mime_charset);
                if (ic == (iconv_t)(-1) ) {
-                       lprintf(5, "iconv_open() failed: %s\n", strerror(errno));
+                       lprintf(5, "%s:%d iconv_open(UTF-8, %s) failed: %s\n",
+                               __FILE__, __LINE__, mime_charset, strerror(errno));
                }
        }
 #endif
@@ -902,8 +917,20 @@ void read_message(long msgnum, int printable_view) {
                while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { }
        }
 
+       /* If there are attached submessages, display them now... */
+       if ( (strlen(mime_submessages) > 0) && (!section[0]) ) {
+               for (i=0; i<num_tokens(mime_submessages, '|'); ++i) {
+                       extract_token(buf, mime_submessages, i, '|', sizeof buf);
+                       /* use printable_view to suppress buttons */
+                       wprintf("<blockquote>");
+                       read_message(msgnum, 1, buf);
+                       wprintf("</blockquote>");
+               }
+       }
+
+
        /* Afterwards, offer links to download attachments 'n' such */
-       if (strlen(mime_http) > 0) {
+       if ( (strlen(mime_http) > 0) && (!section[0]) ) {
                wprintf("%s", mime_http);
        }
 
@@ -917,7 +944,7 @@ void read_message(long msgnum, int printable_view) {
                                || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM))
                                || (WC->wc_view == VIEW_ADDRESSBOOK)
                        ) {
-                               wprintf("<A HREF=\"/edit_vcard?"
+                               wprintf("<a href=\"edit_vcard?"
                                        "msgnum=%ld?partnum=%s\">",
                                        msgnum, vcard_partnum);
                                wprintf("[%s]</A>", _("edit"));
@@ -964,12 +991,12 @@ ENDBODY:
  * Unadorned HTML output of an individual message, suitable
  * for placing in a hidden iframe, for printing, or whatever
  */
-void embed_message(void) {
+void embed_message(char *msgnum_as_string) {
        long msgnum = 0L;
 
-       msgnum = atol(bstr("msgnum"));
+       msgnum = atol(msgnum_as_string);
        begin_ajax_response();
-       read_message(msgnum, 0);
+       read_message(msgnum, 0, "");
        end_ajax_response();
 }
 
@@ -977,10 +1004,10 @@ void embed_message(void) {
 /*
  * Printable view of a message
  */
-void print_message(void) {
+void print_message(char *msgnum_as_string) {
        long msgnum = 0L;
 
-       msgnum = atol(bstr("msgnum"));
+       msgnum = atol(msgnum_as_string);
        output_headers(0, 0, 0, 0, 0, 0);
 
        wprintf("Content-type: text/html\r\n"
@@ -994,7 +1021,7 @@ void print_message(void) {
                "<body onLoad=\" window.print(); window.close(); \">\n"
        );
        
-       read_message(msgnum, 1);
+       read_message(msgnum, 1, "");
 
        wprintf("\n</body></html>\n\n");
        wDumpContent(0);
@@ -1176,10 +1203,13 @@ void pullquote_message(long msgnum, int forward_attachments) {
        /* Set up a character set conversion if we need to (and if we can) */
 #ifdef HAVE_ICONV
        if ( (strcasecmp(mime_charset, "us-ascii"))
-          && (strcasecmp(mime_charset, "UTF-8")) ) {
+          && (strcasecmp(mime_charset, "UTF-8"))
+          && (strcasecmp(mime_charset, ""))
+       ) {
                ic = iconv_open("UTF-8", mime_charset);
                if (ic == (iconv_t)(-1) ) {
-                       lprintf(5, "iconv_open() failed: %s\n", strerror(errno));
+                       lprintf(5, "%s:%d iconv_open() failed: %s\n",
+                               __FILE__, __LINE__, strerror(errno));
                }
        }
 #endif
@@ -1301,32 +1331,35 @@ ENDBODY:
 }
 
 
-
-
-
-
 void display_summarized(int num) {
        char datebuf[64];
 
-       wprintf("<TD>");
-       if (WC->summ[num].is_new) wprintf("<B>");
+       wprintf("<tr id=\"m%ld\" style=\"width:100%%;font-weight:%s;background-color:#fff\" "
+               "onClick=\"CtdlSingleClickMsg(%ld)\">",
+               WC->summ[num].msgnum,
+               (WC->summ[num].is_new ? "bold" : "normal"),
+               WC->summ[num].msgnum
+       );
+
+       wprintf("<td>");
        escputs(WC->summ[num].subj);
-       if (WC->summ[num].is_new) wprintf("</B>");
-       wprintf("</TD><TD>");
-       if (WC->summ[num].is_new) wprintf("<B>");
+       wprintf("</td>");
+
+       wprintf("<td>");
        escputs(WC->summ[num].from);
-       if (WC->summ[num].is_new) wprintf("</B>");
-       wprintf(" </TD><TD>");
-       if (WC->summ[num].is_new) wprintf("<B>");
+       wprintf("</td>");
+
+       wprintf("<td>");
        fmt_date(datebuf, WC->summ[num].date, 1);       /* brief */
        escputs(datebuf);
-       if (WC->summ[num].is_new) wprintf("</B>");
-       wprintf(" </TD>");
-       wprintf("<TD>"
-               "<INPUT TYPE=\"checkbox\" NAME=\"msg_%ld\" VALUE=\"yes\">"
-               "</TD>\n",
+       wprintf("</td>");
+
+       wprintf("<td><input type=\"checkbox\" name=\"msg_%ld\" value=\"yes\">",
                WC->summ[num].msgnum
        );
+       wprintf("</td>");
+
+       wprintf("</tr>\n");
 }
 
 
@@ -1379,7 +1412,7 @@ void display_addressbook(long msgnum, char alpha) {
                                || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM))
                                || (WC->wc_view == VIEW_ADDRESSBOOK)
                        ) {
-                               wprintf("<A HREF=\"/edit_vcard?"
+                               wprintf("<a href=\"edit_vcard?"
                                        "msgnum=%ld?partnum=%s\">",
                                        msgnum, vcard_partnum);
                                wprintf("[%s]</A>", _("edit"));
@@ -1530,7 +1563,7 @@ void do_addrbook_view(struct addrbookent *addrbook, int num_ab) {
        wprintf("Page: ");
        for (i=0; i<=num_pages; ++i) {
                if (i != page) {
-                       wprintf("<A HREF=\"/readfwd?page=%d\">", i);
+                       wprintf("<a href=\"readfwd?page=%d\">", i);
                }
                else {
                        wprintf("<B>");
@@ -1572,7 +1605,7 @@ void do_addrbook_view(struct addrbookent *addrbook, int num_ab) {
        
                        wprintf("<TD>");
        
-                       wprintf("<A HREF=\"/readfwd?startmsg=%ld&is_singlecard=1",
+                       wprintf("<a href=\"readfwd?startmsg=%ld&is_singlecard=1",
                                addrbook[i].ab_msgnum);
                        wprintf("?maxmsgs=1?summary=0?alpha=%s\">", bstr("alpha"));
                        vcard_n_prettyize(addrbook[i].ab_name);
@@ -1681,6 +1714,18 @@ int load_msg_ptrs(char *servcmd, int with_headers)
        return (nummsgs);
 }
 
+int longcmp_r(const void *s1, const void *s2) {
+       long l1;
+       long l2;
+
+       l1 = *(long *)s1;
+       l2 = *(long *)s2;
+
+       if (l1 > l2) return(-1);
+       if (l1 < l2) return(+1);
+       return(0);
+}
+
  
 int summcmp_subj(const void *s1, const void *s2) {
        struct message_summary *summ1;
@@ -1754,6 +1799,7 @@ void readloop(char *oper)
        int nummsgs;
        long startmsg;
        int maxmsgs;
+       long *displayed_msgs = NULL;
        int num_displayed = 0;
        int is_summary = 0;
        int is_addressbook = 0;
@@ -1761,14 +1807,9 @@ void readloop(char *oper)
        int is_calendar = 0;
        int is_tasks = 0;
        int is_notes = 0;
-       int remaining_messages;
        int lo, hi;
        int lowest_displayed = (-1);
        int highest_displayed = 0;
-       long pn_previous = 0L;
-       long pn_current = 0L;
-       long pn_next = 0L;
-       int bg = 0;
        struct addrbookent *addrbook = NULL;
        int num_ab = 0;
        char *sortby = NULL;
@@ -1777,6 +1818,7 @@ void readloop(char *oper)
        char *subjsort_button;
        char *sendsort_button;
        char *datesort_button;
+       int bbs_reverse = 0;    /* FIXME we need to set/reset this option now.  It works. */
 
        startmsg = atol(bstr("startmsg"));
        maxmsgs = atoi(bstr("maxmsgs"));
@@ -1791,7 +1833,17 @@ void readloop(char *oper)
                set_preference(sortpref_name, sortby, 1);
        }
        if (strlen(sortby) == 0) sortby = sortpref_value;
-       if (strlen(sortby) == 0) sortby = "msgid";
+
+       /* mailbox sort */
+       if (strlen(sortby) == 0) sortby = "rdate";
+
+       /* message board sort */
+       if (!strcasecmp(sortby, "reverse")) {
+               bbs_reverse = 1;
+       }
+       else {
+               bbs_reverse = 0;
+       }
 
        output_headers(1, 1, 1, 0, 0, 0);
 
@@ -1888,12 +1940,12 @@ void readloop(char *oper)
                }
        }
 
-       if (startmsg == 0L) startmsg = WC->msgarr[0];
-       remaining_messages = 0;
-
-       for (a = 0; a < nummsgs; ++a) {
-               if (WC->msgarr[a] >= startmsg) {
-                       ++remaining_messages;
+       if (startmsg == 0L) {
+               if (bbs_reverse) {
+                       startmsg = WC->msgarr[(nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0];
+               }
+               else {
+                       startmsg = WC->msgarr[0];
                }
        }
 
@@ -1925,33 +1977,33 @@ void readloop(char *oper)
        }
 
        if (!strcasecmp(sortby, "subject")) {
-               subjsort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rsubject\"><img border=\"0\" src=\"/static/down_pointer.gif\" /></a>" ;
+               subjsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rsubject\"><img border=\"0\" src=\"static/down_pointer.gif\" /></a>" ;
        }
        else if (!strcasecmp(sortby, "rsubject")) {
-               subjsort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=subject\"><img border=\"0\" src=\"/static/up_pointer.gif\" /></a>" ;
+               subjsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=subject\"><img border=\"0\" src=\"static/up_pointer.gif\" /></a>" ;
        }
        else {
-               subjsort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=subject\"><img border=\"0\" src=\"/static/sort_none.gif\" /></a>" ;
+               subjsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=subject\"><img border=\"0\" src=\"static/sort_none.gif\" /></a>" ;
        }
 
        if (!strcasecmp(sortby, "sender")) {
-               sendsort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rsender\"><img border=\"0\" src=\"/static/down_pointer.gif\" /></a>" ;
+               sendsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rsender\"><img border=\"0\" src=\"static/down_pointer.gif\" /></a>" ;
        }
        else if (!strcasecmp(sortby, "rsender")) {
-               sendsort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=sender\"><img border=\"0\" src=\"/static/up_pointer.gif\" /></a>" ;
+               sendsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=sender\"><img border=\"0\" src=\"static/up_pointer.gif\" /></a>" ;
        }
        else {
-               sendsort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=sender\"><img border=\"0\" src=\"/static/sort_none.gif\" /></a>" ;
+               sendsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=sender\"><img border=\"0\" src=\"static/sort_none.gif\" /></a>" ;
        }
 
        if (!strcasecmp(sortby, "date")) {
-               datesort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rdate\"><img border=\"0\" src=\"/static/down_pointer.gif\" /></a>" ;
+               datesort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rdate\"><img border=\"0\" src=\"static/down_pointer.gif\" /></a>" ;
        }
        else if (!strcasecmp(sortby, "rdate")) {
-               datesort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=date\"><img border=\"0\" src=\"/static/up_pointer.gif\" /></a>" ;
+               datesort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=date\"><img border=\"0\" src=\"static/up_pointer.gif\" /></a>" ;
        }
        else {
-               datesort_button = "<a href=\"/readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=date\"><img border=\"0\" src=\"/static/sort_none.gif\" /></a>" ;
+               datesort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?summary=1?sortby=rdate\"><img border=\"0\" src=\"static/sort_none.gif\" /></a>" ;
        }
 
        if (is_summary) {
@@ -1962,20 +2014,15 @@ void readloop(char *oper)
                        "<div id=\"fix_scrollbar_bug\">\n"
 
                        "<form name=\"msgomatic\" "
-                       "method=\"POST\" action=\"/do_stuff_to_msgs\">\n"
+                       "method=\"POST\" action=\"do_stuff_to_msgs\">\n"
 
                        "<span class=\"mailbox_summary\">"
-                       "<table border=0 cellspacing=0 "
-                       "cellpadding=0 width=100%%>\n"
-                       "<TR>"
-                       "<TD align=center><b><i>%s</i></b> %s</TD>"
-                       "<TD align=center><b><i>%s</i></b> %s</TD>"
-                       "<TD align=center><b><i>%s</i></b> %s</TD>"
-                       "<TD><INPUT TYPE=\"submit\" NAME=\"delete_button\" "
-                       "STYLE=\"font-family: Bitstream Vera Sans,Arial,Helvetica,sans-serif;"
-                       " font-size: 6pt;\" "
-                       "VALUE=\"%s\"></TD>"
-                       "</TR>\n"
+                       "<table id=\"summary_headers\" rules=rows cellspacing=0 style=\"width:100%%\"><tr>"
+                       "<td><b><i>%s</i></b> %s</td>"
+                       "<td><b><i>%s</i></b> %s</td>"
+                       "<td><b><i>%s</i></b> %s</td>"
+                       "<td><input type=\"submit\" name=\"delete_button\" style=\"font-size:6pt\" value=\"%s\"></td>"
+                       "</tr>\n"
                        ,
                        _("Subject"),   subjsort_button,
                        _("Sender"),    sendsort_button,
@@ -1987,23 +2034,6 @@ void readloop(char *oper)
        for (a = 0; a < nummsgs; ++a) {
                if ((WC->msgarr[a] >= startmsg) && (num_displayed < maxmsgs)) {
 
-                       /* Learn which msgs "Prev" & "Next" buttons go to */
-                       pn_current = WC->msgarr[a];
-                       if (a > 0) pn_previous = WC->msgarr[a-1];
-                       if (a < (nummsgs-1)) pn_next = WC->msgarr[a+1];
-
-                       /* If a tabular view, set up the line */
-                       if (is_summary) {
-                               bg = 1 - bg;
-                               wprintf("<tr bgcolor=\"#%s\" ",
-                                       (bg ? "DDDDDD" : "FFFFFF")
-                               );
-
-                               wprintf("onClick=\" new Ajax.Updater('preview_pane', '/msg', { method: 'get', parameters: 'msgnum=%ld' } ); \" ", WC->summ[a].msgnum);
-
-                               wprintf(">");
-                       }
-
                        /* Display the message */
                        if (is_summary) {
                                display_summarized(a);
@@ -2027,30 +2057,50 @@ void readloop(char *oper)
                                display_note(WC->msgarr[a]);
                        }
                        else {
-                               read_message(WC->msgarr[a], 0);
-                       }
-
-                       /* If a tabular view, finish the line */
-                       if (is_summary) {
-                               wprintf("</TR>\n");
+                               if (displayed_msgs == NULL) {
+                                       displayed_msgs = malloc(sizeof(long) *
+                                                               (maxmsgs<nummsgs ? maxmsgs : nummsgs));
+                               }
+                               displayed_msgs[num_displayed] = WC->msgarr[a];
                        }
 
                        if (lowest_displayed < 0) lowest_displayed = a;
                        highest_displayed = a;
 
                        ++num_displayed;
-                       --remaining_messages;
                }
        }
 
+       if (displayed_msgs != NULL) {
+               if (bbs_reverse) {
+                       qsort(displayed_msgs, num_displayed, sizeof(long), longcmp_r);
+               }
+
+               for (a=0; a<num_displayed; ++a) {
+                       read_message(displayed_msgs[a], 0, "");
+               }
+               free(displayed_msgs);
+               displayed_msgs = NULL;
+       }
+
        if (is_summary) {
                wprintf("</table></span></form>"
                        "</div>\n");                    /* end of 'fix_scrollbar_bug' div */
                wprintf("</div>");                      /* end of 'message_list' div */
 
-               wprintf("<div id=\"ml_slider\"></div>");        /* slider */
-
                wprintf("<div id=\"preview_pane\">");   /* The preview pane will initially be empty */
+
+               /* Now register each message (whose element ID is "m9999",
+                * where "9999" is the message number) as draggable.
+                * (NOTE: uses script.aculo.us draggables, which will probably not be
+                * adequate for this purpose.)
+               wprintf("<script type=\"text/javascript\">\n");
+               for (a = 0; a < nummsgs; ++a) {
+                       wprintf("new Draggable('m%ld',{revert:true});\n",
+                               WC->summ[a].msgnum);
+               }
+               wprintf("</script>\n");
+                */
        }
 
        /* Bump these because although we're thinking in zero base, the user
@@ -2059,51 +2109,6 @@ void readloop(char *oper)
        ++lowest_displayed;
        ++highest_displayed;
 
-       /* If we're only looking at one message, do a prev/next thing */
-       if (num_displayed == 1) {
-          if ((!is_tasks) && (!is_calendar) && (!is_addressbook) && (!is_notes) && (!is_singlecard)) {
-
-               wprintf("<div id=\"fix_scrollbar_bug\">"
-                       "<table border=0 width=100%% bgcolor=\"#dddddd\"><tr><td>");
-               wprintf(_("Reading #%d of %d messages."), lowest_displayed, nummsgs);
-               wprintf("</TD><TD ALIGN=RIGHT><FONT SIZE=+1>");
-
-               if (pn_previous > 0L) {
-                       wprintf("<A HREF=\"/%s"
-                               "?startmsg=%ld"
-                               "?maxmsgs=1"
-                               "?summary=0\">"
-                               "%s</A> \n",
-                                       oper,
-                                       pn_previous,
-                                       _("Previous"));
-               }
-
-               if (pn_next > 0L) {
-                       wprintf("<A HREF=\"/%s"
-                               "?startmsg=%ld"
-                               "?maxmsgs=1"
-                               "?summary=0\">"
-                               "%s</A> \n",
-                                       oper,
-                                       pn_next,
-                                       _("Next"));
-               }
-
-               wprintf("<A HREF=\"/%s?startmsg=%ld"
-                       "?maxmsgs=%d?summary=1\">"
-                       "%s"
-                       "</A>",
-                       oper,
-                       WC->msgarr[0],
-                       DEFAULT_MAXMSGS,
-                       _("Summary")
-               );
-
-               wprintf("</td></tr></table></div>\n");
-           }
-       }
-
        /*
         * If we're not currently looking at ALL requested
         * messages, then display the selector bar
@@ -2113,7 +2118,7 @@ void readloop(char *oper)
              && (!is_notes) && (!is_singlecard) && (!is_summary)) {
 
                wprintf("<form name=\"msgomatic\" "
-                       "method=\"POST\" action=\"/do_stuff_to_msgs\">\n");
+                       "method=\"POST\" action=\"do_stuff_to_msgs\">\n");
 
                wprintf(_("Reading #"), lowest_displayed, highest_displayed);
 
@@ -2121,23 +2126,45 @@ void readloop(char *oper)
                        "OnChange=\"location.href=msgomatic.whichones.options"
                        "[selectedIndex].value\">\n");
 
-               for (b=0; b<nummsgs; b = b + maxmsgs) {
-               lo = b+1;
-               hi = b+maxmsgs;
-               if (hi > nummsgs) hi = nummsgs;
-                       wprintf("<option %s value="
-                               "\"/%s"
-                               "?startmsg=%ld"
-                               "?maxmsgs=%d"
-                               "?summary=%d\">"
-                               "%d-%d</option> \n",
-                               ((WC->msgarr[b] == startmsg) ? "selected" : ""),
-                               oper,
-                               WC->msgarr[b],
-                               maxmsgs,
-                               is_summary,
-                               lo, hi);
+               if (bbs_reverse) {
+                       for (b=nummsgs-1; b>=0; b = b - maxmsgs) {
+                               hi = b + 1;
+                               lo = b - maxmsgs + 2;
+                               if (lo < 1) lo = 1;
+                               wprintf("<option %s value="
+                                       "\"/%s"
+                                       "?startmsg=%ld"
+                                       "?maxmsgs=%d"
+                                       "?summary=%d\">"
+                                       "%d-%d</option> \n",
+                                       ((WC->msgarr[lo-1] == startmsg) ? "selected" : ""),
+                                       oper,
+                                       WC->msgarr[lo-1],
+                                       maxmsgs,
+                                       is_summary,
+                                       hi, lo);
+                       }
+               }
+               else {
+                       for (b=0; b<nummsgs; b = b + maxmsgs) {
+                               lo = b + 1;
+                               hi = b + maxmsgs + 1;
+                               if (hi > nummsgs) hi = nummsgs;
+                               wprintf("<option %s value="
+                                       "\"/%s"
+                                       "?startmsg=%ld"
+                                       "?maxmsgs=%d"
+                                       "?summary=%d\">"
+                                       "%d-%d</option> \n",
+                                       ((WC->msgarr[b] == startmsg) ? "selected" : ""),
+                                       oper,
+                                       WC->msgarr[lo-1],
+                                       maxmsgs,
+                                       is_summary,
+                                       lo, hi);
+                       }
                }
+
                wprintf("<option value=\"/%s?startmsg=%ld"
                        "?maxmsgs=9999999?summary=%d\">"
                        "ALL"
@@ -2147,6 +2174,25 @@ void readloop(char *oper)
 
                wprintf("</select> ");
                wprintf(_("of %d messages."), nummsgs);
+
+               /* forward/reverse */
+               wprintf("&nbsp;<select name=\"direction\" size=\"1\" "
+                       "OnChange=\"location.href=msgomatic.direction.options"
+                       "[selectedIndex].value\">\n"
+               );
+
+               wprintf("<option %s value=\"/%s&sortby=forward\">oldest to newest</option>\n",
+                       (bbs_reverse ? "" : "selected"),
+                       oper
+               );
+       
+               wprintf("<option %s value=\"/%s&sortby=reverse\">newest to oldest</option>\n",
+                       (bbs_reverse ? "selected" : ""),
+                       oper
+               );
+       
+               wprintf("</select>");
+
                wprintf("</form>\n");
            }
        }
@@ -2179,15 +2225,6 @@ DONE:
                WC->num_summ = 0;
                free(WC->summ);
        }
-
-       /* If we got here via a mailbox view and are reading a single
-        * message, mark it as "seen." We do this after rendering the web page
-        * so it doesn't keep the user waiting.
-        */
-       if ( (maxmsgs == 1) && (WC->wc_view == VIEW_MAILBOX) ) {
-               serv_printf("SEEN %ld|1", startmsg);
-               serv_getln(buf, sizeof buf);
-       }
 }
 
 
@@ -2465,7 +2502,7 @@ void display_enter(void)
 
        /* begin message entry screen */
        wprintf("<form enctype=\"multipart/form-data\" "
-               "method=\"POST\" action=\"/post\" "
+               "method=\"POST\" action=\"post\" "
                "name=\"enterform\""
                ">\n");
        wprintf("<input type=\"hidden\" name=\"postseq\" value=\"%ld\">\n", now);
@@ -2608,7 +2645,7 @@ void display_enter(void)
        );
 
        /* Enumerate any attachments which are already in place... */
-       wprintf("<img src=\"/static/diskette_24x.gif\" border=0 "
+       wprintf("<img src=\"static/diskette_24x.gif\" border=0 "
                "align=middle height=16 width=16> Attachments: ");
        wprintf("<select name=\"which_attachment\" size=1>");
        for (att = WC->first_attachment; att != NULL; att = att->next) {
@@ -2664,8 +2701,7 @@ void delete_msg(void)
 
        output_headers(1, 1, 1, 0, 0, 0);
 
-       sprintf(buf, "DELE %ld", msgid);
-       serv_puts(buf);
+       serv_printf("MOVE %ld|_TRASH_|0", msgid);
        serv_getln(buf, sizeof buf);
        wprintf("<EM>%s</EM><br />\n", &buf[4]);
 
@@ -2701,7 +2737,7 @@ void confirm_move_msg(void)
        wprintf(_("Move this message to:"));
        wprintf("<br />\n");
 
-       wprintf("<form METHOD=\"POST\" ACTION=\"/move_msg\">\n");
+       wprintf("<form METHOD=\"POST\" action=\"move_msg\">\n");
        wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n", bstr("msgid"));
 
        wprintf("<SELECT NAME=\"target_room\" SIZE=5>\n");
@@ -2787,7 +2823,7 @@ void do_stuff_to_msgs(void) {
                if (!strcasecmp(bstr(buf), "yes")) {
 
                        if (delete_button_pressed) {
-                               serv_printf("DELE %ld", stuff->msgnum);
+                               serv_printf("MOVE %ld|_TRASH_|0", stuff->msgnum);
                                serv_getln(buf, sizeof buf);
                        }