X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fmessages.c;h=d4036a13386df7b803d25f1703e1f97fe79a06c1;hb=be00863d58a61c8ee070e346fb0ac70c5b7f6a8e;hp=fdf9f1240d4ae44fb709e2e6d5c2803d7daba07d;hpb=c51db4fd0350a95c7968f518db7b4bfa297e128f;p=citadel.git diff --git a/webcit/messages.c b/webcit/messages.c index fdf9f1240..d4036a133 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -1,14 +1,11 @@ /* * $Id$ - */ -/** - * \defgroup MsgDisp Functions which deal with the fetching and displaying of messages. - * \ingroup WebcitDisplayItems + * + * Functions which deal with the fetching and displaying of messages. * */ -/*@{*/ + #include "webcit.h" -#include "vcard.h" #include "webserver.h" #include "groupdav.h" @@ -16,7 +13,9 @@ #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) */ @@ -29,13 +28,13 @@ struct addrbookent { #ifdef HAVE_ICONV -/** - * \brief Wrapper around iconv_open() - * Our version adds aliases for non-standard Microsoft charsets - * such as 'MS950', aliasing them to names like 'CP950' +/* + * Wrapper around iconv_open() + * Our version adds aliases for non-standard Microsoft charsets + * such as 'MS950', aliasing them to names like 'CP950' * - * \param tocode Target encoding - * \param fromcode Source encoding + * tocode Target encoding + * fromcode Source encoding */ iconv_t ctdl_iconv_open(const char *tocode, const char *fromcode) { @@ -54,14 +53,30 @@ iconv_t ctdl_iconv_open(const char *tocode, const char *fromcode) } -/** - * \brief Handle subjects with RFC2047 encoding - * such as: + +inline char *FindNextEnd (char *bptr) +{ + char * end; + /* Find the next ?Q? */ + end = strchr(bptr + 2, '?'); + if (end == NULL) return NULL; + if (((*(end + 1) == 'B') || (*(end + 1) == 'Q')) && + (*(end + 2) == '?')) { + /* skip on to the end of the cluster, the next ?= */ + end = strstr(end + 3, "?="); + } + else + /* sort of half valid encoding, try to find an end. */ + end = strstr(bptr, "?="); + return end; +} + +/* + * Handle subjects with RFC2047 encoding such as: * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?= - * \param buf the stringbuffer to process */ void utf8ify_rfc822_string(char *buf) { - char *start, *end; + char *start, *end, *next, *nextend, *ptr; char newbuf[1024]; char charset[128]; char encoding[16]; @@ -74,10 +89,10 @@ void utf8ify_rfc822_string(char *buf) { char *isav; /**< Saved pointer to input buffer */ char *osav; /**< Saved pointer to output buffer */ int passes = 0; - int i, len; + int i, len, delta; int illegal_non_rfc2047_encoding = 0; - /** Sometimes, badly formed messages contain strings which were simply + /* Sometimes, badly formed messages contain strings which were simply * written out directly in some foreign character set instead of * using RFC2047 encoding. This is illegal but we will attempt to * handle it anyway by converting from a user-specified default @@ -91,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; @@ -113,10 +129,58 @@ void utf8ify_rfc822_string(char *buf) { } } - /** Now we handle foreign character sets properly encoded - * in RFC2047 format. + /* pre evaluate the first pair */ + nextend = end = NULL; + len = strlen(buf); + start = strstr(buf, "=?"); + if (start != NULL) + end = FindNextEnd (start); + + while ((start != NULL) && (end != NULL)) + { + next = strstr(end, "=?"); + if (next != NULL) + nextend = FindNextEnd(next); + if (nextend == NULL) + next = NULL; + + /* did we find two partitions */ + if ((next != NULL) && + ((next - end) > 2)) + { + ptr = end + 2; + while ((ptr < next) && + (isspace(*ptr) || + (*ptr == '\r') || + (*ptr == '\n') || + (*ptr == '\t'))) + ptr ++; + /* did we find a gab just filled with blanks? */ + if (ptr == next) + { + memmove (end + 2, + next, + len - (next - start)); + + /* now terminate the gab at the end */ + delta = (next - end) - 2; + len -= delta; + buf[len] = '\0'; + + /* move next to its new location. */ + next -= delta; + nextend -= delta; + } + } + /* our next-pair is our new first pair now. */ + start = next; + end = nextend; + } + + /* Now we handle foreign character sets properly encoded + * in RFC2047 format. */ - while (start=strstr(buf, "=?"), end=strstr(buf, "?="), + while (start=strstr(buf, "=?"), end=FindNextEnd((start != NULL)? start : buf), ((start != NULL) && (end != NULL) && (end > start)) ) { extract_token(charset, start, 1, '?', sizeof charset); @@ -185,7 +249,7 @@ void utf8ify_rfc822_string(char *buf) { free(isav); - /** + /* * Since spammers will go to all sorts of absurd lengths to get their * messages through, there are LOTS of corrupt headers out there. * So, prevent a really badly formed RFC2047 header from throwing @@ -196,6 +260,9 @@ void utf8ify_rfc822_string(char *buf) { } } +#else +inline void utf8ify_rfc822_string(char *a){}; + #endif @@ -209,58 +276,82 @@ void utf8ify_rfc822_string(char *buf) { * \param target Target buffer. * \param maxlen Maximum size of target buffer. * \param source Source string to be encoded. + * \param SourceLen Length of the source string + * \returns encoded length; -1 if non success. */ -void rfc2047encode(char *target, int maxlen, char *source) +int webcit_rfc2047encode(char *target, int maxlen, char *source, long SourceLen) { + const char headerStr[] = "=?UTF-8?Q?"; int need_to_encode = 0; - int i, len; + int i = 0; + int len; unsigned char ch; - if (target == NULL) return; - len = strlen(source); - for (i=0; i 126)) { + if ((source == NULL) || + (target == NULL) || + (SourceLen > maxlen)) return -1; + + while ((!IsEmptyStr (&source[i])) && + (need_to_encode == 0) && + (i < SourceLen) ) { + if (((unsigned char) source[i] < 32) || + ((unsigned char) source[i] > 126)) { need_to_encode = 1; - i = len; ///< shortcut. won't become more than 1 } + i++; } if (!need_to_encode) { - safestrncpy(target, source, maxlen); - return; + memcpy (target, source, SourceLen); + target[SourceLen] = '\0'; + return SourceLen; } - - strcpy(target, "=?UTF-8?Q?"); - for (i=0; i maxlen) + return -1; + memcpy (target, headerStr, sizeof (headerStr)); + 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[strlen(target)], "=%02X", ch); + sprintf(&target[len], "=%02X", ch); + len += 3; } else { - sprintf(&target[strlen(target)], "%c", ch); + sprintf(&target[len], "%c", ch); + len ++; } } - strcat(target, "?="); + if (len + 2 < maxlen) { + strcat(&target[len], "?="); + len +=2; + return len; + } + else + return -1; } -/** - * \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)) @@ -291,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'; } @@ -383,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; @@ -446,7 +556,10 @@ void display_parsed_vcard(struct vCard *v, int full) { } len = strlen(v->prop[i].value); - + /* if we have some untagged QP, detect it here. */ + if (!is_qp && (strstr(v->prop[i].value, "=?")!=NULL)) + utf8ify_rfc822_string(v->prop[i].value); + if (is_qp) { // %ff can become 6 bytes in utf8 thisvalue = malloc(len * 2 + 3); @@ -492,18 +605,26 @@ void display_parsed_vcard(struct vCard *v, int full) { } else if (!strcasecmp(firsttoken, "email")) { + size_t len; if (!IsEmptyStr(mailto)) strcat(mailto, "
"); strcat(mailto, ""); + len = strlen(mailto); + urlesc(&mailto[len], SIZ - len, "\""); + len = strlen(mailto); + urlesc(&mailto[len], SIZ - len, fullname); + len = strlen(mailto); + urlesc(&mailto[len], SIZ - len, "\" <"); + len = strlen(mailto); + urlesc(&mailto[len], SIZ - len, thisvalue); + len = strlen(mailto); + urlesc(&mailto[len], SIZ - len, ">"); strcat(mailto, "\">"); - stresc(&mailto[strlen(mailto)], thisvalue, 1, 1); + len = strlen(mailto); + stresc(mailto+len, SIZ - len, thisvalue, 1, 1); strcat(mailto, ""); } else if (!strcasecmp(firsttoken, "tel")) { @@ -542,6 +663,14 @@ void display_parsed_vcard(struct vCard *v, int full) { wprintf("\n"); } } + /* else if (!strcasecmp(firsttoken, "photo") && full && pass == 2) { + // Only output on second pass + wprintf(""); + wprintf(_("Photo:")); + wprintf(""); + wprintf("\"Contact",msgnum); + wprintf("\n"); + } */ else if (!strcasecmp(firsttoken, "version")) { /* ignore */ } @@ -616,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]; @@ -628,6 +759,7 @@ void display_vcard(char *vcard_source, char alpha, int full, char *storename) { name = vcard_get_prop(v, "n", 1, 0, 0); if (name != NULL) { + utf8ify_rfc822_string(name); strcpy(buf, name); this_alpha = buf[0]; } @@ -639,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); @@ -652,40 +784,45 @@ struct attach_link { }; -/** - * \brief I wanna SEE that message! - * \param msgnum the citadel number of the message to display - * \param printable_view are we doing a print view? - * \param section Optional for encapsulated message/rfc822 submessage) +/* + * I wanna SEE that message! + * + * msgnum Message number to display + * printable_view Nonzero to display a printable view + * section Optional for encapsulated message/rfc822 submessage */ void read_message(long msgnum, int printable_view, char *section) { char buf[SIZ]; - char mime_partnum[256]; - char mime_name[256]; - char mime_filename[256]; - char mime_content_type[256]; - char mime_charset[256]; - char mime_disposition[256]; + char mime_partnum[256] = ""; + char mime_name[256] = ""; + char mime_filename[256] = ""; + char escaped_mime_filename[256] = ""; + char mime_content_type[256] = ""; + const char *mime_content_type_ptr; + char mime_charset[256] = ""; + char mime_disposition[256] = ""; int mime_length; struct attach_link *attach_links = NULL; int num_attach_links = 0; - char mime_submessages[256]; - char m_subject[256]; - char m_cc[1024]; - char from[256]; - char node[256]; - char rfca[256]; - char reply_to[512]; - char reply_all[4096]; - char now[64]; + char mime_submessages[256] = ""; + char m_subject[1024] = ""; + char m_cc[1024] = ""; + char from[256] = ""; + char node[256] = ""; + char rfca[256] = ""; + 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; int bq = 0; int i = 0; - char vcard_partnum[256]; - char cal_partnum[256]; + char vcard_partnum[256] = ""; + char cal_partnum[256] = ""; char *part_source = NULL; - char msg4_partnum[32]; + char msg4_partnum[32] = ""; #ifdef HAVE_ICONV iconv_t ic = (iconv_t)(-1) ; char *ibuf; /**< Buffer of characters to be converted */ @@ -695,13 +832,6 @@ void read_message(long msgnum, int printable_view, char *section) { char *osav; /**< Saved pointer to output buffer */ #endif - strcpy(from, ""); - strcpy(node, ""); - strcpy(rfca, ""); - strcpy(reply_to, ""); - strcpy(reply_all, ""); - strcpy(vcard_partnum, ""); - strcpy(cal_partnum, ""); strcpy(mime_content_type, "text/plain"); strcpy(mime_charset, "us-ascii"); strcpy(mime_submessages, ""); @@ -746,9 +876,7 @@ void read_message(long msgnum, int printable_view, char *section) { strcpy(from, &buf[5]); wprintf(_("from ")); wprintf(""); escputs(from); @@ -757,6 +885,12 @@ void read_message(long msgnum, int printable_view, char *section) { if (!strncasecmp(buf, "subj=", 5)) { safestrncpy(m_subject, &buf[5], sizeof m_subject); } + if (!strncasecmp(buf, "msgn=", 5)) { + safestrncpy(reply_inreplyto, &buf[5], sizeof reply_inreplyto); + } + if (!strncasecmp(buf, "wefw=", 5)) { + safestrncpy(reply_references, &buf[5], sizeof reply_references); + } if (!strncasecmp(buf, "cccc=", 5)) { int len; safestrncpy(m_cc, &buf[5], sizeof m_cc); @@ -803,14 +937,12 @@ void read_message(long msgnum, int printable_view, char *section) { len = strlen(reply_all); safestrncpy(&reply_all[len], &buf[5], (sizeof reply_all - len) ); -#ifdef HAVE_ICONV utf8ify_rfc822_string(&buf[5]); -#endif escputs(&buf[5]); wprintf(" "); } if (!strncasecmp(buf, "time=", 5)) { - fmt_date(now, atol(&buf[5]), 0); + webcit_fmt_date(now, atol(&buf[5]), 0); wprintf(""); wprintf("%s ", now); wprintf(""); @@ -855,8 +987,16 @@ void read_message(long msgnum, int printable_view, char *section) { attach_links = realloc(attach_links, (num_attach_links*sizeof(struct attach_link))); safestrncpy(attach_links[num_attach_links-1].partnum, mime_partnum, 32); + utf8ify_rfc822_string(mime_filename); + + mime_content_type_ptr = mime_content_type; + if (strcasecmp(mime_content_type, "application/octet-stream") == 0) { + mime_content_type_ptr = GuessMimeByFilename(mime_filename, + strlen(mime_filename)); + } + urlesc(escaped_mime_filename, 265, mime_filename); snprintf(attach_links[num_attach_links-1].html, 1024, - "\n" "%s (%s, %d bytes) [ " "%s" " ]
\n", + mime_content_type_ptr, mime_filename, mime_content_type, mime_length, - msgnum, mime_partnum, mime_filename, + msgnum, mime_partnum, escaped_mime_filename, msgnum, mime_partnum, _("View"), - msgnum, mime_partnum, mime_filename, + msgnum, mime_partnum, escaped_mime_filename, _("Download") ); } @@ -880,7 +1021,8 @@ void read_message(long msgnum, int printable_view, char *section) { strcpy(vcard_partnum, mime_partnum); } - if (!strcasecmp(mime_content_type, "text/calendar")) { + if ( (!strcasecmp(mime_content_type, "text/calendar")) + || (!strcasecmp(mime_content_type, "application/ics")) ) { strcpy(cal_partnum, mime_partnum); } @@ -890,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); @@ -915,73 +1066,93 @@ void read_message(long msgnum, int printable_view, char *section) { wprintf("****"); } -#ifdef HAVE_ICONV utf8ify_rfc822_string(m_cc); utf8ify_rfc822_string(m_subject); -#endif /** start msg buttons */ + char Urlsep = '?'; + if (!printable_view) { wprintf("

\n",msgnum); - /** Reply */ + /* Reply */ if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) { wprintf("is_mailbox) { - wprintf("?replyquote=%ld", msgnum); + wprintf("%creplyquote=%ld", Urlsep, msgnum); + Urlsep = '&'; } - wprintf("?recp="); + wprintf("%crecp=", Urlsep); + Urlsep = '&'; urlescputs(reply_to); if (!IsEmptyStr(m_subject)) { - wprintf("?subject="); - if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20"); + wprintf("%csubject=", Urlsep); + if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%%20"); urlescputs(m_subject); } + wprintf("%creferences=", Urlsep); + if (!IsEmptyStr(reply_references)) { + urlescputs(reply_references); + urlescputs("|"); + } + urlescputs(reply_inreplyto); wprintf("\">[%s] ", _("Reply")); } - /** ReplyQuoted */ + /* ReplyQuoted */ if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) { if (!WC->is_mailbox) { wprintf("[%s] ", _("ReplyQuoted")); } } - /** ReplyAll */ + /* ReplyAll */ if (WC->wc_view == VIEW_MAILBOX) { wprintf("[%s] ", _("ReplyAll")); } - /** Forward */ + /* Forward */ if (WC->wc_view == VIEW_MAILBOX) { - wprintf("[%s] ", _("Forward")); } - /** If this is one of my own rooms, or if I'm an Aide or Room Aide, I can move/delete */ + /* 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) || (WC->room_flags2 & QR2_COLLABDEL) ) { /** Move */ wprintf("[%s] ", @@ -995,12 +1166,12 @@ void read_message(long msgnum, int printable_view, char *section) { ); } - /** Headers */ + /* Headers */ wprintf("" "[%s]", msgnum, msgnum, _("Headers")); - /** Print */ + /* Print */ wprintf("" "[%s]", msgnum, msgnum, _("Print")); @@ -1025,18 +1196,16 @@ void read_message(long msgnum, int printable_view, char *section) { wprintf(""); - /** Begin body */ + /* Begin body */ wprintf("

"); - /** + /* * Learn the content type */ strcpy(mime_content_type, "text/plain"); while (serv_getln(buf, sizeof buf), (!IsEmptyStr(buf))) { if (!strcmp(buf, "000")) { - wprintf(""); - wprintf(_("unexpected end of message")); - wprintf(" (2)

\n"); + /* This is not necessarily an error condition. See bug #226. */ goto ENDBODY; } if (!strncasecmp(buf, "X-Citadel-MSG4-Partnum:", 23)) { @@ -1070,7 +1239,7 @@ void read_message(long msgnum, int printable_view, char *section) { } } - /** Set up a character set conversion if we need to (and if we can) */ + /* 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")) @@ -1085,12 +1254,12 @@ void read_message(long msgnum, int printable_view, char *section) { } #endif - /** Messages in legacy Citadel variformat get handled thusly... */ + /* Messages in legacy Citadel variformat get handled thusly... */ if (!strcasecmp(mime_content_type, "text/x-citadel-variformat")) { fmout("JUSTIFY"); } - /** Boring old 80-column fixed format text gets handled this way... */ + /* Boring old 80-column fixed format text gets handled this way... */ else if ( (!strcasecmp(mime_content_type, "text/plain")) || (!strcasecmp(mime_content_type, "text")) ) { buf [0] = '\0'; @@ -1127,26 +1296,27 @@ void read_message(long msgnum, int printable_view, char *section) { bq = 0; } wprintf(""); - url(buf); + url(buf, sizeof(buf)); escputs(buf); wprintf("
\n"); } wprintf("
"); } - else /** HTML is fun, but we've got to strip it first */ - if (!strcasecmp(mime_content_type, "text/html")) { - output_html(mime_charset, (WC->wc_view == VIEW_WIKI ? 1 : 0)); + /* 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), msgnum); } - /** Unknown weirdness */ + /* Unknown weirdness */ else { wprintf(_("I don't know how to display %s"), mime_content_type); - wprintf("
\n", mime_content_type); + wprintf("
\n"); while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { } } - /** If there are attached submessages, display them now... */ +ENDBODY: /* If there are attached submessages, display them now... */ + if ( (!IsEmptyStr(mime_submessages)) && (!section[0]) ) { for (i=0; i 0) && (!section[0]) ) { for (i=0; iwc_roomname[11], USERCONFIGROOM)) || (WC->wc_view == VIEW_ADDRESSBOOK) ) { - wprintf("", + wprintf("", msgnum, vcard_partnum); wprintf("[%s]", _("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); } } @@ -1202,10 +1370,9 @@ void read_message(long msgnum, int printable_view, char *section) { part_source = NULL; } -ENDBODY: wprintf("
\n"); - /** end everythingamundo table */ + /* end everythingamundo table */ if (!printable_view) { wprintf("\n"); } @@ -1223,41 +1390,40 @@ ENDBODY: -/** - * \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", - SERVER); + PACKAGE_STRING); begin_burst(); - wprintf("\r\n\r\n\n" - "Printable view\n" + wprintf("\r\n\n"); + escputs(WC->wc_fullname); + wprintf("\n" "\n" ); @@ -1267,24 +1433,37 @@ void print_message(char *msgnum_as_string) { wDumpContent(0); } - +/* + * Mobile browser view of message + * + * @param msg_num_as_string Message number as a string instead of as a long int + */ +void mobile_message_view(void) { + long msgnum = 0L; + msgnum = StrTol(WC->UrlFragment1); + output_headers(1, 0, 0, 0, 0, 1); + begin_burst(); + do_template("msgcontrols", NULL); + read_message(msgnum,1, ""); + wDumpContent(0); +} /** * \brief Display a message's headers * * \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", - SERVER); + PACKAGE_STRING); begin_burst(); serv_printf("MSG2 %ld|3", msgnum); @@ -1323,10 +1502,11 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers char *ptr = NULL; int num_attachments = 0; struct wc_attachment *att, *aptr; - char m_subject[256]; + char m_subject[1024]; char from[256]; char node[256]; char rfca[256]; + char to[256]; char reply_to[512]; char now[256]; int format_type = 0; @@ -1374,9 +1554,7 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers if (!strncasecmp(buf, "from=", 5)) { strcpy(from, &buf[5]); wprintf(_("from ")); -#ifdef HAVE_ICONV utf8ify_rfc822_string(from); -#endif msgescputs(from); } if (!strncasecmp(buf, "subj=", 5)) { @@ -1398,7 +1576,6 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers msgescputs(rfca); wprintf("> "); } - if (!strncasecmp(buf, "node=", 5)) { strcpy(node, &buf[5]); if ( ((WC->room_flags & QR_NETWORK) @@ -1411,10 +1588,12 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers } if (!strncasecmp(buf, "rcpt=", 5)) { wprintf(_("to ")); - wprintf("%s ", &buf[5]); + strcpy(to, &buf[5]); + utf8ify_rfc822_string(to); + wprintf("%s ", to); } if (!strncasecmp(buf, "time=", 5)) { - fmt_date(now, atol(&buf[5]), 0); + webcit_fmt_date(now, atol(&buf[5]), 0); wprintf("%s ", now); } } @@ -1442,9 +1621,7 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers if (include_headers) { wprintf("
"); -#ifdef HAVE_ICONV utf8ify_rfc822_string(m_subject); -#endif if (!IsEmptyStr(m_subject)) { wprintf(_("Subject:")); wprintf(" "); @@ -1518,8 +1695,8 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { int len; len = strlen(buf); - if (buf[len-1] == '\n') buf[--len] = 0; - if (buf[len-1] == '\r') buf[--len] = 0; + if ((len > 0) && (buf[len-1] == '\n')) buf[--len] = 0; + if ((len > 0) && (buf[len-1] == '\r')) buf[--len] = 0; #ifdef HAVE_ICONV if (ic != (iconv_t)(-1) ) { @@ -1548,7 +1725,7 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers bq = 0; } wprintf(""); - url(buf); + url(buf, sizeof(buf)); msgescputs1(buf); wprintf("
"); } @@ -1561,7 +1738,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 { @@ -1638,16 +1815,16 @@ ENDBODY: */ void display_summarized(int num) { char datebuf[64]; - wprintf("", WC->summ[num].msgnum, - (WC->summ[num].is_new ? "bold" : "normal"), + ((WC->summ[num].is_new) ? "bold" : "normal"), WC->summ[num].msgnum ); wprintf("", SUBJ_COL_WIDTH_PCT); - escputs(WC->summ[num].subj); + + escputs(WC->summ[num].subj);//////////////////////////////////TODO: QP DECODE wprintf(""); wprintf("", SENDER_COL_WIDTH_PCT); @@ -1655,14 +1832,32 @@ void display_summarized(int num) { wprintf(""); wprintf("", DATE_PLUS_BUTTONS_WIDTH_PCT); - fmt_date(datebuf, WC->summ[num].date, 1); /* brief */ + webcit_fmt_date(datebuf, WC->summ[num].date, 1); /* brief */ escputs(datebuf); wprintf(""); wprintf("\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
", + WC->summ[num].msgnum, + (WC->summ[num].is_new ? "bold" : "normal"), + WC->summ[num].msgnum + ); + wprintf("%s",WC->summ[num].from); + wprintf(""); + webcit_fmt_date(datebuf, WC->summ[num].date, 1); /* brief */ + escputs(datebuf); + wprintf("
"); + escputs(WC->summ[num].subj); + wprintf("
",WC->summ[num].msgnum); +} /** * \brief display the adressbook overview @@ -1709,7 +1904,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)) @@ -1717,7 +1912,7 @@ void display_addressbook(long msgnum, char alpha) { || (WC->wc_view == VIEW_ADDRESSBOOK) ) { wprintf("", + "msgnum=%ld&partnum=%s\">", msgnum, vcard_partnum); wprintf("[%s]", _("edit")); } @@ -1800,7 +1995,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); } @@ -1836,8 +2031,8 @@ int abcmp(const void *ab1, const void *ab2) { * \param tabbuf the tabbuffer to add name to * \param name the name to add to the tabbuffer */ -void nametab(char *tabbuf, char *name) { - stresc(tabbuf, name, 0, 0); +void nametab(char *tabbuf, long len, char *name) { + stresc(tabbuf, len, name, 0, 0); tabbuf[0] = toupper(tabbuf[0]); tabbuf[1] = tolower(tabbuf[1]); tabbuf[2] = tolower(tabbuf[2]); @@ -1889,8 +2084,8 @@ void do_addrbook_view(struct addrbookent *addrbook, int num_ab) { tabfirst = i * NAMESPERPAGE; tablast = tabfirst + NAMESPERPAGE - 1; if (tablast > (num_ab - 1)) tablast = (num_ab - 1); - nametab(tabfirst_label, addrbook[tabfirst].ab_name); - nametab(tablast_label, addrbook[tablast].ab_name); + nametab(tabfirst_label, 64, addrbook[tabfirst].ab_name); + nametab(tablast_label, 64, addrbook[tablast].ab_name); sprintf(this_tablabel, "%s - %s", tabfirst_label, tablast_label); tablabels[i] = strdup(this_tablabel); } @@ -1923,18 +2118,29 @@ void do_addrbook_view(struct addrbookent *addrbook, int num_ab) { wprintf(""); - wprintf("", bstr("alpha")); + wprintf("?maxmsgs=1?is_summary=0?alpha=%s\">", bstr("alpha")); vcard_n_prettyize(addrbook[i].ab_name); escputs(addrbook[i].ab_name); wprintf("\n"); ++displayed; } + /* Placeholders for empty columns at end */ + if ((num_ab % 4) != 0) { + for (i=0; i<(4-(num_ab % 4)); ++i) { + wprintf(" "); + } + } + wprintf("\n"); end_tab((num_pages-1), num_pages); + begin_tab(num_pages, num_pages); + /* FIXME there ought to be something here */ + end_tab(num_pages, num_pages); + for (i=0; isumm[nummsgs-1].msgnum = WC->msgarr[nummsgs-1]; safestrncpy(WC->summ[nummsgs-1].subj, _("(no subject)"), sizeof WC->summ[nummsgs-1].subj); - if (!IsEmptyStr(fullname)) { - safestrncpy(WC->summ[nummsgs-1].from, - fullname, sizeof WC->summ[nummsgs-1].from); - } if (!IsEmptyStr(subject)) { - safestrncpy(WC->summ[nummsgs-1].subj, subject, - sizeof WC->summ[nummsgs-1].subj); - } -#ifdef HAVE_ICONV /** Handle subjects with RFC2047 encoding */ - utf8ify_rfc822_string(WC->summ[nummsgs-1].subj); -#endif - if (strlen(WC->summ[nummsgs-1].subj) > 75) { - strcpy(&WC->summ[nummsgs-1].subj[72], "..."); + utf8ify_rfc822_string(subject); + safestrncpy(WC->summ[nummsgs-1].subj, subject, + sizeof WC->summ[nummsgs-1].subj); } + sbjlen = Ctdl_Utf8StrLen(WC->summ[nummsgs-1].subj); + if (sbjlen > 75) { + ptr = Ctdl_Utf8StrCut(WC->summ[nummsgs-1].subj, 72); - 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); - } + strcpy(ptr, "..."); } - WC->summ[nummsgs-1].date = datestamp; - -#ifdef HAVE_ICONV + if (!IsEmptyStr(fullname)) { /** Handle senders with RFC2047 encoding */ - utf8ify_rfc822_string(WC->summ[nummsgs-1].from); -#endif - if (strlen(WC->summ[nummsgs-1].from) > 25) { - strcpy(&WC->summ[nummsgs-1].from[22], "..."); + 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; } } } return (nummsgs); } -/** - * \brief qsort() compatible function to compare two longs in descending order. - * - * \param s1 first number to compare - * \param s2 second number to compare + +typedef int (*QSortFunction) (const void*, const void*); + +/* + * qsort() compatible function to compare two longs in descending order. */ int longcmp_r(const void *s1, const void *s2) { long l1; @@ -2059,11 +2268,8 @@ int longcmp_r(const void *s1, const void *s2) { } -/** - * \brief qsort() compatible function to compare two message summary structs by ascending subject. - * - * \param s1 first item to compare - * \param s2 second item to compare +/* + * qsort() compatible function to compare two message summary structs by ascending subject. */ int summcmp_subj(const void *s1, const void *s2) { struct message_summary *summ1; @@ -2074,11 +2280,8 @@ int summcmp_subj(const void *s1, const void *s2) { return strcasecmp(summ1->subj, summ2->subj); } -/** - * \brief qsort() compatible function to compare two message summary structs by descending subject. - * - * \param s1 first item to compare - * \param s2 second item to compare +/* + * qsort() compatible function to compare two message summary structs by descending subject. */ int summcmp_rsubj(const void *s1, const void *s2) { struct message_summary *summ1; @@ -2089,11 +2292,8 @@ int summcmp_rsubj(const void *s1, const void *s2) { return strcasecmp(summ2->subj, summ1->subj); } -/** - * \brief qsort() compatible function to compare two message summary structs by ascending sender. - * - * \param s1 first item to compare - * \param s2 second item to compare +/* + * qsort() compatible function to compare two message summary structs by ascending sender. */ int summcmp_sender(const void *s1, const void *s2) { struct message_summary *summ1; @@ -2104,11 +2304,8 @@ int summcmp_sender(const void *s1, const void *s2) { return strcasecmp(summ1->from, summ2->from); } -/** - * \brief qsort() compatible function to compare two message summary structs by descending sender. - * - * \param s1 first item to compare - * \param s2 second item to compare +/* + * qsort() compatible function to compare two message summary structs by descending sender. */ int summcmp_rsender(const void *s1, const void *s2) { struct message_summary *summ1; @@ -2119,11 +2316,8 @@ int summcmp_rsender(const void *s1, const void *s2) { return strcasecmp(summ2->from, summ1->from); } -/** - * \brief qsort() compatible function to compare two message summary structs by ascending date. - * - * \param s1 first item to compare - * \param s2 second item to compare +/* + * qsort() compatible function to compare two message summary structs by ascending date. */ int summcmp_date(const void *s1, const void *s2) { struct message_summary *summ1; @@ -2137,11 +2331,8 @@ int summcmp_date(const void *s1, const void *s2) { else return 0; } -/** - * \brief qsort() compatible function to compare two message summary structs by descending date. - * - * \param s1 first item to compare - * \param s2 second item to compare +/* + * qsort() compatible function to compare two message summary structs by descending date. */ int summcmp_rdate(const void *s1, const void *s2) { struct message_summary *summ1; @@ -2156,15 +2347,92 @@ int summcmp_rdate(const void *s1, const void *s2) { } +enum { + eUp, + eDown, + eNone +}; -/** - * \brief command loop for reading messages +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}; + + +/* + * Translates sortoption String to its SortEnum representation + * returns the enum matching the string; defaults to RDate + */ +//SortByEnum +int StrToESort (const StrBuf *sortby) +{ + int result = eDate; + + if (!IsEmptyStr(ChrPtr(sortby))) while (result < eUnSet){ + if (!strcasecmp(ChrPtr(sortby), + SortByStrings[result])) + return result; + result ++; + } + return eRDate; +} + + + + +/* + * command loop for reading messages * - * \param oper Set to "readnew" or "readold" or "readfwd" or "headers" + * Set oper to "readnew" or "readold" or "readfwd" or "headers" */ void readloop(char *oper) { - char cmd[256]; + char cmd[256] = ""; char buf[SIZ]; char old_msgs[SIZ]; int a, b; @@ -2185,39 +2453,37 @@ 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; + const StrBuf *sortby = NULL; + //SortByEnum + int SortBy = eRDate; + const StrBuf *sortpref_value; int bbs_reverse = 0; + struct wcsession *WCC = WC; /* This is done to make it run faster; WC is a function */ - if (WC->wc_view == VIEW_WIKI) { - sprintf(buf, "wiki?room=%s?page=home", WC->wc_roomname); + if (WCC->wc_view == VIEW_WIKI) { + sprintf(buf, "wiki?room=%s&page=home", WCC->wc_roomname); http_redirect(buf); return; } - startmsg = atol(bstr("startmsg")); - maxmsgs = atoi(bstr("maxmsgs")); - is_summary = atoi(bstr("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", WC->wc_roomname); - get_preference(sortpref_name, sortpref_value, sizeof sortpref_value); + sortpref_value = get_room_pref("sort"); - sortby = bstr("sortby"); - if ( (!IsEmptyStr(sortby)) && (strcasecmp(sortby, sortpref_value)) ) { - set_preference(sortpref_name, sortby, 1); + sortby = sbstr("sortby"); + if ( (!IsEmptyStr(ChrPtr(sortby))) && + (strcasecmp(ChrPtr(sortby), ChrPtr(sortpref_value)) != 0)) { + set_room_pref("sort", NewStrBufDup(sortby), 1); + sortpref_value = NULL; + sortpref_value = sortby; } - if (IsEmptyStr(sortby)) sortby = sortpref_value; - - /** mailbox sort */ - if (IsEmptyStr(sortby)) sortby = "rdate"; - /** message board sort */ - if (!strcasecmp(sortby, "reverse")) { + SortBy = StrToESort(sortpref_value); + /* message board sort */ + if (SortBy == eReverse) { bbs_reverse = 1; } else { @@ -2226,7 +2492,7 @@ void readloop(char *oper) output_headers(1, 1, 1, 0, 0, 0); - /** + /* * When in summary mode, always show ALL messages instead of just * new or old. Otherwise, show what the user asked for. */ @@ -2237,26 +2503,26 @@ void readloop(char *oper) strcpy(cmd, "MSGS OLD"); } else if (!strcmp(oper, "do_search")) { - sprintf(cmd, "MSGS SEARCH|%s", bstr("query")); + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); } else { strcpy(cmd, "MSGS ALL"); } - if ((WC->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")) { - sprintf(cmd, "MSGS SEARCH|%s", bstr("query")); + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); } else { strcpy(cmd, "MSGS ALL"); } } - if ((WC->wc_view == VIEW_ADDRESSBOOK) && (maxmsgs > 1)) { + if ((WCC->wc_view == VIEW_ADDRESSBOOK) && (maxmsgs > 1)) { is_addressbook = 1; if (!strcmp(oper, "do_search")) { - sprintf(cmd, "MSGS SEARCH|%s", bstr("query")); + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); } else { strcpy(cmd, "MSGS ALL"); @@ -2265,21 +2531,29 @@ void readloop(char *oper) } if (is_summary) { /**< fetch header summary */ - snprintf(cmd, sizeof cmd, "MSGS %s|%s||1", + 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; + snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1", + (!strcmp(oper, "do_search") ? "SEARCH" : "ALL"), + (!strcmp(oper, "do_search") ? bstr("query") : "") + ); + SortBy = eRDate; } - /** + /* * Are we doing a summary view? If so, we need to know old messages * and new messages, so we can do that pretty boldface thing for the * new messages. */ strcpy(old_msgs, ""); - if (is_summary) { + if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){ serv_puts("GTSN"); serv_getln(buf, sizeof buf); if (buf[0] == '2') { @@ -2287,30 +2561,29 @@ void readloop(char *oper) } } - is_singlecard = atoi(bstr("is_singlecard")); + is_singlecard = ibstr("is_singlecard"); - if (WC->wc_default_view == VIEW_CALENDAR) { /**< calendar */ + if (WCC->wc_default_view == VIEW_CALENDAR) { /**< calendar */ is_calendar = 1; - strcpy(cmd, "MSGS ALL"); + strcpy(cmd, "MSGS ALL|||1"); maxmsgs = 32767; } - if (WC->wc_default_view == VIEW_TASKS) { /**< tasks */ + if (WCC->wc_default_view == VIEW_TASKS) { /**< tasks */ is_tasks = 1; strcpy(cmd, "MSGS ALL"); maxmsgs = 32767; } - if (WC->wc_default_view == VIEW_NOTES) { /**< notes */ + if (WCC->wc_default_view == VIEW_NOTES) { /**< notes */ is_notes = 1; strcpy(cmd, "MSGS ALL"); maxmsgs = 32767; } if (is_notes) { - wprintf("
%s
\n", _("Click on any note to edit it.")); wprintf("
\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)) { @@ -2328,15 +2601,15 @@ void readloop(char *oper) goto DONE; } - if (is_summary) { + 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) { - if (is_msg_in_mset(old_msgs, WC->msgarr[a])) { - WC->summ[a].is_new = 0; + if (is_msg_in_mset(old_msgs, WCC->msgarr[a])) { + WCC->summ[a].is_new = 0; } else { - WC->summ[a].is_new = 1; + WCC->summ[a].is_new = 1; } } } @@ -2344,69 +2617,18 @@ void readloop(char *oper) if (startmsg == 0L) { if (bbs_reverse) { - startmsg = WC->msgarr[(nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0]; + startmsg = WCC->msgarr[(nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0]; } else { - startmsg = WC->msgarr[0]; + startmsg = WCC->msgarr[0]; } } - if (is_summary) { - if (!strcasecmp(sortby, "subject")) { - qsort(WC->summ, WC->num_summ, - sizeof(struct message_summary), summcmp_subj); - } - else if (!strcasecmp(sortby, "rsubject")) { - qsort(WC->summ, WC->num_summ, - sizeof(struct message_summary), summcmp_rsubj); - } - else if (!strcasecmp(sortby, "sender")) { - qsort(WC->summ, WC->num_summ, - sizeof(struct message_summary), summcmp_sender); - } - else if (!strcasecmp(sortby, "rsender")) { - qsort(WC->summ, WC->num_summ, - sizeof(struct message_summary), summcmp_rsender); - } - else if (!strcasecmp(sortby, "date")) { - qsort(WC->summ, WC->num_summ, - sizeof(struct message_summary), summcmp_date); - } - else if (!strcasecmp(sortby, "rdate")) { - qsort(WC->summ, WC->num_summ, - sizeof(struct message_summary), summcmp_rdate); - } + if (is_summary || WCC->is_mobile) { + qsort(WCC->summ, WCC->num_summ, + sizeof(struct message_summary), SortFuncs[SortBy]); } - if (!strcasecmp(sortby, "subject")) { - subjsort_button = "" ; - } - else if (!strcasecmp(sortby, "rsubject")) { - subjsort_button = "" ; - } - else { - subjsort_button = "" ; - } - - if (!strcasecmp(sortby, "sender")) { - sendsort_button = "" ; - } - else if (!strcasecmp(sortby, "rsender")) { - sendsort_button = "" ; - } - else { - sendsort_button = "" ; - } - - if (!strcasecmp(sortby, "date")) { - datesort_button = "" ; - } - else if (!strcasecmp(sortby, "rdate")) { - datesort_button = "" ; - } - else { - datesort_button = "" ; - } if (is_summary) { @@ -2424,9 +2646,9 @@ void readloop(char *oper) "" "" ); - wprintf("" - "" - "\n" + "\n" + "
%s %s%s %s%s %s" + wprintf("%s %s %s \n" " " "\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("
\n"); - wprintf("
" "
\n" - "" ); + } else if (WCC->is_mobile) { + wprintf("
"); } @@ -2469,8 +2697,8 @@ void readloop(char *oper) */ if (is_bbview) { /** begin bbview scroller */ - wprintf("
"); - wprintf(_("Reading #"), lowest_displayed, highest_displayed); + wprintf(" \n

"); + wprintf(_("Reading #"));//// TODO this isn't used, should it? : , lowest_displayed, highest_displayed); wprintf(" "); @@ -2543,43 +2771,42 @@ void readloop(char *oper) wprintf(_("newest to oldest")); wprintf("\n"); - wprintf("\n"); + wprintf("

\n"); /** end bbview scroller */ } - - - for (a = 0; a < nummsgs; ++a) { - if ((WC->msgarr[a] >= startmsg) && (num_displayed < maxmsgs)) { + if ((WCC->msgarr[a] >= startmsg) && (num_displayed < maxmsgs)) { /** Display the message */ if (is_summary) { display_summarized(a); } else if (is_addressbook) { - fetch_ab_name(WC->msgarr[a], buf); + fetch_ab_name(WCC->msgarr[a], buf); ++num_ab; addrbook = realloc(addrbook, (sizeof(struct addrbookent) * num_ab) ); safestrncpy(addrbook[num_ab-1].ab_name, buf, sizeof(addrbook[num_ab-1].ab_name)); - addrbook[num_ab-1].ab_msgnum = WC->msgarr[a]; + addrbook[num_ab-1].ab_msgnum = WCC->msgarr[a]; } else if (is_calendar) { - display_calendar(WC->msgarr[a]); + display_calendar(WCC->msgarr[a], WCC->summ[a].is_new); } else if (is_tasks) { - display_task(WC->msgarr[a]); + display_task(WCC->msgarr[a], WCC->summ[a].is_new); } else if (is_notes) { - display_note(WC->msgarr[a]); + display_note(WCC->msgarr[a], WCC->summ[a].is_new); + } else if (WCC->is_mobile) { + display_mobile_summary(a); } else { if (displayed_msgs == NULL) { displayed_msgs = malloc(sizeof(long) * (maxmsgsmsgarr[a]; + displayed_msgs[num_displayed] = WCC->msgarr[a]; } if (lowest_displayed < 0) lowest_displayed = a; @@ -2589,7 +2816,6 @@ void readloop(char *oper) } } - /** Output loop */ if (displayed_msgs != NULL) { if (bbs_reverse) { @@ -2612,7 +2838,7 @@ void readloop(char *oper) wprintf("
" "
\n"); /**< end of 'fix_scrollbar_bug' div */ wprintf("
"); /**< end of 'message_list' div */ - + /** Here's the grab-it-to-resize-the-message-list widget */ wprintf("
" @@ -2621,6 +2847,8 @@ void readloop(char *oper) ); wprintf("
"); /**< The preview pane will initially be empty */ + } else if (WCC->is_mobile) { + wprintf("
"); } /** @@ -2636,8 +2864,8 @@ void readloop(char *oper) */ if (is_bbview) { /** begin bbview scroller */ - wprintf("
"); - wprintf(_("Reading #"), lowest_displayed, highest_displayed); + wprintf(" \n

"); + wprintf(_("Reading #")); /// TODO: this isn't used: , lowest_displayed, highest_displayed); wprintf(" "); @@ -2693,7 +2921,7 @@ void readloop(char *oper) /** forward/reverse */ wprintf("\n"); + wprintf("

\n"); /** end bbview scroller */ } - + DONE: if (is_tasks) { do_tasks_view(); /** Render the task list */ @@ -2731,87 +2959,110 @@ DONE: wDumpContent(1); /** free the summary */ - if (WC->summ != NULL) { - free(WC->summ); - WC->num_summ = 0; - WC->summ = NULL; + if (WCC->summ != NULL) { + free(WCC->summ); + WCC->num_summ = 0; + WCC->summ = NULL; } if (addrbook != NULL) free(addrbook); } -/** - * \brief Back end for post_message() +/* + * Back end for post_message() * ... this is where the actual message gets transmitted to the server. */ void post_mime_to_server(void) { - char boundary[SIZ]; + char top_boundary[SIZ]; + char alt_boundary[SIZ]; int is_multipart = 0; static int seq = 0; struct wc_attachment *att; char *encoded; size_t encoded_length; + size_t encoded_strlen; + char *txtmail = NULL; + + sprintf(top_boundary, "Citadel--Multipart--%s--%04x--%04x", + serv_info.serv_fqdn, + getpid(), + ++seq + ); + sprintf(alt_boundary, "Citadel--Multipart--%s--%04x--%04x", + serv_info.serv_fqdn, + getpid(), + ++seq + ); - /** RFC2045 requires this, and some clients look for it... */ + /* RFC2045 requires this, and some clients look for it... */ serv_puts("MIME-Version: 1.0"); - serv_puts("X-Mailer: " SERVER); + serv_puts("X-Mailer: " PACKAGE_STRING); - /** If there are attachments, we have to do multipart/mixed */ + /* If there are attachments, we have to do multipart/mixed */ if (WC->first_attachment != NULL) { is_multipart = 1; } if (is_multipart) { - sprintf(boundary, "Citadel--Multipart--%s--%04x--%04x", - serv_info.serv_fqdn, - getpid(), - ++seq - ); - - /** Remember, serv_printf() appends an extra newline */ - serv_printf("Content-type: multipart/mixed; " - "boundary=\"%s\"\n", boundary); + /* Remember, serv_printf() appends an extra newline */ + serv_printf("Content-type: multipart/mixed; boundary=\"%s\"\n", top_boundary); serv_printf("This is a multipart message in MIME format.\n"); - serv_printf("--%s", boundary); + serv_printf("--%s", top_boundary); } + /* Remember, serv_printf() appends an extra newline */ + serv_printf("Content-type: multipart/alternative; " + "boundary=\"%s\"\n", alt_boundary); + serv_printf("This is a multipart message in MIME format.\n"); + serv_printf("--%s", alt_boundary); + + serv_puts("Content-type: text/plain; charset=utf-8"); + serv_puts("Content-Transfer-Encoding: quoted-printable"); + serv_puts(""); + txtmail = html_to_ascii(bstr("msgtext"), 0, 80, 0); + text_to_server_qp(txtmail); /* Transmit message in quoted-printable encoding */ + free(txtmail); + + serv_printf("--%s", alt_boundary); + serv_puts("Content-type: text/html; charset=utf-8"); serv_puts("Content-Transfer-Encoding: quoted-printable"); serv_puts(""); serv_puts("\r\n"); - text_to_server_qp(bstr("msgtext")); /** Transmit message in quoted-printable encoding */ + text_to_server_qp(bstr("msgtext")); /* Transmit message in quoted-printable encoding */ serv_puts("\r\n"); + + serv_printf("--%s--", alt_boundary); if (is_multipart) { - /** Add in the attachments */ + /* Add in the attachments */ for (att = WC->first_attachment; att!=NULL; att=att->next) { encoded_length = ((att->length * 150) / 100); encoded = malloc(encoded_length); if (encoded == NULL) break; - CtdlEncodeBase64(encoded, att->data, att->length, 1); + encoded_strlen = CtdlEncodeBase64(encoded, att->data, att->length, 1); - serv_printf("--%s", boundary); + serv_printf("--%s", top_boundary); serv_printf("Content-type: %s", att->content_type); - serv_printf("Content-disposition: attachment; " - "filename=\"%s\"", att->filename); + serv_printf("Content-disposition: attachment; filename=\"%s\"", att->filename); serv_puts("Content-transfer-encoding: base64"); serv_puts(""); - serv_write(encoded, strlen(encoded)); + serv_write(encoded, encoded_strlen); serv_puts(""); serv_puts(""); free(encoded); } - serv_printf("--%s--", boundary); + serv_printf("--%s--", top_boundary); } serv_puts("000"); } -/** - * \brief Post message (or don't post message) +/* + * Post message (or don't post message) * * Note regarding the "dont_post" variable: * A random value (actually, it's just a timestamp) is inserted as a hidden @@ -2824,35 +3075,42 @@ void post_mime_to_server(void) { void post_message(void) { char buf[1024]; - char encoded_subject[1024]; + StrBuf *encoded_subject = NULL; static long dont_post = (-1L); struct wc_attachment *att, *aptr; int is_anonymous = 0; - char *display_name; + const StrBuf *display_name = NULL; + struct wcsession *WCC = WC; + + if (havebstr("force_room")) { + gotoroom(bstr("force_room")); + } - display_name = bstr("display_name"); - if (!strcmp(display_name, "__ANONYMOUS__")) { - display_name = ""; - is_anonymous = 1; + if (havebstr("display_name")) { + display_name = sbstr("display_name"); + if (!strcmp(ChrPtr(display_name), "__ANONYMOUS__")) { + display_name = NULL; + is_anonymous = 1; + } } - if (WC->upload_length > 0) { + if (WCC->upload_length > 0) { - lprintf(9, "%s:%d: we are uploading %d bytes\n", __FILE__, __LINE__, WC->upload_length); + lprintf(9, "%s:%d: we are uploading %d bytes\n", __FILE__, __LINE__, WCC->upload_length); /** There's an attachment. Save it to this struct... */ att = malloc(sizeof(struct wc_attachment)); memset(att, 0, sizeof(struct wc_attachment)); - att->length = WC->upload_length; - strcpy(att->content_type, WC->upload_content_type); - strcpy(att->filename, WC->upload_filename); + att->length = WCC->upload_length; + strcpy(att->content_type, WCC->upload_content_type); + strcpy(att->filename, WCC->upload_filename); att->next = NULL; /** And add it to the list. */ - if (WC->first_attachment == NULL) { - WC->first_attachment = att; + if (WCC->first_attachment == NULL) { + WCC->first_attachment = att; } else { - aptr = WC->first_attachment; + aptr = WCC->first_attachment; while (aptr->next != NULL) aptr = aptr->next; aptr->next = att; } @@ -2873,49 +3131,97 @@ void post_message(void) * Transfer control of this memory from the upload struct * to the attachment struct. */ - att->data = WC->upload; - WC->upload_length = 0; - WC->upload = NULL; + att->data = WCC->upload; + WCC->upload_length = 0; + WCC->upload = NULL; display_enter(); return; } - if (!IsEmptyStr(bstr("cancel_button"))) { - sprintf(WC->ImportantMessage, + 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) { - sprintf(WC->ImportantMessage, + } else if (lbstr("postseq") == dont_post) { + sprintf(WCC->ImportantMessage, _("Automatically cancelled because you have already " "saved this message.")); } else { - rfc2047encode(encoded_subject, sizeof encoded_subject, bstr("subject")); - sprintf(buf, "ENT0 1|%s|%d|4|%s|%s||%s|%s|%s|%s", - bstr("recp"), - is_anonymous, - encoded_subject, - display_name, - bstr("cc"), - bstr("bcc"), - bstr("wikipage"), - bstr("my_email_addr") - ); - serv_puts(buf); + const char CMD[] = "ENT0 1|%s|%d|4|%s|%s||%s|%s|%s|%s|%s"; + const StrBuf *Recp = NULL; + const StrBuf *Cc = NULL; + const StrBuf *Bcc = NULL; + const StrBuf *Wikipage = NULL; + const StrBuf *my_email_addr = NULL; + StrBuf *CmdBuf = NULL;; + StrBuf *references = NULL; + + if (havebstr("references")) + { + const StrBuf *ref = sbstr("references"); + references = NewStrBufPlain(ChrPtr(ref), StrLength(ref)); + lprintf(9, "Converting: %s\n", ChrPtr(references)); + StrBufReplaceChars(references, '|', '!'); + lprintf(9, "Converted: %s\n", ChrPtr(references)); + } + if (havebstr("subject")) { + const StrBuf *Subj; + /* + * make enough room for the encoded string; + * plus the QP header + */ + Subj = sbstr("subject"); + + StrBufRFC2047encode(&encoded_subject, Subj); + } + Recp = sbstr("recp"); + Cc = sbstr("cc"); + Bcc = sbstr("bcc"); + Wikipage = sbstr("wikipage"); + my_email_addr = sbstr("my_email_addr"); + + CmdBuf = NewStrBufPlain(NULL, + sizeof (CMD) + + StrLength(Recp) + + StrLength(encoded_subject) + + StrLength(Cc) + + StrLength(Bcc) + + StrLength(Wikipage) + + StrLength(my_email_addr) + + StrLength(references)); + + StrBufPrintf(CmdBuf, + CMD, + ChrPtr(Recp), + is_anonymous, + ChrPtr(encoded_subject), + ChrPtr(display_name), + ChrPtr(Cc), + ChrPtr(Bcc), + ChrPtr(Wikipage), + ChrPtr(my_email_addr), + ChrPtr(references)); + FreeStrBuf(&references); + + lprintf(9, "%s\n", CmdBuf); + serv_puts(ChrPtr(CmdBuf)); serv_getln(buf, sizeof buf); + FreeStrBuf(&CmdBuf); + FreeStrBuf(&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(WC->ImportantMessage, _("Message has been sent.\n")); + 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]); @@ -2924,19 +3230,19 @@ void post_message(void) } } - free_attachments(WC); + free_attachments(WCC); /** * 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); } @@ -2957,26 +3263,26 @@ void post_message(void) void display_enter(void) { char buf[SIZ]; - char ebuf[SIZ]; + StrBuf *ebuf; long now; - char *display_name; + const StrBuf *display_name = NULL; 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); + 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"); - if (!strcmp(display_name, "__ANONYMOUS__")) { - display_name = ""; + display_name = sbstr("display_name"); + if (!strcmp(ChrPtr(display_name), "__ANONYMOUS__")) { + display_name = NULL; is_anonymous = 1; } @@ -2988,7 +3294,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; } @@ -3002,32 +3308,30 @@ 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, "", ""); + if (WCC->wc_default_view == VIEW_ADDRESSBOOK) { + do_edit_vcard(-1, "", "", WCC->wc_roomname); return; } -#ifdef WEBCIT_WITH_CALENDAR_SERVICE - /** + /* * 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; } - /** + /* * 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; } -#endif - /** + /* * Otherwise proceed normally. * Do a custom room banner with no navbar... */ @@ -3038,20 +3342,44 @@ void display_enter(void) wprintf("
\n" "
"); - /** Now check our actual recipients if there are any */ + /* 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 StrBuf *Recp = NULL; + const StrBuf *Cc = NULL; + const StrBuf *Bcc = NULL; + const StrBuf *Wikipage = NULL; + StrBuf *CmdBuf = NULL;; + const char CMD[] = "ENT0 0|%s|%d|0||%s||%s|%s|%s"; + + Recp = sbstr("recp"); + Cc = sbstr("cc"); + Bcc = sbstr("bcc"); + Wikipage = sbstr("wikipage"); + + CmdBuf = NewStrBufPlain(NULL, + sizeof (CMD) + + StrLength(Recp) + + StrLength(display_name) + + StrLength(Cc) + + StrLength(Bcc) + + StrLength(Wikipage)); + + StrBufPrintf(CmdBuf, + CMD, + ChrPtr(Recp), + is_anonymous, + ChrPtr(display_name), + ChrPtr(Cc), + ChrPtr(Bcc), + ChrPtr(Wikipage)); + serv_puts(ChrPtr(CmdBuf)); serv_getln(buf, sizeof buf); + FreeStrBuf(&CmdBuf); 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; } } @@ -3063,7 +3391,7 @@ void display_enter(void) /** If we got this far, we can display the message entry screen. */ - /** begin message entry screen */ + /* begin message entry screen */ wprintf("
\n"); wprintf("\n", now); - if (WC->wc_view == VIEW_WIKI) { + if (WCC->wc_view == VIEW_WIKI) { wprintf("\n", bstr("wikipage")); } wprintf("\n", bstr("return_to")); - wprintf("\n", WC->nonce); + wprintf("\n", WCC->nonce); + wprintf("wc_roomname); + wprintf("\">\n"); + wprintf("\n"); /** submit or cancel buttons */ wprintf("

"); @@ -3094,14 +3428,17 @@ void display_enter(void) wprintf(""); wprintf(" "); /** header bar */ - fmt_date(buf, now, 0); + webcit_fmt_date(buf, now, 0); wprintf("%s", buf); wprintf("\n"); /** header bar */ - wprintf("

"); - wprintf("
\n"); + wprintf("
\n"); /* end of "fix_scrollbar_bug" div */ + /* NOTE: address_book_popup() will close the "content" div. Don't close it here. */ DONE: address_book_popup(); wDumpContent(1); } @@ -3331,7 +3702,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); @@ -3355,9 +3726,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); @@ -3373,8 +3744,8 @@ void move_msg(void) -/** - * \brief Confirm move of a message +/* + * Confirm move of a message */ void confirm_move_msg(void) { @@ -3382,7 +3753,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); @@ -3400,7 +3771,7 @@ void confirm_move_msg(void) wprintf("
\n"); wprintf("
\n"); - wprintf("\n", WC->nonce); + wprintf("\n", WC->nonce); wprintf("\n", bstr("msgid")); wprintf("