* use strbuffer as wprintf backend
[citadel.git] / webcit / messages.c
index f9e0ae7677adc31fd9eb68095baf191f774f681c..90340896472e3686b4485c4fbbe558f4a8594816 100644 (file)
@@ -13,6 +13,8 @@
 #define SENDER_COL_WIDTH_PCT           30      /**< Mailbox view column width */
 #define DATE_PLUS_BUTTONS_WIDTH_PCT    20      /**< Mailbox view column width */
 
+void display_enter(void);
+
 /*
  * Address book entry (keep it short and sweet, it's just a quickie lookup
  * which we can use to get to the real meat and bones later)
@@ -104,10 +106,11 @@ void utf8ify_rfc822_string(char *buf) {
                }
        }
        if (illegal_non_rfc2047_encoding) {
-               char default_header_charset[128];
-               get_preference("default_header_charset", default_header_charset, sizeof default_header_charset);
-               if ( (strcasecmp(default_header_charset, "UTF-8")) && (strcasecmp(default_header_charset, "us-ascii")) ) {
-                       ic = ctdl_iconv_open("UTF-8", default_header_charset);
+               StrBuf *default_header_charset;
+               get_preference("default_header_charset", &default_header_charset);
+               if ( (strcasecmp(ChrPtr(default_header_charset), "UTF-8")) && 
+                    (strcasecmp(ChrPtr(default_header_charset), "us-ascii")) ) {
+                       ic = ctdl_iconv_open("UTF-8", ChrPtr(default_header_charset));
                        if (ic != (iconv_t)(-1) ) {
                                ibuf = malloc(1024);
                                isav = ibuf;
@@ -300,14 +303,15 @@ int webcit_rfc2047encode(char *target, int maxlen, char *source, long SourceLen)
 
        if (!need_to_encode) {
                memcpy (target, source, SourceLen);
+               target[SourceLen] = '\0';
                return SourceLen;
        }
        
        if (sizeof (headerStr + SourceLen + 2) > maxlen)
                return -1;
        memcpy (target, headerStr, sizeof (headerStr));
-       len = sizeof (headerStr);
-       for (i=0; (i < SourceLen) && (len < maxlen) ; ++i) {
+       len = sizeof (headerStr) - 1;
+       for (i=0; (i < SourceLen) && (len + 3< maxlen) ; ++i) {
                ch = (unsigned char) source[i];
                if ((ch < 32) || (ch > 126) || (ch == 61)) {
                        sprintf(&target[len], "=%02X", ch);
@@ -331,20 +335,23 @@ int webcit_rfc2047encode(char *target, int maxlen, char *source, long SourceLen)
 
 
 
-/**
- * \brief Look for URL's embedded in a buffer and make them linkable.  We use a
- * target window in order to keep the BBS session in its own window.
- * \param buf the message buffer
+/*
+ * Look for URL's embedded in a buffer and make them linkable.  We use a
+ * target window in order to keep the Citadel session in its own window.
  */
-void url(char *buf)
+void url(char *buf, size_t bufsize)
 {
-       int len;
+       int len, UrlLen, Offset, TrailerLen, outpos;
        char *start, *end, *pos;
        char urlbuf[SIZ];
-       char outbuf[1024];
+       char outbuf[SIZ];
 
        start = NULL;
        len = strlen(buf);
+       if (len > bufsize) {
+               lprintf(1, "URL: content longer than buffer!");
+               return;
+       }
        end = buf + len;
        for (pos = buf; (pos < end) && (start == NULL); ++pos) {
                if (!strncasecmp(pos, "http://", 7))
@@ -375,17 +382,35 @@ void url(char *buf)
                        end = pos;
                }
        }
+       
+       UrlLen = end - start;
+       if (UrlLen > sizeof(urlbuf)){
+               lprintf(1, "URL: content longer than buffer!");
+               return;
+       }
+       memcpy(urlbuf, start, UrlLen);
+       urlbuf[UrlLen] = '\0';
+
+       Offset = start - buf;
+       if ((Offset != 0) && (Offset < sizeof(outbuf)))
+               memcpy(outbuf, buf, Offset);
+       outpos = snprintf(&outbuf[Offset], sizeof(outbuf) - Offset,  
+                         "%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);
+       if (outpos >= sizeof(outbuf) - Offset) {
+               lprintf(1, "URL: content longer than buffer!");
+               return;
+       }
 
-       strncpy(urlbuf, start, end - start);
-       urlbuf[end - start] = '\0';
-
-       if (start != buf)
-               strncpy(outbuf, buf, start - buf );
-       sprintf(&outbuf[start-buf], "%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, end);
-       if ( strlen(outbuf) < 250 )
-               strcpy(buf, outbuf);
+       TrailerLen = len - (end - start);
+       if (TrailerLen > 0)
+               memcpy(outbuf + Offset + outpos, end, TrailerLen);
+       if (Offset + outpos + TrailerLen > bufsize) {
+               lprintf(1, "URL: content longer than buffer!");
+               return;
+       }
+       memcpy (buf, outbuf, Offset + outpos + TrailerLen);
+       *(buf + Offset + outpos + TrailerLen) = '\0';
 }
 
 
@@ -467,8 +492,9 @@ void fetchname_parsed_vcard(struct vCard *v, char *storename) {
  * understand in a simple two-column name/value format.
  * \param v the vCard to display
  * \param full display all items of the vcard?
+ * \param msgnum Citadel message pointer
  */
-void display_parsed_vcard(struct vCard *v, int full) {
+void display_parsed_vcard(struct vCard *v, int full, long msgnum) {
        int i, j;
        char buf[SIZ];
        char *name;
@@ -637,6 +663,14 @@ void display_parsed_vcard(struct vCard *v, int full) {
                                        wprintf("</TD></TR>\n");
                                }
                        }
+                       /* else if (!strcasecmp(firsttoken, "photo") && full && pass == 2) { 
+                               // Only output on second pass
+                               wprintf("<tr><td>");
+                               wprintf(_("Photo:"));
+                               wprintf("</td><td>");
+                               wprintf("<img src=\"/vcardphoto/%ld/\" alt=\"Contact photo\"/>",msgnum);
+                               wprintf("</td></tr>\n");
+                       } */
                        else if (!strcasecmp(firsttoken, "version")) {
                                /* ignore */
                        }
@@ -711,8 +745,10 @@ void display_parsed_vcard(struct vCard *v, int full) {
  * \param alpha what???
  * \param full should we usse all lines?
  * \param storename where to store???
+ * \param msgnum Citadel message pointer
  */
-void display_vcard(char *vcard_source, char alpha, int full, char *storename) {
+void display_vcard(char *vcard_source, char alpha, int full, char *storename, 
+       long msgnum) {
        struct vCard *v;
        char *name;
        char buf[SIZ];
@@ -735,7 +771,7 @@ void display_vcard(char *vcard_source, char alpha, int full, char *storename) {
                        || ((isalpha(alpha)) && (tolower(alpha) == tolower(this_alpha)) )
                        || ((!isalpha(alpha)) && (!isalpha(this_alpha)))
                ) {
-               display_parsed_vcard(v, full);
+               display_parsed_vcard(v, full,msgnum);
        }
 
        vcard_free(v);
@@ -777,6 +813,7 @@ void read_message(long msgnum, int printable_view, char *section) {
        char reply_to[512] = "";
        char reply_all[4096] = "";
        char reply_references[1024] = "";
+       char reply_inreplyto[256] = "";
        char now[64] = "";
        int format_type = 0;
        int nhdr = 0;
@@ -849,15 +886,10 @@ void read_message(long msgnum, int printable_view, char *section) {
                        safestrncpy(m_subject, &buf[5], sizeof m_subject);
                }
                if (!strncasecmp(buf, "msgn=", 5)) {
-                       safestrncpy(reply_references, &buf[5], sizeof reply_references);
+                       safestrncpy(reply_inreplyto, &buf[5], sizeof reply_inreplyto);
                }
                if (!strncasecmp(buf, "wefw=", 5)) {
-                       int rrlen = strlen(reply_references);
-                       if (rrlen > 0) {
-                               strcpy(&reply_references[rrlen++], "|");
-                       }
-                       safestrncpy(&reply_references[rrlen], &buf[5],
-                               (sizeof(reply_references) - rrlen) );
+                       safestrncpy(reply_references, &buf[5], sizeof reply_references);
                }
                if (!strncasecmp(buf, "cccc=", 5)) {
                        int len;
@@ -1000,7 +1032,16 @@ void read_message(long msgnum, int printable_view, char *section) {
 
        }
 
-       /** Generate a reply-to address */
+       /* Trim down excessively long lists of thread references.  We eliminate the
+        * second one in the list so that the thread root remains intact.
+        */
+       int rrtok = num_tokens(reply_references, '|');
+       int rrlen = strlen(reply_references);
+       if ( ((rrtok >= 3) && (rrlen > 900)) || (rrtok > 10) ) {
+               remove_token(reply_references, 1, '|');
+       }
+
+       /* Generate a reply-to address */
        if (!IsEmptyStr(rfca)) {
                if (!IsEmptyStr(from)) {
                        snprintf(reply_to, sizeof(reply_to), "%s <%s>", from, rfca);
@@ -1043,13 +1084,15 @@ void read_message(long msgnum, int printable_view, char *section) {
                        urlescputs(reply_to);
                        if (!IsEmptyStr(m_subject)) {
                                wprintf("?subject=");
-                               if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20");
+                               if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%%20");
                                urlescputs(m_subject);
                        }
+                       wprintf("?references=");
                        if (!IsEmptyStr(reply_references)) {
-                               wprintf("?references=");
                                urlescputs(reply_references);
+                               urlescputs("|");
                        }
+                       urlescputs(reply_inreplyto);
                        wprintf("\"><span>[</span>%s<span>]</span></a> ", _("Reply"));
                }
 
@@ -1062,13 +1105,15 @@ void read_message(long msgnum, int printable_view, char *section) {
                                urlescputs(reply_to);
                                if (!IsEmptyStr(m_subject)) {
                                        wprintf("?subject=");
-                                       if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20");
+                                       if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%%20");
                                        urlescputs(m_subject);
                                }
+                               wprintf("?references=");
                                if (!IsEmptyStr(reply_references)) {
-                                       wprintf("?references=");
                                        urlescputs(reply_references);
+                                       urlescputs("|");
                                }
+                               urlescputs(reply_inreplyto);
                                wprintf("\"><span>[</span>%s<span>]</span></a> ", _("ReplyQuoted"));
                        }
                }
@@ -1083,20 +1128,22 @@ void read_message(long msgnum, int printable_view, char *section) {
                        urlescputs(reply_all);
                        if (!IsEmptyStr(m_subject)) {
                                wprintf("?subject=");
-                               if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20");
+                               if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%%20");
                                urlescputs(m_subject);
                        }
+                       wprintf("?references=");
                        if (!IsEmptyStr(reply_references)) {
-                               wprintf("?references=");
                                urlescputs(reply_references);
+                               urlescputs("|");
                        }
+                       urlescputs(reply_inreplyto);
                        wprintf("\"><span>[</span>%s<span>]</span></a> ", _("ReplyAll"));
                }
 
                /* Forward */
                if (WC->wc_view == VIEW_MAILBOX) {
                        wprintf("<a href=\"display_enter?fwdquote=%ld?subject=", msgnum);
-                       if (strncasecmp(m_subject, "Fwd:", 4)) wprintf("Fwd:%20");
+                       if (strncasecmp(m_subject, "Fwd:", 4)) wprintf("Fwd:%%20");
                        urlescputs(m_subject);
                        wprintf("\"><span>[</span>%s<span>]</span></a> ", _("Forward"));
                }
@@ -1245,22 +1292,22 @@ void read_message(long msgnum, int printable_view, char *section) {
                                bq = 0;
                        }
                        wprintf("<tt>");
-                       url(buf);
+                       url(buf, sizeof(buf));
                        escputs(buf);
                        wprintf("</tt><br />\n");
                }
                wprintf("</i><br />");
        }
 
-       else /** HTML is fun, but we've got to strip it first */
-       if (!strcasecmp(mime_content_type, "text/html")) {
+       /* HTML is fun, but we've got to strip it first */
+       else if (!strcasecmp(mime_content_type, "text/html")) {
                output_html(mime_charset, (WC->wc_view == VIEW_WIKI ? 1 : 0));
        }
 
-       /** Unknown weirdness */
+       /* Unknown weirdness */
        else {
                wprintf(_("I don't know how to display %s"), mime_content_type);
-               wprintf("<br />\n", mime_content_type);
+               wprintf("<br />\n");
                while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { }
        }
 
@@ -1277,7 +1324,7 @@ ENDBODY:  /* If there are attached submessages, display them now... */
        }
 
 
-       /** Afterwards, offer links to download attachments 'n' such */
+       /* Afterwards, offer links to download attachments 'n' such */
        if ( (num_attach_links > 0) && (!section[0]) ) {
                for (i=0; i<num_attach_links; ++i) {
                        if (strcasecmp(attach_links[i].partnum, msg4_partnum)) {
@@ -1286,7 +1333,7 @@ ENDBODY:  /* If there are attached submessages, display them now... */
                }
        }
 
-       /** Handler for vCard parts */
+       /* Handler for vCard parts */
        if (!IsEmptyStr(vcard_partnum)) {
                part_source = load_mimepart(msgnum, vcard_partnum);
                if (part_source != NULL) {
@@ -1296,23 +1343,21 @@ ENDBODY:        /* If there are attached submessages, display them now... */
                                || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM))
                                || (WC->wc_view == VIEW_ADDRESSBOOK)
                        ) {
-                               wprintf("<a href=\"edit_vcard?"
-                                       "msgnum=%ld?partnum=%s\">",
+                               wprintf("<a href=\"edit_vcard?msgnum=%ld?partnum=%s\">",
                                        msgnum, vcard_partnum);
                                wprintf("[%s]</a>", _("edit"));
                        }
 
-                       /** In all cases, display the full card */
-                       display_vcard(part_source, 0, 1, NULL);
+                       /* In all cases, display the full card */
+                       display_vcard(part_source, 0, 1, NULL,msgnum);
                }
        }
 
-       /** Handler for calendar parts */
+       /* Handler for calendar parts */
        if (!IsEmptyStr(cal_partnum)) {
                part_source = load_mimepart(msgnum, cal_partnum);
                if (part_source != NULL) {
-                       cal_process_attachment(part_source,
-                                               msgnum, cal_partnum);
+                       cal_process_attachment(part_source, msgnum, cal_partnum);
                }
        }
 
@@ -1323,7 +1368,7 @@ ENDBODY:  /* If there are attached submessages, display them now... */
 
        wprintf("</div>\n");
 
-       /** end everythingamundo table */
+       /* end everythingamundo table */
        if (!printable_view) {
                wprintf("</div>\n");
        }
@@ -1341,41 +1386,40 @@ ENDBODY:        /* If there are attached submessages, display them now... */
 
 
 
-/**
- * \brief Unadorned HTML output of an individual message, suitable
+/*
+ * Unadorned HTML output of an individual message, suitable
  * for placing in a hidden iframe, for printing, or whatever
  *
- * \param msgnum_as_string Message number, as a string instead of as a long int
+ * msgnum_as_string == Message number, as a string instead of as a long int
  */
-void embed_message(char *msgnum_as_string) {
+void embed_message(void) {
        long msgnum = 0L;
 
-       msgnum = atol(msgnum_as_string);
-       begin_ajax_response();
+       msgnum = StrTol(WC->UrlFragment1);
        read_message(msgnum, 0, "");
-       end_ajax_response();
 }
 
 
-/**
- * \brief Printable view of a message
+/*
+ * Printable view of a message
  *
- * \param msgnum_as_string Message number, as a string instead of as a long int
+ * msgnum_as_string == Message number, as a string instead of as a long int
  */
-void print_message(char *msgnum_as_string) {
+void print_message(void) {
        long msgnum = 0L;
 
-       msgnum = atol(msgnum_as_string);
+       msgnum = StrTol(WC->UrlFragment1);
        output_headers(0, 0, 0, 0, 0, 0);
 
-       wprintf("Content-type: text/html\r\n"
+       hprintf("Content-type: text/html\r\n"
                "Server: %s\r\n"
-               "Connection: close\r\n",
+               "Connection: close\r\n"
                PACKAGE_STRING);
        begin_burst();
 
-       wprintf("\r\n\r\n<html>\n"
-               "<head><title>Printable view</title></head>\n"
+       wprintf("\r\n<html>\n<head><title>");
+       escputs(WC->wc_fullname);
+       wprintf("</title></head>\n"
                "<body onLoad=\" window.print(); window.close(); \">\n"
        );
        
@@ -1392,14 +1436,14 @@ void print_message(char *msgnum_as_string) {
  *
  * \param msgnum_as_string Message number, as a string instead of as a long int
  */
-void display_headers(char *msgnum_as_string) {
+void display_headers(void) {
        long msgnum = 0L;
        char buf[1024];
 
-       msgnum = atol(msgnum_as_string);
+       msgnum = StrTol(WC->UrlFragment1);
        output_headers(0, 0, 0, 0, 0, 0);
 
-       wprintf("Content-type: text/plain\r\n"
+       hprintf("Content-type: text/plain\r\n"
                "Server: %s\r\n"
                "Connection: close\r\n",
                PACKAGE_STRING);
@@ -1664,7 +1708,7 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers
                                bq = 0;
                        }
                        wprintf("<tt>");
-                       url(buf);
+                       url(buf, sizeof(buf));
                        msgescputs1(buf);
                        wprintf("</tt><br />");
                }
@@ -1677,7 +1721,7 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers
                        strcat(buf, "\n");
                        msgescputs(buf);
                }
-       }
+       }//// TODO: charset? utf8?
 
        /** Unknown weirdness ... don't know how to handle this content type */
        else {
@@ -1754,7 +1798,6 @@ ENDBODY:
  */
 void display_summarized(int num) {
        char datebuf[64];
-
        wprintf("<tr id=\"m%ld\" style=\"font-weight:%s;\" "
                "onMouseDown=\"CtdlMoveMsgMouseDown(event,%ld)\">",
                WC->summ[num].msgnum,
@@ -1778,8 +1821,26 @@ void display_summarized(int num) {
 
        wprintf("</tr>\n");
 }
-
-
+/**
+ * \brief Output a message row for the mobile view
+ * \param The row number 
+ */
+void display_mobile_summary(int num) {
+       char datebuf[64];
+       wprintf("\n<div><div id=\"m%ld\" style=\"font-weight:%s;\" "
+               "onClick=\"CtdlLoadMsgMouseDown(event,%ld)\">",
+               WC->summ[num].msgnum,
+               (WC->summ[num].is_new ? "bold" : "normal"),
+               WC->summ[num].msgnum
+       );
+               wprintf("<span>%s</span>",WC->summ[num].from);
+               wprintf("<span style=\"float: right;\">");
+               webcit_fmt_date(datebuf, WC->summ[num].date, 1);        /* brief */
+       escputs(datebuf);
+               wprintf("</span><br/><span class=\"subject\">");
+               wprintf(WC->summ[num].subj);
+               wprintf("</span></div><div id=\"m_%ld\" class=\"msgview\" onMouseDown=\"\"></div></div>",WC->summ[num].msgnum);
+}
 
 /**
  * \brief display the adressbook overview
@@ -1826,7 +1887,7 @@ void display_addressbook(long msgnum, char alpha) {
                if (vcard_source != NULL) {
 
                        /** Display the summary line */
-                       display_vcard(vcard_source, alpha, 0, NULL);
+                       display_vcard(vcard_source, alpha, 0, NULL,msgnum);
 
                        /** If it's my vCard I can edit it */
                        if (    (!strcasecmp(WC->wc_roomname, USERCONFIGROOM))
@@ -1917,7 +1978,7 @@ void fetch_ab_name(long msgnum, char *namebuf) {
                if (vcard_source != NULL) {
 
                        /* Grab the name off the card */
-                       display_vcard(vcard_source, 0, 0, namebuf);
+                       display_vcard(vcard_source, 0, 0, namebuf,msgnum);
 
                        free(vcard_source);
                }
@@ -2073,6 +2134,7 @@ int load_msg_ptrs(char *servcmd, int with_headers)
        char nodename[128];
        char inetaddr[128];
        char subject[1024];
+       char *ptr;
        int nummsgs;
        int sbjlen;
        int maxload = 0;
@@ -2117,12 +2179,6 @@ int load_msg_ptrs(char *servcmd, int with_headers)
                                WC->summ[nummsgs-1].msgnum = WC->msgarr[nummsgs-1];
                                safestrncpy(WC->summ[nummsgs-1].subj,
                                        _("(no subject)"), sizeof WC->summ[nummsgs-1].subj);
-                               if (!IsEmptyStr(fullname)) {
-                               /** Handle senders with RFC2047 encoding */
-                                       utf8ify_rfc822_string(fullname);
-                                       safestrncpy(WC->summ[nummsgs-1].from,
-                                               fullname, sizeof WC->summ[nummsgs-1].from);
-                               }
                                if (!IsEmptyStr(subject)) {
                                /** Handle subjects with RFC2047 encoding */
                                        utf8ify_rfc822_string(subject);
@@ -2131,35 +2187,41 @@ int load_msg_ptrs(char *servcmd, int with_headers)
                                }
                                sbjlen = Ctdl_Utf8StrLen(WC->summ[nummsgs-1].subj);
                                if (sbjlen > 75) {
-                                       char *ptr;
                                        ptr = Ctdl_Utf8StrCut(WC->summ[nummsgs-1].subj, 72);
 
                                        strcpy(ptr, "...");
                                }
 
-                               if (!IsEmptyStr(nodename)) {
-                                       if ( ((WC->room_flags & QR_NETWORK)
-                                          || ((strcasecmp(nodename, serv_info.serv_nodename)
-                                          && (strcasecmp(nodename, serv_info.serv_fqdn)))))
-                                       ) {
-                                               strcat(WC->summ[nummsgs-1].from, " @ ");
-                                               strcat(WC->summ[nummsgs-1].from, nodename);
-                                       }
+                               if (!IsEmptyStr(fullname)) {
+                               /** Handle senders with RFC2047 encoding */
+                                       utf8ify_rfc822_string(fullname);
+                                       safestrncpy(WC->summ[nummsgs-1].from,
+                                               fullname, sizeof WC->summ[nummsgs-1].from);
+                               }
+                               if ((!IsEmptyStr(nodename)) &&
+                                   ( ((WC->room_flags & QR_NETWORK)
+                                      || ((strcasecmp(nodename, serv_info.serv_nodename)
+                                                && (strcasecmp(nodename, serv_info.serv_fqdn)))))))
+                               {
+                                       strcat(WC->summ[nummsgs-1].from, " @ ");
+                                       strcat(WC->summ[nummsgs-1].from, nodename);
+                                       
+                               }
+                               sbjlen = Ctdl_Utf8StrLen(WC->summ[nummsgs-1].from);
+                               if (sbjlen > 25) {
+                                       ptr = Ctdl_Utf8StrCut(WC->summ[nummsgs-1].from, 23);
+                                       strcpy(ptr, "...");
                                }
 
                                WC->summ[nummsgs-1].date = datestamp;
-       
-                               /** Handle senders with RFC2047 encoding */
-                               utf8ify_rfc822_string(WC->summ[nummsgs-1].from);
-                               if (strlen(WC->summ[nummsgs-1].from) > 25) {
-                                       strcpy(&WC->summ[nummsgs-1].from[22], "...");
-                               }
                        }
                }
        }
        return (nummsgs);
 }
 
+
+typedef int (*QSortFunction) (const void*, const void*);
 /**
  * \brief qsort() compatible function to compare two longs in descending order.
  *
@@ -2276,6 +2338,84 @@ int summcmp_rdate(const void *s1, const void *s2) {
 }
 
 
+enum {
+       eUp,
+       eDown,
+       eNone
+};
+
+const char* SortIcons[3] = {
+       "static/up_pointer.gif",
+       "static/down_pointer.gif",
+       "static/sort_none.gif"
+};
+
+ enum  {/// SortByEnum
+       eDate,
+       eRDate,
+       eSubject,
+       eRSubject,
+       eSender,
+       eRSender,
+       eReverse,
+       eUnSet
+}; 
+
+/** SortEnum to plain string representation */
+static const char* SortByStrings[] = {
+       "date",
+       "rdate",
+       "subject", 
+       "rsubject", 
+       "sender",
+       "rsender",
+       "reverse",
+       "unset"
+};
+
+/** SortEnum to sort-Function Table */
+const QSortFunction SortFuncs[eUnSet] = {
+       summcmp_date,
+       summcmp_rdate,
+       summcmp_subj,
+       summcmp_rsubj,
+       summcmp_sender,
+       summcmp_rsender,
+       summcmp_rdate
+};
+
+/** given a SortEnum, which icon should we choose? */
+const int SortDateToIcon[eUnSet] = { eUp, eDown, eNone, eNone, eNone, eNone, eNone};
+const int SortSubjectToIcon[eUnSet] = { eNone, eNone, eUp, eDown, eNone, eNone, eNone};
+const int SortSenderToIcon[eUnSet] = { eNone, eNone, eNone, eNone, eUp, eDown, eNone};
+
+/** given a SortEnum, which would be the "opposite" search option? */
+const int DateInvertSortString[eUnSet] =  { eRDate, eDate, eDate, eDate, eDate, eDate, eDate};
+const int SubjectInvertSortString[eUnSet] =  { eSubject, eSubject, eRSubject, eUnSet, eSubject, eSubject, eSubject};
+const int SenderInvertSortString[eUnSet] =  { eSender, eSender, eSender, eSender, eRSender, eUnSet, eSender};
+
+
+/**
+ * \Brief Translates sortoption String to its SortEnum representation 
+ * \param SortBy string to translate
+ * \return the enum matching the string; defaults to RDate
+ */
+//SortByEnum 
+int StrToESort (StrBuf *sortby)
+{
+       int result = eDate;
+
+       if (!IsEmptyStr(ChrPtr(sortby))) while (result < eUnSet){
+                       if (!strcasecmp(ChrPtr(sortby), 
+                                       SortByStrings[result])) 
+                               return result;
+                       result ++;
+               }
+       return eRDate;
+}
+
+
+
 
 /**
  * \brief command loop for reading messages
@@ -2305,12 +2445,11 @@ void readloop(char *oper)
        int highest_displayed = 0;
        struct addrbookent *addrbook = NULL;
        int num_ab = 0;
-       char *sortby = NULL;
-       char sortpref_name[128];
-       char sortpref_value[128];
-       char *subjsort_button;
-       char *sendsort_button;
-       char *datesort_button;
+       StrBuf *sortby = NULL;
+       //SortByEnum 
+       int SortBy = eRDate;
+       StrBuf *sortpref_name;
+       StrBuf *sortpref_value;
        int bbs_reverse = 0;
        struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
 
@@ -2320,25 +2459,27 @@ void readloop(char *oper)
                return;
        }
 
-       startmsg = atol(bstr("startmsg"));
-       maxmsgs = atoi(bstr("maxmsgs"));
-       is_summary = atoi(bstr("is_summary"));
+       startmsg = lbstr("startmsg");
+       maxmsgs = ibstr("maxmsgs");
+       is_summary = (ibstr("is_summary") && !WCC->is_mobile);
        if (maxmsgs == 0) maxmsgs = DEFAULT_MAXMSGS;
 
-       snprintf(sortpref_name, sizeof sortpref_name, "sort %s", WCC->wc_roomname);
-       get_preference(sortpref_name, sortpref_value, sizeof sortpref_value);
+       sortpref_name = NewStrBuf ();
+       StrBufPrintf(sortpref_name, "sort %s", WCC->wc_roomname);
+       get_pref(sortpref_name, &sortpref_value);
 
-       sortby = bstr("sortby");
-       if ( (!IsEmptyStr(sortby)) && (strcasecmp(sortby, sortpref_value)) ) {
-               set_preference(sortpref_name, sortby, 1);
+       sortby = NewStrBufPlain(bstr("sortby"), -1);
+       if ( (!IsEmptyStr(ChrPtr(sortby))) && 
+            (strcasecmp(ChrPtr(sortby), ChrPtr(sortpref_value)) != 0)) {
+               set_pref(sortpref_name, sortby, 1);
+               sortpref_value = NULL;
+               sortpref_value = sortby;
        }
-       if (IsEmptyStr(sortby)) sortby = sortpref_value;
-
-       /** mailbox sort */
-       if (IsEmptyStr(sortby)) sortby = "rdate";
-
+       
+       FreeStrBuf(&sortpref_name);
+       SortBy = StrToESort(sortpref_value);
        /** message board sort */
-       if (!strcasecmp(sortby, "reverse")) {
+       if (SortBy == eReverse) {
                bbs_reverse = 1;
        }
        else {
@@ -2364,7 +2505,7 @@ void readloop(char *oper)
                strcpy(cmd, "MSGS ALL");
        }
 
-       if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1)) {
+       if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1) && !WCC->is_mobile) {
                is_summary = 1;
                if (!strcmp(oper, "do_search")) {
                        snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query"));
@@ -2385,13 +2526,17 @@ void readloop(char *oper)
                maxmsgs = 9999999;
        }
 
-       if (is_summary) {                       /**< fetch header summary */
+       if (is_summary || WCC->is_mobile) {                     /**< fetch header summary */
                snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1",
                        (!strcmp(oper, "do_search") ? "SEARCH" : "ALL"),
                        (!strcmp(oper, "do_search") ? bstr("query") : "")
                );
                startmsg = 1;
                maxmsgs = 9999999;
+       } 
+       if (WCC->is_mobile) {
+               maxmsgs = 20;
+               SortBy =  eRDate;
        }
 
        /**
@@ -2400,7 +2545,7 @@ void readloop(char *oper)
         * new messages.
         */
        strcpy(old_msgs, "");
-       if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR)){
+       if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){
                serv_puts("GTSN");
                serv_getln(buf, sizeof buf);
                if (buf[0] == '2') {
@@ -2408,7 +2553,7 @@ void readloop(char *oper)
                }
        }
 
-       is_singlecard = atoi(bstr("is_singlecard"));
+       is_singlecard = ibstr("is_singlecard");
 
        if (WCC->wc_default_view == VIEW_CALENDAR) {            /**< calendar */
                is_calendar = 1;
@@ -2427,11 +2572,10 @@ void readloop(char *oper)
        }
 
        if (is_notes) {
-               wprintf("<div align=center>%s</div>\n", _("Click on any note to edit it."));
                wprintf("<div id=\"new_notes_here\"></div>\n");
        }
 
-       nummsgs = load_msg_ptrs(cmd, is_summary);
+       nummsgs = load_msg_ptrs(cmd, (is_summary || WCC->is_mobile));
        if (nummsgs == 0) {
 
                if ((!is_tasks) && (!is_calendar) && (!is_notes) && (!is_addressbook)) {
@@ -2449,7 +2593,7 @@ void readloop(char *oper)
                goto DONE;
        }
 
-       if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR)){
+       if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){
                for (a = 0; a < nummsgs; ++a) {
                        /** Are you a new message, or an old message? */
                        if (is_summary) {
@@ -2472,62 +2616,11 @@ void readloop(char *oper)
                }
        }
 
-       if (is_summary) {
-               if (!strcasecmp(sortby, "subject")) {
-                       qsort(WCC->summ, WCC->num_summ,
-                               sizeof(struct message_summary), summcmp_subj);
-               }
-               else if (!strcasecmp(sortby, "rsubject")) {
-                       qsort(WCC->summ, WCC->num_summ,
-                               sizeof(struct message_summary), summcmp_rsubj);
-               }
-               else if (!strcasecmp(sortby, "sender")) {
-                       qsort(WCC->summ, WCC->num_summ,
-                               sizeof(struct message_summary), summcmp_sender);
-               }
-               else if (!strcasecmp(sortby, "rsender")) {
-                       qsort(WCC->summ, WCC->num_summ,
-                               sizeof(struct message_summary), summcmp_rsender);
-               }
-               else if (!strcasecmp(sortby, "date")) {
-                       qsort(WCC->summ, WCC->num_summ,
-                               sizeof(struct message_summary), summcmp_date);
-               }
-               else if (!strcasecmp(sortby, "rdate")) {
-                       qsort(WCC->summ, WCC->num_summ,
-                               sizeof(struct message_summary), summcmp_rdate);
-               }
-       }
-
-       if (!strcasecmp(sortby, "subject")) {
-               subjsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_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?is_summary=1?sortby=subject\"><img border=\"0\" src=\"static/up_pointer.gif\" /></a>" ;
-       }
-       else {
-               subjsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_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?is_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?is_summary=1?sortby=sender\"><img border=\"0\" src=\"static/up_pointer.gif\" /></a>" ;
-       }
-       else {
-               sendsort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_summary=1?sortby=sender\"><img border=\"0\" src=\"static/sort_none.gif\" /></a>" ;
+       if (is_summary || WCC->is_mobile) {
+               qsort(WCC->summ, WCC->num_summ,
+                     sizeof(struct message_summary), SortFuncs[SortBy]);
        }
 
-       if (!strcasecmp(sortby, "date")) {
-               datesort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_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?is_summary=1?sortby=date\"><img border=\"0\" src=\"static/up_pointer.gif\" /></a>" ;
-       }
-       else {
-               datesort_button = "<a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_summary=1?sortby=rdate\"><img border=\"0\" src=\"static/sort_none.gif\" /></a>" ;
-       }
 
        if (is_summary) {
 
@@ -2545,9 +2638,9 @@ void readloop(char *oper)
                        "<table cellspacing=0 style=\"width:100%%\">"
                        "<tr>"
                );
-               wprintf("<th width=%d%%>%s %s</th>"
-                       "<th width=%d%%>%s %s</th>"
-                       "<th width=%d%%>%s %s"
+               wprintf("<th width=%d%%>%s <a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_summary=1?sortby=%s\"><img border=\"0\" src=\"%s\" /></a> </th>\n"
+                       "<th width=%d%%>%s <a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_summary=1?sortby=%s\"><img border=\"0\" src=\"%s\" /></a> </th>\n"
+                       "<th width=%d%%>%s <a href=\"readfwd?startmsg=1?maxmsgs=9999999?is_summary=1?sortby=%s\"><img border=\"0\" src=\"%s\" /></a> \n"
                        "&nbsp;"
                        "<input type=\"submit\" name=\"delete_button\" id=\"delbutton\" "
                        " onClick=\"CtdlDeleteSelectedMessages(event)\" "
@@ -2556,22 +2649,28 @@ void readloop(char *oper)
                        "</tr>\n"
                        ,
                        SUBJ_COL_WIDTH_PCT,
-                       _("Subject"),   subjsort_button,
+                       _("Subject"),
+                       SortByStrings[SubjectInvertSortString[SortBy]],
+                       SortIcons[SortSubjectToIcon[SortBy]],
                        SENDER_COL_WIDTH_PCT,
-                       _("Sender"),    sendsort_button,
+                       _("Sender"),
+                       SortByStrings[SenderInvertSortString[SortBy]],
+                       SortIcons[SortSenderToIcon[SortBy]],
                        DATE_PLUS_BUTTONS_WIDTH_PCT,
-                       _("Date"),      datesort_button,
+                       _("Date"),
+                       SortByStrings[DateInvertSortString[SortBy]],
+                       SortIcons[SortDateToIcon[SortBy]],
                        _("Delete")
                );
                wprintf("</table></div></div>\n");
-
                wprintf("<div id=\"message_list\">"
 
                        "<div class=\"fix_scrollbar_bug\">\n"
-
                        "<table class=\"mailbox_summary\" id=\"summary_headers\" "
                        "cellspacing=0 style=\"width:100%%;-moz-user-select:none;\">"
                );
+       } else if (WCC->is_mobile) {
+               wprintf("<div id=\"message_list\">");
        }
 
 
@@ -2591,7 +2690,7 @@ void readloop(char *oper)
        if (is_bbview) {
                /** begin bbview scroller */
                wprintf("<form name=\"msgomatictop\" class=\"selector_top\" > \n <p>");
-               wprintf(_("Reading #"), lowest_displayed, highest_displayed);
+               wprintf(_("Reading #"));//// TODO this isn't used, should it? : , lowest_displayed, highest_displayed);
 
                wprintf("<select name=\"whichones\" size=\"1\" "
                        "OnChange=\"location.href=msgomatictop.whichones.options"
@@ -2667,14 +2766,6 @@ void readloop(char *oper)
                wprintf("</p></form>\n");
                /** end bbview scroller */
        }
-
-       if (is_notes)
-       {
-               wprintf ("<script src=\"/static/dragdrop.js\" type=\"text/javascript\"></script>\n");
-       }
-
-
-
        for (a = 0; a < nummsgs; ++a) {
                if ((WCC->msgarr[a] >= startmsg) && (num_displayed < maxmsgs)) {
 
@@ -2699,6 +2790,8 @@ void readloop(char *oper)
                        }
                        else if (is_notes) {
                                display_note(WCC->msgarr[a], WCC->summ[a].is_new);
+                       } else if (WCC->is_mobile) {
+                               display_mobile_summary(a);
                        }
                        else {
                                if (displayed_msgs == NULL) {
@@ -2737,7 +2830,7 @@ void readloop(char *oper)
                wprintf("</table>"
                        "</div>\n");                    /**< end of 'fix_scrollbar_bug' div */
                wprintf("</div>");                      /**< end of 'message_list' div */
-
+               
                /** Here's the grab-it-to-resize-the-message-list widget */
                wprintf("<div id=\"resize_msglist\" "
                        "onMouseDown=\"CtdlResizeMsgListMouseDown(event)\">"
@@ -2746,6 +2839,8 @@ void readloop(char *oper)
                );
 
                wprintf("<div id=\"preview_pane\">");   /**< The preview pane will initially be empty */
+       } else if (WCC->is_mobile) {
+               wprintf("</div>");
        }
 
        /**
@@ -2762,7 +2857,7 @@ void readloop(char *oper)
        if (is_bbview) {
                /** begin bbview scroller */
                wprintf("<form name=\"msgomatic\" class=\"selector_bottom\" > \n <p>");
-               wprintf(_("Reading #"), lowest_displayed, highest_displayed);
+               wprintf(_("Reading #")); /// TODO: this isn't used: , lowest_displayed, highest_displayed);
 
                wprintf("<select name=\"whichones\" size=\"1\" "
                        "OnChange=\"location.href=msgomatic.whichones.options"
@@ -2838,40 +2933,6 @@ void readloop(char *oper)
                /** end bbview scroller */
        }
        
-       if (is_notes)
-       {
-//             wprintf ("</div>\n");
-               wprintf ("<div id=\"wastebin\" align=middle>Drop notes here to remove them.</div>\n");
-               wprintf ("<script type=\"text/javascript\">\n");
-//             wprintf ("//<![CDATA[\n");
-               wprintf ("Droppables.add(\"wastebin\",\n");
-               wprintf ("\t{\n");
-               wprintf ("\t\taccept:'notes',\n");
-               wprintf ("\t\tonDrop:function(element)\n");
-               wprintf ("\t\t{\n");
-               wprintf ("\t\t\tElement.hide(element);\n");
-               wprintf ("\t\t\tnew Ajax.Updater('notes', 'delnote',\n");
-               wprintf ("\t\t\t{\n");
-               wprintf ("\t\t\t\tasynchronous:true,\n");
-               wprintf ("\t\t\t\tevalScripts:true,\n");
-               wprintf ("\t\t\t\tonComplete:function(request)\n");
-               wprintf ("\t\t\t\t{\n");
-               wprintf ("\t\t\t\t\tElement.hide('indicator')\n");
-               wprintf ("\t\t\t\t},\n");
-               wprintf ("\t\t\t\tonLoading:function(request)\n");
-               wprintf ("\t\t\t\t{\n");
-               wprintf ("\t\t\t\t\tElement.show('indicator')\n");
-               wprintf ("\t\t\t\t},\n");
-               wprintf ("\t\t\t\tparameters:'id=' + encodeURIComponent(element.id)\n");
-               wprintf ("\t\t\t})\n");
-               wprintf ("\t\t}\n");
-               wprintf ("\t})\n");
-//             wprintf ("//]]>\n");
-               wprintf ("</script>\n");
-       }
-
-
-
 DONE:
        if (is_tasks) {
                do_tasks_view();        /** Render the task list */
@@ -3017,11 +3078,11 @@ void post_message(void)
        struct wcsession *WCC = WC;
        char *ptr = NULL;
 
-       if (!IsEmptyStr(bstr("force_room"))) {
+       if (havebstr("force_room")) {
                gotoroom(bstr("force_room"));
        }
 
-       if (GetHash(WCC->urlstrings, HKEY("display_name"), &U)) {
+       if (GetHash(WC->urlstrings, HKEY("display_name"), &U)) {
                u = (urlcontent*) U;
                display_name = u->url_data;
                dpLen = u->url_data_size;
@@ -3078,13 +3139,13 @@ void post_message(void)
                return;
        }
 
-       if (!IsEmptyStr(bstr("cancel_button"))) {
+       if (havebstr("cancel_button")) {
                sprintf(WCC->ImportantMessage, 
                        _("Cancelled.  Message was not posted."));
-       } else if (!IsEmptyStr(bstr("attach_button"))) {
+       } else if (havebstr("attach_button")) {
                display_enter();
                return;
-       } else if (atol(bstr("postseq")) == dont_post) {
+       } else if (lbstr("postseq") == dont_post) {
                sprintf(WCC->ImportantMessage, 
                        _("Automatically cancelled because you have already "
                        "saved this message."));
@@ -3109,15 +3170,17 @@ void post_message(void)
                } 
                lprintf(9, "Converted: %s\n", references);
 
-               if (GetHash(WCC->urlstrings, HKEY("subject"), &U)) {
-                       u = (urlcontent*) U;
+               if (havebstr("subject")) {
+                       char *Subj;
+                       size_t SLen;
                        /*
                         * make enough room for the encoded string; 
                         * plus the QP header 
                         */
-                       len = u->url_data_size * 3 + 32;
+                       Subj = xbstr("subject", &SLen);
+                       len = SLen * 3 + 32;
                        encoded_subject = malloc (len);
-                       len = webcit_rfc2047encode(encoded_subject, len, u->url_data, u->url_data_size);
+                       len = webcit_rfc2047encode(encoded_subject, len, Subj, SLen);
                        if (len < 0) {
                                free (encoded_subject);
                                return;
@@ -3155,16 +3218,16 @@ void post_message(void)
                if (encoded_subject) free(encoded_subject);
                if (buf[0] == '4') {
                        post_mime_to_server();
-                       if (  (!IsEmptyStr(bstr("recp")))
-                          || (!IsEmptyStr(bstr("cc"  )))
-                          || (!IsEmptyStr(bstr("bcc" )))
+                       if (  (havebstr("recp"))
+                          || (havebstr("cc"  ))
+                          || (havebstr("bcc" ))
                        ) {
                                sprintf(WCC->ImportantMessage, _("Message has been sent.\n"));
                        }
                        else {
                                sprintf(WC->ImportantMessage, _("Message has been posted.\n"));
                        }
-                       dont_post = atol(bstr("postseq"));
+                       dont_post = lbstr("postseq");
                } else {
                        lprintf(9, "%s:%d: server post error: %s\n", __FILE__, __LINE__, buf);
                        sprintf(WC->ImportantMessage, "%s", &buf[4]);
@@ -3179,13 +3242,13 @@ void post_message(void)
         *  We may have been supplied with instructions regarding the location
         *  to which we must return after posting.  If found, go there.
         */
-       if (!IsEmptyStr(bstr("return_to"))) {
+       if (havebstr("return_to")) {
                http_redirect(bstr("return_to"));
        }
        /**
         *  If we were editing a page in a wiki room, go to that page now.
         */
-       else if (!IsEmptyStr(bstr("wikipage"))) {
+       else if (havebstr("wikipage")) {
                snprintf(buf, sizeof buf, "wiki?page=%s", bstr("wikipage"));
                http_redirect(buf);
        }
@@ -3206,26 +3269,28 @@ void post_message(void)
 void display_enter(void)
 {
        char buf[SIZ];
-       char ebuf[SIZ];
+       StrBuf *ebuf;
        long now;
        char *display_name;
        struct wc_attachment *att;
        int recipient_required = 0;
        int subject_required = 0;
        int recipient_bad = 0;
-       int i;
        int is_anonymous = 0;
        long existing_page = (-1L);
+       size_t dplen;
+       struct wcsession *WCC = WC;
 
        now = time(NULL);
 
-       if (!IsEmptyStr(bstr("force_room"))) {
+       if (havebstr("force_room")) {
                gotoroom(bstr("force_room"));
        }
 
-       display_name = bstr("display_name");
+       display_name = xbstr("display_name", &dplen);
        if (!strcmp(display_name, "__ANONYMOUS__")) {
                display_name = "";
+               dplen = 0;
                is_anonymous = 1;
        }
 
@@ -3237,7 +3302,7 @@ void display_enter(void)
                recipient_required = 1;
        }
        else if (buf[0] != '2') {               /** Any other error means that we cannot continue */
-               sprintf(WC->ImportantMessage, "%s", &buf[4]);
+               sprintf(WCC->ImportantMessage, "%s", &buf[4]);
                readloop("readnew");
                return;
        }
@@ -3251,8 +3316,8 @@ void display_enter(void)
         * Are we perhaps in an address book view?  If so, then an "enter
         * message" command really means "add new entry."
         */
-       if (WC->wc_default_view == VIEW_ADDRESSBOOK) {
-               do_edit_vcard(-1, "", "", WC->wc_roomname);
+       if (WCC->wc_default_view == VIEW_ADDRESSBOOK) {
+               do_edit_vcard(-1, "", "", WCC->wc_roomname);
                return;
        }
 
@@ -3260,7 +3325,7 @@ void display_enter(void)
         * Are we perhaps in a calendar room?  If so, then an "enter
         * message" command really means "add new calendar item."
         */
-       if (WC->wc_default_view == VIEW_CALENDAR) {
+       if (WCC->wc_default_view == VIEW_CALENDAR) {
                display_edit_event();
                return;
        }
@@ -3269,7 +3334,7 @@ void display_enter(void)
         * Are we perhaps in a tasks view?  If so, then an "enter
         * message" command really means "add new task."
         */
-       if (WC->wc_default_view == VIEW_TASKS) {
+       if (WCC->wc_default_view == VIEW_TASKS) {
                display_edit_task();
                return;
        }
@@ -3287,18 +3352,39 @@ void display_enter(void)
 
        /* Now check our actual recipients if there are any */
        if (recipient_required) {
-               sprintf(buf, "ENT0 0|%s|%d|0||%s||%s|%s|%s",
-                       bstr("recp"),
-                       is_anonymous,
-                       display_name,
-                       bstr("cc"), bstr("bcc"), bstr("wikipage"));
-               serv_puts(buf);
+               const char *Recp = ""; 
+               const char *Cc = "";
+               const char *Bcc = "";
+               const char *Wikipage = "";
+               char *CmdBuf = NULL;;
+               size_t len = 0;
+               size_t nLen;
+               const char CMD[] = "ENT0 0|%s|%d|0||%s||%s|%s|%s";
+               
+               len = sizeof(CMD) + dplen;
+               Recp = xbstr("recp", &nLen);
+               len += nLen;
+               Cc = xbstr("cc", &nLen);
+               len += nLen;
+               Bcc = xbstr("bcc", &nLen);
+               len += nLen;
+               Wikipage = xbstr("wikipage", &nLen);
+               len += nLen;
+               
+
+               CmdBuf = (char*) malloc (len + 1);
+
+               snprintf(CmdBuf, len, CMD,
+                        Recp, is_anonymous,
+                        display_name,
+                        Cc, Bcc, Wikipage);
+               serv_puts(CmdBuf);
                serv_getln(buf, sizeof buf);
 
                if (!strncmp(buf, "570", 3)) {  /** 570 means we have an invalid recipient listed */
-                       if (!IsEmptyStr(bstr("recp")) && 
-                           !IsEmptyStr(bstr("cc"  )) && 
-                           !IsEmptyStr(bstr("bcc" ))) {
+                       if (havebstr("recp") && 
+                           havebstr("cc"  ) && 
+                           havebstr("bcc" )) {
                                recipient_bad = 1;
                        }
                }
@@ -3319,13 +3405,13 @@ void display_enter(void)
                "name=\"enterform\""
                ">\n");
        wprintf("<input type=\"hidden\" name=\"postseq\" value=\"%ld\">\n", now);
-       if (WC->wc_view == VIEW_WIKI) {
+       if (WCC->wc_view == VIEW_WIKI) {
                wprintf("<input type=\"hidden\" name=\"wikipage\" value=\"%s\">\n", bstr("wikipage"));
        }
        wprintf("<input type=\"hidden\" name=\"return_to\" value=\"%s\">\n", bstr("return_to"));
-       wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
+       wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WCC->nonce);
        wprintf("<input type=\"hidden\" name=\"force_room\" value=\"");
-       escputs(WC->wc_roomname);
+       escputs(WCC->wc_roomname);
        wprintf("\">\n");
        wprintf("<input type=\"hidden\" name=\"references\" value=\"");
        escputs(bstr("references"));
@@ -3377,9 +3463,9 @@ void display_enter(void)
                }
        }
 
-       if (WC->room_flags & QR_ANONOPT) {
+       if (WCC->room_flags & QR_ANONOPT) {
                wprintf("<option %s value=\"__ANONYMOUS__\">%s</option>\n",
-                       ((!strcasecmp(bstr("__ANONYMOUS__"), WC->wc_fullname)) ? "selected" : ""),
+                       ((!strcasecmp(bstr("__ANONYMOUS__"), WCC->wc_fullname)) ? "selected" : ""),
                        _("Anonymous")
                );
        }
@@ -3406,7 +3492,7 @@ void display_enter(void)
        }
 
        wprintf(_(" <I>in</I> "));
-       escputs(WC->wc_roomname);
+       escputs(WCC->wc_roomname);
 
        wprintf("</td></tr>");
 
@@ -3418,8 +3504,7 @@ void display_enter(void)
                wprintf(_("To:"));
                wprintf("</label></th>"
                        "<td><input autocomplete=\"off\" type=\"text\" name=\"recp\" id=\"recp_id\" value=\"");
-               ccraw = bstr("recp");
-               len = strlen(ccraw);
+               ccraw = xbstr("recp", &len);
                copy = (char*) malloc(len * 2 + 1);
                memcpy(copy, ccraw, len + 1); 
                utf8ify_rfc822_string(copy);
@@ -3446,8 +3531,7 @@ void display_enter(void)
                wprintf(_("CC:"));
                wprintf("</label></th>"
                        "<td><input autocomplete=\"off\" type=\"text\" name=\"cc\" id=\"cc_id\" value=\"");
-               ccraw = bstr("cc");
-               len = strlen(ccraw);
+               ccraw = xbstr("cc", &len);
                copy = (char*) malloc(len * 2 + 1);
                memcpy(copy, ccraw, len + 1); 
                utf8ify_rfc822_string(copy);
@@ -3461,8 +3545,7 @@ void display_enter(void)
                wprintf(_("BCC:"));
                wprintf("</label></th>"
                        "<td><input autocomplete=\"off\" type=\"text\" name=\"bcc\" id=\"bcc_id\" value=\"");
-               ccraw = bstr("bcc");
-               len = strlen(ccraw);
+               ccraw = xbstr("bcc", &len);
                copy = (char*) malloc(len * 2 + 1);
                memcpy(copy, ccraw, len + 1); 
                utf8ify_rfc822_string(copy);
@@ -3502,23 +3585,23 @@ void display_enter(void)
        msgescputs(bstr("msgtext"));
 
        /* If we're forwarding a message, insert it here... */
-       if (atol(bstr("fwdquote")) > 0L) {
+       if (lbstr("fwdquote") > 0L) {
                wprintf("<br><div align=center><i>");
                wprintf(_("--- forwarded message ---"));
                wprintf("</i></div><br>");
-               pullquote_message(atol(bstr("fwdquote")), 1, 1);
+               pullquote_message(lbstr("fwdquote"), 1, 1);
        }
 
        /** If we're replying quoted, insert the quote here... */
-       else if (atol(bstr("replyquote")) > 0L) {
+       else if (lbstr("replyquote") > 0L) {
                wprintf("<br>"
                        "<blockquote>");
-               pullquote_message(atol(bstr("replyquote")), 0, 1);
+               pullquote_message(lbstr("replyquote"), 0, 1);
                wprintf("</blockquote><br>");
        }
 
        /** If we're editing a wiki page, insert the existing page here... */
-       else if (WC->wc_view == VIEW_WIKI) {
+       else if (WCC->wc_view == VIEW_WIKI) {
                safestrncpy(buf, bstr("wikipage"), sizeof buf);
                str_wiki_index(buf);
                existing_page = locate_message_by_uid(buf);
@@ -3528,36 +3611,42 @@ void display_enter(void)
        }
 
        /** Insert our signature if appropriate... */
-       if ( (WC->is_mailbox) && (strcmp(bstr("sig_inserted"), "yes")) ) {
-               get_preference("use_sig", buf, sizeof buf);
-               if (!strcasecmp(buf, "yes")) {
-                       int len;
-                       get_preference("signature", ebuf, sizeof ebuf);
-                       euid_unescapize(buf, ebuf);
+       if ( (WCC->is_mailbox) && !yesbstr("sig_inserted") ) {
+               int UseSig;
+               get_pref_yesno("use_sig", &UseSig, 0);
+               if (UseSig) {
+                       StrBuf *Sig;
+                       const char *sig, *esig;
+
+                       get_preference("signature", &ebuf);
+                       Sig = NewStrBuf();
+                       StrBufEUid_unescapize(Sig, ebuf);
+                       sig = ChrPtr(Sig);
+                       esig = sig + StrLength(Sig);
                        wprintf("<br>--<br>");
-                       len = strlen(buf);
-                       for (i=0; i<len; ++i) {
-                               if (buf[i] == '\n') {
+                       while (sig <= esig) {
+                               if (*sig == '\n') {
                                        wprintf("<br>");
                                }
-                               else if (buf[i] == '<') {
+                               else if (*sig == '<') {
                                        wprintf("&lt;");
                                }
-                               else if (buf[i] == '>') {
+                               else if (*sig == '>') {
                                        wprintf("&gt;");
                                }
-                               else if (buf[i] == '&') {
+                               else if (*sig == '&') {
                                        wprintf("&amp;");
                                }
-                               else if (buf[i] == '\"') {
+                               else if (*sig == '\"') {
                                        wprintf("&quot;");
                                }
-                               else if (buf[i] == '\'') {
+                               else if (*sig == '\'') {
                                        wprintf("&#39;");
                                }
-                               else if (isprint(buf[i])) {
-                                       wprintf("%c", buf[i]);
-                               }
+                               else /* since we're utf 8, is this a good idea? if (isprint(*sig))*/ {
+                                       wprintf("%c", *sig);
+                               } 
+                               sig ++;
                        }
                }
        }
@@ -3579,7 +3668,7 @@ void display_enter(void)
        wprintf(_("Attachments:"));
        wprintf(" ");
        wprintf("<select name=\"which_attachment\" size=1>");
-       for (att = WC->first_attachment; att != NULL; att = att->next) {
+       for (att = WCC->first_attachment; att != NULL; att = att->next) {
                wprintf("<option value=\"");
                urlescputs(att->filename);
                wprintf("\">");
@@ -3617,7 +3706,7 @@ void delete_msg(void)
        long msgid;
        char buf[SIZ];
 
-       msgid = atol(bstr("msgid"));
+       msgid = lbstr("msgid");
 
        if (WC->wc_is_trash) {  /** Delete from Trash is a real delete */
                serv_printf("DELE %ld", msgid); 
@@ -3641,9 +3730,9 @@ void move_msg(void)
        long msgid;
        char buf[SIZ];
 
-       msgid = atol(bstr("msgid"));
+       msgid = lbstr("msgid");
 
-       if (!IsEmptyStr(bstr("move_button"))) {
+       if (havebstr("move_button")) {
                sprintf(buf, "MOVE %ld|%s", msgid, bstr("target_room"));
                serv_puts(buf);
                serv_getln(buf, sizeof buf);
@@ -3659,8 +3748,8 @@ void move_msg(void)
 
 
 
-/**
- * \brief Confirm move of a message
+/*
+ * Confirm move of a message
  */
 void confirm_move_msg(void)
 {
@@ -3668,7 +3757,7 @@ void confirm_move_msg(void)
        char buf[SIZ];
        char targ[SIZ];
 
-       msgid = atol(bstr("msgid"));
+       msgid = lbstr("msgid");
 
 
        output_headers(1, 1, 2, 0, 0, 0);
@@ -3686,7 +3775,7 @@ void confirm_move_msg(void)
        wprintf("<br />\n");
 
        wprintf("<form METHOD=\"POST\" action=\"move_msg\">\n");
-       wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
+       wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
        wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n", bstr("msgid"));
 
        wprintf("<SELECT NAME=\"target_room\" SIZE=5>\n");
@@ -3712,5 +3801,28 @@ void confirm_move_msg(void)
        wDumpContent(1);
 }
 
+void readnew(void) { readloop("readnew");}
+void readold(void) { readloop("readold");}
+void readfwd(void) { readloop("readfwd");}
+void headers(void) { readloop("headers");}
+void do_search(void) { readloop("do_search");}
 
-/*@}*/
+void 
+InitModule_MSG
+(void)
+{
+       WebcitAddUrlHandler(HKEY("readnew"), readnew, 0);
+       WebcitAddUrlHandler(HKEY("readold"), readold, 0);
+       WebcitAddUrlHandler(HKEY("readfwd"), readfwd, 0);
+       WebcitAddUrlHandler(HKEY("headers"), headers, 0);
+       WebcitAddUrlHandler(HKEY("do_search"), do_search, 0);
+       WebcitAddUrlHandler(HKEY("display_enter"), display_enter, 0);
+       WebcitAddUrlHandler(HKEY("post"), post_message, 0);
+       WebcitAddUrlHandler(HKEY("move_msg"), move_msg, 0);
+       WebcitAddUrlHandler(HKEY("delete_msg"), delete_msg, 0);
+       WebcitAddUrlHandler(HKEY("confirm_move_msg"), confirm_move_msg, 0);
+       WebcitAddUrlHandler(HKEY("msg"), embed_message, NEED_URL|AJAX);
+       WebcitAddUrlHandler(HKEY("printmsg"), print_message, NEED_URL);
+       WebcitAddUrlHandler(HKEY("msgheaders"), display_headers, NEED_URL);
+       return ;
+}