X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fmessages.c;h=bad4b3e8bed827fb434453bb5a8c3092b43aefc3;hb=c881934110f3c99194fad96c923b7d0ecb24ecdc;hp=2f4a5950900cdd0b87e3362327fbb209178981cf;hpb=a2e182a626959e075987b73bb97e9949eb15d236;p=citadel.git diff --git a/webcit/messages.c b/webcit/messages.c index 2f4a59509..bad4b3e8b 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -9,708 +9,35 @@ #include "webserver.h" #include "groupdav.h" +HashList *MsgHeaderHandler = NULL; +HashList *MsgEvaluators = NULL; +HashList *MimeRenderHandler = NULL; + #define SUBJ_COL_WIDTH_PCT 50 /**< Mailbox view column width */ #define SENDER_COL_WIDTH_PCT 30 /**< Mailbox view column width */ #define DATE_PLUS_BUTTONS_WIDTH_PCT 20 /**< Mailbox view column width */ -/** - * 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) - */ -struct addrbookent { - char ab_name[64]; /**< name string */ - long ab_msgnum; /**< message number of address book entry */ -}; - - - -#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' - * - * \param tocode Target encoding - * \param fromcode Source encoding - */ -iconv_t ctdl_iconv_open(const char *tocode, const char *fromcode) -{ - iconv_t ic = (iconv_t)(-1) ; - ic = iconv_open(tocode, fromcode); - if (ic == (iconv_t)(-1) ) { - char alias_fromcode[64]; - if ( (strlen(fromcode) == 5) && (!strncasecmp(fromcode, "MS", 2)) ) { - safestrncpy(alias_fromcode, fromcode, sizeof alias_fromcode); - alias_fromcode[0] = 'C'; - alias_fromcode[1] = 'P'; - ic = iconv_open(tocode, alias_fromcode); - } - } - return(ic); -} - - -/** - * \brief 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, *next, *nextend, *ptr; - char newbuf[1024]; - char charset[128]; - char encoding[16]; - char istr[1024]; - iconv_t ic = (iconv_t)(-1) ; - char *ibuf; /**< Buffer of characters to be converted */ - char *obuf; /**< Buffer for converted characters */ - size_t ibuflen; /**< Length of input buffer */ - size_t obuflen; /**< Length of output buffer */ - char *isav; /**< Saved pointer to input buffer */ - char *osav; /**< Saved pointer to output buffer */ - int passes = 0; - int i, len, delta; - int illegal_non_rfc2047_encoding = 0; - - /** 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 - * charset to UTF-8 if we see any nonprintable characters. - */ - len = strlen(buf); - for (i=0; i 126)) { - illegal_non_rfc2047_encoding = 1; - i = len; ///< take a shortcut, it won't be more than one. - } - } - 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); - if (ic != (iconv_t)(-1) ) { - ibuf = malloc(1024); - isav = ibuf; - safestrncpy(ibuf, buf, 1024); - ibuflen = strlen(ibuf); - obuflen = 1024; - obuf = (char *) malloc(obuflen); - osav = obuf; - iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen); - osav[1024-obuflen] = 0; - strcpy(buf, osav); - free(osav); - iconv_close(ic); - free(isav); - } - } - } - - /* pre evaluate the first pair */ - nextend = end = NULL; - len = strlen(buf); - start = strstr(buf, "=?"); - if (start != NULL) - end = strstr(start, "?="); - - while ((start != NULL) && (end != NULL)) - { - next = strstr(end, "=?"); - if (next != NULL) - nextend = strstr(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, "?="), - ((start != NULL) && (end != NULL) && (end > start)) ) - { - extract_token(charset, start, 1, '?', sizeof charset); - extract_token(encoding, start, 2, '?', sizeof encoding); - extract_token(istr, start, 3, '?', sizeof istr); - - ibuf = malloc(1024); - isav = ibuf; - if (!strcasecmp(encoding, "B")) { /**< base64 */ - ibuflen = CtdlDecodeBase64(ibuf, istr, strlen(istr)); - } - else if (!strcasecmp(encoding, "Q")) { /**< quoted-printable */ - size_t len; - long pos; - - len = strlen(istr); - pos = 0; - while (pos < len) - { - if (istr[pos] == '_') istr[pos] = ' '; - pos++; - } - - ibuflen = CtdlDecodeQuotedPrintable(ibuf, istr, len); - } - else { - strcpy(ibuf, istr); /**< unknown encoding */ - ibuflen = strlen(istr); - } - - ic = ctdl_iconv_open("UTF-8", charset); - if (ic != (iconv_t)(-1) ) { - obuflen = 1024; - obuf = (char *) malloc(obuflen); - osav = obuf; - iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen); - osav[1024-obuflen] = 0; - - end = start; - end++; - strcpy(start, ""); - remove_token(end, 0, '?'); - remove_token(end, 0, '?'); - remove_token(end, 0, '?'); - remove_token(end, 0, '?'); - strcpy(end, &end[1]); - - snprintf(newbuf, sizeof newbuf, "%s%s%s", buf, osav, end); - strcpy(buf, newbuf); - free(osav); - iconv_close(ic); - } - else { - end = start; - end++; - strcpy(start, ""); - remove_token(end, 0, '?'); - remove_token(end, 0, '?'); - remove_token(end, 0, '?'); - remove_token(end, 0, '?'); - strcpy(end, &end[1]); - - snprintf(newbuf, sizeof newbuf, "%s(unreadable)%s", buf, end); - strcpy(buf, newbuf); - } - - 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 - * this function into an infinite loop. - */ - ++passes; - if (passes > 20) return; - } - -} -#else -inline void utf8ify_rfc822_string(char *a){}; - -#endif - - - - -/** - * \brief RFC2047-encode a header field if necessary. - * If no non-ASCII characters are found, the string - * will be copied verbatim without encoding. - * - * \param target Target buffer. - * \param maxlen Maximum size of target buffer. - * \param source Source string to be encoded. - */ -void webcit_rfc2047encode(char *target, int maxlen, char *source) -{ - int need_to_encode = 0; - int i, len; - unsigned char ch; - - if (target == NULL) return; - len = strlen(source); - for (i=0; i 126)) { - need_to_encode = 1; - i = len; ///< shortcut. won't become more than 1 - } - } - - if (!need_to_encode) { - safestrncpy(target, source, maxlen); - return; - } - - strcpy(target, "=?UTF-8?Q?"); - for (i=0; i 126) || (ch == 61)) { - sprintf(&target[strlen(target)], "=%02X", ch); - } - else { - sprintf(&target[strlen(target)], "%c", ch); - } - } - - strcat(target, "?="); -} - - - - -/** - * \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 - */ -void url(char *buf) -{ - int len; - char *start, *end, *pos; - char urlbuf[SIZ]; - char outbuf[1024]; - - start = NULL; - len = strlen(buf); - end = buf + len; - for (pos = buf; (pos < end) && (start == NULL); ++pos) { - if (!strncasecmp(pos, "http://", 7)) - start = pos; - if (!strncasecmp(pos, "ftp://", 6)) - start = pos; - } - - if (start == NULL) - return; - - for (pos = buf+len; pos > start; --pos) { - if ( (!isprint(*pos)) - || (isspace(*pos)) - || (*pos == '{') - || (*pos == '}') - || (*pos == '|') - || (*pos == '\\') - || (*pos == '^') - || (*pos == '[') - || (*pos == ']') - || (*pos == '`') - || (*pos == '<') - || (*pos == '>') - || (*pos == '(') - || (*pos == ')') - ) { - end = pos; - } - } - - 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); -} - - -/** - * \brief Turn a vCard "n" (name) field into something displayable. - * \param name the name field to convert - */ -void vcard_n_prettyize(char *name) -{ - char *original_name; - int i, j, len; - - original_name = strdup(name); - len = strlen(original_name); - for (i=0; i<5; ++i) { - if (len > 0) { - if (original_name[len-1] == ' ') { - original_name[--len] = 0; - } - if (original_name[len-1] == ';') { - original_name[--len] = 0; - } - } - } - strcpy(name, ""); - j=0; - for (i=0; i"); - name = vcard_get_prop(v, "fn", 1, 0, 0); - if (name != NULL) { - escputs(name); - } - else if (name = vcard_get_prop(v, "n", 1, 0, 0), name != NULL) { - strcpy(fullname, name); - vcard_n_prettyize(fullname); - escputs(fullname); - } - else { - wprintf(" "); - } - wprintf(""); - return; - } - - wprintf("
" - ""); - for (pass=1; pass<=2; ++pass) { - - if (v->numprops) for (i=0; i<(v->numprops); ++i) { - int len; - thisname = strdup(v->prop[i].name); - extract_token(firsttoken, thisname, 0, ';', sizeof firsttoken); - - for (j=0; jprop[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); - j = CtdlDecodeQuotedPrintable( - thisvalue, v->prop[i].value, - len); - thisvalue[j] = 0; - } - else if (is_b64) { - // ff will become one byte.. - thisvalue = malloc(len + 50); - CtdlDecodeBase64( - thisvalue, v->prop[i].value, - strlen(v->prop[i].value) ); - } - else { - thisvalue = strdup(v->prop[i].value); - } - - /** Various fields we may encounter ***/ - - /** N is name, but only if there's no FN already there */ - if (!strcasecmp(firsttoken, "n")) { - if (IsEmptyStr(fullname)) { - strcpy(fullname, thisvalue); - vcard_n_prettyize(fullname); - } - } - - /** FN (full name) is a true 'display name' field */ - else if (!strcasecmp(firsttoken, "fn")) { - strcpy(fullname, thisvalue); - } - - /** title */ - else if (!strcasecmp(firsttoken, "title")) { - strcpy(title, thisvalue); - } - - /** organization */ - else if (!strcasecmp(firsttoken, "org")) { - strcpy(org, thisvalue); - } - - else if (!strcasecmp(firsttoken, "email")) { - size_t len; - if (!IsEmptyStr(mailto)) strcat(mailto, "
"); - strcat(mailto, - ""); - - strcat(mailto, "\">"); - len = strlen(mailto); - stresc(mailto+len, SIZ - len, thisvalue, 1, 1); - strcat(mailto, ""); - } - else if (!strcasecmp(firsttoken, "tel")) { - if (!IsEmptyStr(phone)) strcat(phone, "
"); - strcat(phone, thisvalue); - for (j=0; j
\n"); - } - } - else if (!strcasecmp(firsttoken, "version")) { - /* ignore */ - } - else if (!strcasecmp(firsttoken, "rev")) { - /* ignore */ - } - else if (!strcasecmp(firsttoken, "label")) { - /* ignore */ - } - else { - - /*** Don't show extra fields. They're ugly. - if (pass == 2) { - wprintf("\n"); - } - ***/ - } - - free(thisname); - free(thisvalue); - } - - if (pass == 1) { - wprintf("" - "\n"); - - if (!IsEmptyStr(phone)) { - wprintf("\n", phone); - } - if (!IsEmptyStr(mailto)) { - wprintf("\n", mailto); - } - } - } - wprintf("
"); - wprintf(_("Address:")); - wprintf(""); - for (j=0; j"); - else wprintf(" "); - } - } - wprintf("
"); - escputs(thisname); - wprintf(""); - escputs(thisvalue); - wprintf("
" - "" - ""); - escputs(fullname); - wprintf(""); - if (!IsEmptyStr(title)) { - wprintf("
"); - escputs(title); - wprintf("
"); - } - if (!IsEmptyStr(org)) { - wprintf("
"); - escputs(org); - wprintf("
"); - } - wprintf("
"); - wprintf(_("Telephone:")); - wprintf("%s
"); - wprintf(_("E-mail:")); - wprintf("%s
\n"); -} +void display_enter(void); +int longcmp_r(const void *s1, const void *s2); +int summcmp_subj(const void *s1, const void *s2); +int summcmp_rsubj(const void *s1, const void *s2); +int summcmp_sender(const void *s1, const void *s2); +int summcmp_rsender(const void *s1, const void *s2); +int summcmp_date(const void *s1, const void *s2); +int summcmp_rdate(const void *s1, const void *s2); +/*----------------------------------------------------------------------------*/ -/** - * \brief Display a textual vCard - * (Converts to a vCard object and then calls the actual display function) - * Set 'full' to nonzero to display the whole card instead of a one-liner. - * Or, if "storename" is non-NULL, just store the person's name in that - * buffer instead of displaying the card at all. - * \param vcard_source the buffer containing the vcard text - * \param alpha what??? - * \param full should we usse all lines? - * \param storename where to store??? - */ -void display_vcard(char *vcard_source, char alpha, int full, char *storename) { - struct vCard *v; - char *name; - char buf[SIZ]; - char this_alpha = 0; +typedef void (*MsgPartEvaluatorFunc)(message_summary *Sum, StrBuf *Buf); - v = vcard_load(vcard_source); - if (v == NULL) return; - name = vcard_get_prop(v, "n", 1, 0, 0); - if (name != NULL) { - utf8ify_rfc822_string(name); - strcpy(buf, name); - this_alpha = buf[0]; - } - if (storename != NULL) { - fetchname_parsed_vcard(v, storename); - } - else if ( (alpha == 0) - || ((isalpha(alpha)) && (tolower(alpha) == tolower(this_alpha)) ) - || ((!isalpha(alpha)) && (!isalpha(this_alpha))) - ) { - display_parsed_vcard(v, full); - } - - vcard_free(v); -} +/*----------------------------------------------------------------------------*/ -struct attach_link { - char partnum[32]; - char html[1024]; -}; - /* * I wanna SEE that message! @@ -719,1953 +46,781 @@ struct attach_link { * 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) { +int read_message(StrBuf *Target, const char *tmpl, long tmpllen, long msgnum, int printable_view, const StrBuf *PartNum) { + StrBuf *Buf; + StrBuf *HdrToken; + StrBuf *FoundCharset; + HashPos *it; + void *vMime; + message_summary *Msg = NULL; + headereval *Hdr; + void *vHdr; char buf[SIZ]; - 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[1024] = ""; - char m_cc[1024] = ""; - char from[256] = ""; - char node[256] = ""; - char rfca[256] = ""; - char reply_to[512] = ""; - char reply_all[4096] = ""; - 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 *part_source = NULL; - char msg4_partnum[32] = ""; -#ifdef HAVE_ICONV - iconv_t ic = (iconv_t)(-1) ; - char *ibuf; /**< Buffer of characters to be converted */ - char *obuf; /**< Buffer for converted characters */ - size_t ibuflen; /**< Length of input buffer */ - size_t obuflen; /**< Length of output buffer */ - char *osav; /**< Saved pointer to output buffer */ -#endif - - strcpy(mime_content_type, "text/plain"); - strcpy(mime_charset, "us-ascii"); - strcpy(mime_submessages, ""); - - serv_printf("MSG4 %ld|%s", msgnum, section); - serv_getln(buf, sizeof buf); - if (buf[0] != '1') { - wprintf(""); - wprintf(_("ERROR:")); - wprintf(" %s
\n", &buf[4]); - return; +// char mime_submessages[256] = ""; + char reply_references[1024] = ""; + int Done = 0; + int state=0; + long len; + const char *Key; + + Buf = NewStrBuf(); + lprintf(1, "----------%s---------MSG4 %ld|%s--------------\n", tmpl, msgnum, ChrPtr(PartNum)); + serv_printf("MSG4 %ld|%s", msgnum, ChrPtr(PartNum)); + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) != 1) { + StrBufAppendPrintf(Target, ""); + StrBufAppendPrintf(Target, _("ERROR:")); + StrBufAppendPrintf(Target, " %s
\n", &buf[4]); + FreeStrBuf(&Buf); + return 0; } /** begin everythingamundo table */ - if (!printable_view) { - wprintf("
", msgnum); - } - - /** begin message header table */ - wprintf("
"); - - strcpy(m_subject, ""); - strcpy(m_cc, ""); - - while (serv_getln(buf, sizeof buf), strcasecmp(buf, "text")) { - if (!strcmp(buf, "000")) { - wprintf(""); - wprintf(_("unexpected end of message")); - wprintf(" (1)

\n"); - wprintf("
\n"); - return; - } - if (!strncasecmp(buf, "nhdr=yes", 8)) - nhdr = 1; - if (nhdr == 1) - buf[0] = '_'; - if (!strncasecmp(buf, "type=", 5)) - format_type = atoi(&buf[5]); - if (!strncasecmp(buf, "from=", 5)) { - strcpy(from, &buf[5]); - wprintf(_("from ")); - wprintf(""); - escputs(from); - wprintf(" "); - } - if (!strncasecmp(buf, "subj=", 5)) { - safestrncpy(m_subject, &buf[5], sizeof m_subject); - } - if (!strncasecmp(buf, "cccc=", 5)) { - int len; - safestrncpy(m_cc, &buf[5], sizeof m_cc); - if (!IsEmptyStr(reply_all)) { - strcat(reply_all, ", "); - } - len = strlen(reply_all); - safestrncpy(&reply_all[len], &buf[5], - (sizeof reply_all - len) ); - } - if ((!strncasecmp(buf, "hnod=", 5)) - && (strcasecmp(&buf[5], serv_info.serv_humannode))) { - wprintf("(%s) ", &buf[5]); - } - if ((!strncasecmp(buf, "room=", 5)) - && (strcasecmp(&buf[5], WC->wc_roomname)) - && (!IsEmptyStr(&buf[5])) ) { - wprintf(_("in ")); - wprintf("%s> ", &buf[5]); - } - if (!strncasecmp(buf, "rfca=", 5)) { - strcpy(rfca, &buf[5]); - wprintf("<"); - escputs(rfca); - wprintf("> "); - } - if (!strncasecmp(buf, "node=", 5)) { - strcpy(node, &buf[5]); - if ( ((WC->room_flags & QR_NETWORK) - || ((strcasecmp(&buf[5], serv_info.serv_nodename) - && (strcasecmp(&buf[5], serv_info.serv_fqdn))))) - && (IsEmptyStr(rfca)) - ) { - wprintf("@%s ", &buf[5]); - } - } - if (!strncasecmp(buf, "rcpt=", 5)) { - int len; - wprintf(_("to ")); - if (!IsEmptyStr(reply_all)) { - strcat(reply_all, ", "); - } - len = strlen(reply_all); - safestrncpy(&reply_all[len], &buf[5], - (sizeof reply_all - len) ); - utf8ify_rfc822_string(&buf[5]); - escputs(&buf[5]); - wprintf(" "); - } - if (!strncasecmp(buf, "time=", 5)) { - webcit_fmt_date(now, atol(&buf[5]), 0); - wprintf(""); - wprintf("%s ", now); - wprintf(""); - } - - if (!strncasecmp(buf, "part=", 5)) { - extract_token(mime_name, &buf[5], 0, '|', sizeof mime_filename); - extract_token(mime_filename, &buf[5], 1, '|', sizeof mime_filename); - extract_token(mime_partnum, &buf[5], 2, '|', sizeof mime_partnum); - extract_token(mime_disposition, &buf[5], 3, '|', sizeof mime_disposition); - extract_token(mime_content_type, &buf[5], 4, '|', sizeof mime_content_type); - mime_length = extract_int(&buf[5], 5); - - striplt(mime_name); - striplt(mime_filename); - if ( (IsEmptyStr(mime_filename)) && (!IsEmptyStr(mime_name)) ) { - strcpy(mime_filename, mime_name); - } - - if (!strcasecmp(mime_content_type, "message/rfc822")) { - if (!IsEmptyStr(mime_submessages)) { - strcat(mime_submessages, "|"); - } - strcat(mime_submessages, mime_partnum); - } - else if ((!strcasecmp(mime_disposition, "inline")) - && (!strncasecmp(mime_content_type, "image/", 6)) ){ - ++num_attach_links; - attach_links = realloc(attach_links, - (num_attach_links*sizeof(struct attach_link))); - safestrncpy(attach_links[num_attach_links-1].partnum, mime_partnum, 32); - snprintf(attach_links[num_attach_links-1].html, 1024, - "", - msgnum, mime_partnum, mime_filename); - } - else if ( ( (!strcasecmp(mime_disposition, "attachment")) - || (!strcasecmp(mime_disposition, "inline")) - || (!strcasecmp(mime_disposition, "")) - ) && (!IsEmptyStr(mime_content_type)) - ) { - ++num_attach_links; - 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" - " | " - "%s" - " ]
\n", - mime_content_type_ptr, - mime_filename, - mime_content_type, mime_length, - msgnum, mime_partnum, escaped_mime_filename, - msgnum, mime_partnum, - _("View"), - msgnum, mime_partnum, escaped_mime_filename, - _("Download") - ); - } - - /** begin handler prep ***/ - if ( (!strcasecmp(mime_content_type, "text/x-vcard")) - || (!strcasecmp(mime_content_type, "text/vcard")) ) { - strcpy(vcard_partnum, mime_partnum); - } - - if ( (!strcasecmp(mime_content_type, "text/calendar")) - || (!strcasecmp(mime_content_type, "application/ics")) ) { - strcpy(cal_partnum, mime_partnum); - } - - /** end handler prep ***/ - - } - - } - - /** Generate a reply-to address */ - if (!IsEmptyStr(rfca)) { - if (!IsEmptyStr(from)) { - snprintf(reply_to, sizeof(reply_to), "%s <%s>", from, rfca); - } - else { - strcpy(reply_to, rfca); - } - } - else { - if ((!IsEmptyStr(node)) - && (strcasecmp(node, serv_info.serv_nodename)) - && (strcasecmp(node, serv_info.serv_humannode)) ) { - snprintf(reply_to, sizeof(reply_to), "%s @ %s", - from, node); - } - else { - snprintf(reply_to, sizeof(reply_to), "%s", from); - } - } - - if (nhdr == 1) { - wprintf("****"); - } - - utf8ify_rfc822_string(m_cc); - utf8ify_rfc822_string(m_subject); - - /** start msg buttons */ - - if (!printable_view) { - wprintf("

\n",msgnum); - - /** Reply */ - if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) { - wprintf("is_mailbox) { - wprintf("?replyquote=%ld", msgnum); - } - wprintf("?recp="); - urlescputs(reply_to); - if (!IsEmptyStr(m_subject)) { - wprintf("?subject="); - if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20"); - urlescputs(m_subject); - } - wprintf("\">[%s] ", _("Reply")); - } - - /** ReplyQuoted */ - if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) { - if (!WC->is_mailbox) { - wprintf("[%s] ", _("ReplyQuoted")); - } - } - /** ReplyAll */ - if (WC->wc_view == VIEW_MAILBOX) { - wprintf("[%s] ", _("ReplyAll")); - } - - /** 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 ( (WC->is_room_aide) || (WC->is_mailbox) || (WC->room_flags2 & QR2_COLLABDEL) ) { - /** Move */ - wprintf("[%s] ", - msgnum, _("Move")); - - /** Delete */ - wprintf("" - "[%s] " - " ", msgnum, _("Delete this message?"), _("Delete") - ); - } - - /** Headers */ - wprintf("" - "[%s]", msgnum, msgnum, _("Headers")); - - - /** Print */ - wprintf("" - "[%s]", msgnum, msgnum, _("Print")); - - wprintf("

"); - - } - - if (!IsEmptyStr(m_cc)) { - wprintf("

"); - wprintf(_("CC:")); - wprintf(" "); - escputs(m_cc); - wprintf("

"); - } - if (!IsEmptyStr(m_subject)) { - wprintf("

"); - wprintf(_("Subject:")); - wprintf(" "); - escputs(m_subject); - wprintf("

"); - } - - wprintf("
"); - - /** 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")) { - /* This is not necessarily an error condition. See bug #226. */ - goto ENDBODY; - } - if (!strncasecmp(buf, "X-Citadel-MSG4-Partnum:", 23)) { - safestrncpy(msg4_partnum, &buf[23], sizeof(msg4_partnum)); - striplt(msg4_partnum); - } - if (!strncasecmp(buf, "Content-type:", 13)) { - int len; - safestrncpy(mime_content_type, &buf[13], sizeof(mime_content_type)); - striplt(mime_content_type); - len = strlen(mime_content_type); - for (i=0; iMsgBody->ContentType = NewStrBufPlain(HKEY("text/html")); + StrBufAppendPrintf(Msg->MsgBody->Data, "
"); + StrBufAppendPrintf(Msg->MsgBody->Data, _("unexpected end of message")); + StrBufAppendPrintf(Msg->MsgBody->Data, " (1)

\n"); + StrBufAppendPrintf(Msg->MsgBody->Data, "
\n"); + } + break; + } + switch (state) { + case 0:/* Citadel Message Headers */ + if (StrLength(Buf) == 0) { + state ++; + break; + } + StrBufExtract_token(HdrToken, Buf, 0, '='); + StrBufCutLeft(Buf, StrLength(HdrToken) + 1); + + lprintf(1, ":: [%s] = [%s]\n", ChrPtr(HdrToken), ChrPtr(Buf)); + if (GetHash(MsgHeaderHandler, SKEY(HdrToken), &vHdr) && + (vHdr != NULL)) { + Hdr = (headereval*)vHdr; + Hdr->evaluator(Msg, Buf, FoundCharset); + if (Hdr->Type == 1) { + state++; } } - len = strlen(mime_charset); - for (i=0; iMsgBody->ContentType == NULL) + /* end of header or no header? */ + Msg->MsgBody->ContentType = NewStrBufPlain(HKEY("text/plain")); + /* usual end of mime header */ + } + else + { + StrBufExtract_token(HdrToken, Buf, 0, ':'); + if (StrLength(HdrToken) > 0) { + StrBufCutLeft(Buf, StrLength(HdrToken) + 1); + lprintf(1, ":: [%s] = [%s]\n", ChrPtr(HdrToken), ChrPtr(Buf)); + if (GetHash(MsgHeaderHandler, SKEY(HdrToken), &vHdr) && + (vHdr != NULL)) { + Hdr = (headereval*)vHdr; + Hdr->evaluator(Msg, Buf, FoundCharset); + } + break; } } - } - } - - /** Set up a character set conversion if we need to (and if we can) */ -#ifdef HAVE_ICONV - if (strchr(mime_charset, ';')) strcpy(strchr(mime_charset, ';'), ""); - if ( (strcasecmp(mime_charset, "us-ascii")) - && (strcasecmp(mime_charset, "UTF-8")) - && (strcasecmp(mime_charset, "")) - ) { - ic = ctdl_iconv_open("UTF-8", mime_charset); - if (ic == (iconv_t)(-1) ) { - lprintf(5, "%s:%d iconv_open(UTF-8, %s) failed: %s\n", - __FILE__, __LINE__, mime_charset, strerror(errno)); - } - } -#endif - - /** 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... */ - else if ( (!strcasecmp(mime_content_type, "text/plain")) - || (!strcasecmp(mime_content_type, "text")) ) { - buf [0] = '\0'; - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - int len; - len = strlen(buf); - 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) ) { - ibuf = buf; - ibuflen = strlen(ibuf); - obuflen = SIZ; - obuf = (char *) malloc(obuflen); - osav = obuf; - iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen); - osav[SIZ-obuflen] = 0; - safestrncpy(buf, osav, sizeof buf); - free(osav); - } -#endif - - len = strlen(buf); - while ((!IsEmptyStr(buf)) && (isspace(buf[len-1]))) - buf[--len] = 0; - if ((bq == 0) && - ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) )) { - wprintf("
"); - bq = 1; - } else if ((bq == 1) && - (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) ) { - wprintf("
"); - bq = 0; - } - wprintf(""); - url(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)); - } - - /** Unknown weirdness */ - else { - wprintf(_("I don't know how to display %s"), mime_content_type); - wprintf("
\n", mime_content_type); - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { } - } - -ENDBODY: /* If there are attached submessages, display them now... */ - - if ( (!IsEmptyStr(mime_submessages)) && (!section[0]) ) { - for (i=0; i"); - read_message(msgnum, 1, buf); - wprintf(""); - } - } - - - /** Afterwards, offer links to download attachments 'n' such */ - if ( (num_attach_links > 0) && (!section[0]) ) { - for (i=0; iMsgBody->size_known > 0) { + StrBuf_ServGetBLOB(Msg->MsgBody->Data, Msg->MsgBody->length); + state ++; + /// todo: check next line, if not 000, append following lines } - } - } - - /** Handler for vCard parts */ - if (!IsEmptyStr(vcard_partnum)) { - part_source = load_mimepart(msgnum, vcard_partnum); - if (part_source != NULL) { - - /** If it's my vCard I can edit it */ - if ( (!strcasecmp(WC->wc_roomname, USERCONFIGROOM)) - || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM)) - || (WC->wc_view == VIEW_ADDRESSBOOK) - ) { - wprintf("", - msgnum, vcard_partnum); - wprintf("[%s]", _("edit")); + else if (1){ + if (StrLength(Msg->MsgBody->Data) > 0) + StrBufAppendBufPlain(Msg->MsgBody->Data, "\n", 1, 0); + StrBufAppendBuf(Msg->MsgBody->Data, Buf, 0); } - - /** In all cases, display the full card */ - display_vcard(part_source, 0, 1, NULL); + break; + case 3: + StrBufAppendBuf(Msg->MsgBody->Data, Buf, 0); + break; } } - /** 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); - } - } - - if (part_source) { - free(part_source); - part_source = NULL; - } - - wprintf("
\n"); - - /** end everythingamundo table */ - if (!printable_view) { - wprintf("\n"); - } - - if (num_attach_links > 0) { - free(attach_links); - } - -#ifdef HAVE_ICONV - if (ic != (iconv_t)(-1) ) { - iconv_close(ic); - } -#endif -} - - - -/** - * \brief 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 - */ -void embed_message(char *msgnum_as_string) { - long msgnum = 0L; - - msgnum = atol(msgnum_as_string); - begin_ajax_response(); - read_message(msgnum, 0, ""); - end_ajax_response(); -} - - -/** - * \brief Printable view of a message - * - * \param msgnum_as_string Message number, as a string instead of as a long int - */ -void print_message(char *msgnum_as_string) { - long msgnum = 0L; - - msgnum = atol(msgnum_as_string); - output_headers(0, 0, 0, 0, 0, 0); - - wprintf("Content-type: text/html\r\n" - "Server: %s\r\n" - "Connection: close\r\n", - PACKAGE_STRING); - begin_burst(); - - wprintf("\r\n\r\n\n" - "Printable view\n" - "\n" - ); + if (Msg->AllAttach == NULL) + Msg->AllAttach = NewHash(1,NULL); + Put(Msg->AllAttach, SKEY(Msg->MsgBody->PartNum), Msg->MsgBody, DestroyMime); - read_message(msgnum, 1, ""); - - wprintf("\n\n\n"); - 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) { - long msgnum = 0L; - char buf[1024]; - - msgnum = atol(msgnum_as_string); - output_headers(0, 0, 0, 0, 0, 0); - - wprintf("Content-type: text/plain\r\n" - "Server: %s\r\n" - "Connection: close\r\n", - PACKAGE_STRING); - begin_burst(); - - serv_printf("MSG2 %ld|3", msgnum); - serv_getln(buf, sizeof buf); - if (buf[0] == '1') { - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - wprintf("%s\n", buf); - } - } - - wDumpContent(0); -} - - - -/** - * \brief Read message in simple, JavaScript-embeddable form for 'forward' - * or 'reply quoted' operations. - * - * NOTE: it is VITALLY IMPORTANT that we output no single-quotes or linebreaks - * in this function. Doing so would throw a JavaScript error in the - * 'supplied text' argument to the editor. - * - * \param msgnum Message number of the message we want to quote - * \param forward_attachments Nonzero if we want attachments to be forwarded - */ -void pullquote_message(long msgnum, int forward_attachments, int include_headers) { - char buf[SIZ]; - char mime_partnum[256]; - char mime_filename[256]; - char mime_content_type[256]; - char mime_charset[256]; - char mime_disposition[256]; - int mime_length; - char *attachments = NULL; - char *ptr = NULL; - int num_attachments = 0; - struct wc_attachment *att, *aptr; - 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; - int nhdr = 0; - int bq = 0; - int i = 0; -#ifdef HAVE_ICONV - iconv_t ic = (iconv_t)(-1) ; - char *ibuf; /**< Buffer of characters to be converted */ - char *obuf; /**< Buffer for converted characters */ - size_t ibuflen; /**< Length of input buffer */ - size_t obuflen; /**< Length of output buffer */ - char *osav; /**< Saved pointer to output buffer */ -#endif - - strcpy(from, ""); - strcpy(node, ""); - strcpy(rfca, ""); - strcpy(reply_to, ""); - strcpy(mime_content_type, "text/plain"); - strcpy(mime_charset, "us-ascii"); - - serv_printf("MSG4 %ld", msgnum); - serv_getln(buf, sizeof buf); - if (buf[0] != '1') { - wprintf(_("ERROR:")); - wprintf("%s
", &buf[4]); - return; - } - - strcpy(m_subject, ""); - - while (serv_getln(buf, sizeof buf), strcasecmp(buf, "text")) { - if (!strcmp(buf, "000")) { - wprintf("%s (3)", _("unexpected end of message")); - return; - } - if (include_headers) { - if (!strncasecmp(buf, "nhdr=yes", 8)) - nhdr = 1; - if (nhdr == 1) - buf[0] = '_'; - if (!strncasecmp(buf, "type=", 5)) - format_type = atoi(&buf[5]); - if (!strncasecmp(buf, "from=", 5)) { - strcpy(from, &buf[5]); - wprintf(_("from ")); - utf8ify_rfc822_string(from); - msgescputs(from); - } - if (!strncasecmp(buf, "subj=", 5)) { - strcpy(m_subject, &buf[5]); - } - if ((!strncasecmp(buf, "hnod=", 5)) - && (strcasecmp(&buf[5], serv_info.serv_humannode))) { - wprintf("(%s) ", &buf[5]); - } - if ((!strncasecmp(buf, "room=", 5)) - && (strcasecmp(&buf[5], WC->wc_roomname)) - && (!IsEmptyStr(&buf[5])) ) { - wprintf(_("in ")); - wprintf("%s> ", &buf[5]); - } - if (!strncasecmp(buf, "rfca=", 5)) { - strcpy(rfca, &buf[5]); - wprintf("<"); - msgescputs(rfca); - wprintf("> "); - } - - if (!strncasecmp(buf, "node=", 5)) { - strcpy(node, &buf[5]); - if ( ((WC->room_flags & QR_NETWORK) - || ((strcasecmp(&buf[5], serv_info.serv_nodename) - && (strcasecmp(&buf[5], serv_info.serv_fqdn))))) - && (IsEmptyStr(rfca)) - ) { - wprintf("@%s ", &buf[5]); - } - } - if (!strncasecmp(buf, "rcpt=", 5)) { - wprintf(_("to ")); - strcpy(to, &buf[5]); - utf8ify_rfc822_string(to); - wprintf("%s ", to); - } - if (!strncasecmp(buf, "time=", 5)) { - webcit_fmt_date(now, atol(&buf[5]), 0); - wprintf("%s ", now); - } - } - - /** - * Save attachment info for later. We can't start downloading them - * yet because we're in the middle of a server transaction. + /* strip the bare contenttype, so we ommit charset etc. */ + StrBufExtract_token(Buf, Msg->MsgBody->ContentType, 0, ';'); + StrBufTrim(Buf); + if (GetHash(MimeRenderHandler, SKEY(Buf), &vHdr) && + (vHdr != NULL)) { + RenderMimeFunc Render; + Render = (RenderMimeFunc)vHdr; + Render(Msg->MsgBody, NULL, FoundCharset); + } + + if (StrLength(Msg->reply_references)> 0) { + /* Trim down excessively long lists of thread references. We eliminate the + * second one in the list so that the thread root remains intact. */ - if (!strncasecmp(buf, "part=", 5)) { - ptr = malloc( (strlen(buf) + ((attachments != NULL) ? strlen(attachments) : 0)) ) ; - if (ptr != NULL) { - ++num_attachments; - sprintf(ptr, "%s%s\n", - ((attachments != NULL) ? attachments : ""), - &buf[5] - ); - free(attachments); - attachments = ptr; - lprintf(9, "attachments=<%s>\n", attachments); - } - } - - } - - if (include_headers) { - wprintf("
"); - - utf8ify_rfc822_string(m_subject); - if (!IsEmptyStr(m_subject)) { - wprintf(_("Subject:")); - wprintf(" "); - msgescputs(m_subject); - wprintf("
"); - } - - /** - * 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("%s (4)", _("unexpected end of message")); - goto ENDBODY; - } - if (!strncasecmp(buf, "Content-type: ", 14)) { - int len; - safestrncpy(mime_content_type, &buf[14], - sizeof(mime_content_type)); - for (i=0; ireply_references), '|'); + int rrlen = StrLength(Msg->reply_references); + if ( ((rrtok >= 3) && (rrlen > 900)) || (rrtok > 10) ) { + remove_token(reply_references, 1, '|');////todo } } -#endif - /** Messages in legacy Citadel variformat get handled thusly... */ - if (!strcasecmp(mime_content_type, "text/x-citadel-variformat")) { - pullquote_fmout(); - } - - /* Boring old 80-column fixed format text gets handled this way... */ - else if (!strcasecmp(mime_content_type, "text/plain")) { - 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; - -#ifdef HAVE_ICONV - if (ic != (iconv_t)(-1) ) { - ibuf = buf; - ibuflen = len; - obuflen = SIZ; - obuf = (char *) malloc(obuflen); - osav = obuf; - iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen); - osav[SIZ-obuflen] = 0; - safestrncpy(buf, osav, sizeof buf); - free(osav); - } -#endif - - len = strlen(buf); - while ((!IsEmptyStr(buf)) && (isspace(buf[len - 1]))) - buf[--len] = 0; - if ((bq == 0) && - ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) )) { - wprintf("
"); - bq = 1; - } else if ((bq == 1) && - (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) ) { - wprintf("
"); - bq = 0; - } - wprintf(""); - url(buf); - msgescputs1(buf); - wprintf("
"); - } - wprintf("
"); - } - - /** HTML just gets escaped and stuffed back into the editor */ - else if (!strcasecmp(mime_content_type, "text/html")) { - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - strcat(buf, "\n"); - msgescputs(buf); + /* Generate a reply-to address */ + if (StrLength(Msg->Rfca) > 0) { + if (Msg->reply_to == NULL) + Msg->reply_to = NewStrBuf(); + if (StrLength(Msg->from) > 0) { + StrBufPrintf(Msg->reply_to, "%s <%s>", ChrPtr(Msg->from), ChrPtr(Msg->Rfca)); } - } - - /** Unknown weirdness ... don't know how to handle this content type */ - else { - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { } - } - -ENDBODY: - /** end of body handler */ - - /* - * If there were attachments, we have to download them and insert them - * into the attachment chain for the forwarded message we are composing. - */ - if ( (forward_attachments) && (num_attachments) ) { - for (i=0; ilength = mime_length; - strcpy(att->content_type, mime_content_type); - strcpy(att->filename, mime_filename); - att->next = NULL; - att->data = load_mimepart(msgnum, mime_partnum); - - /* And add it to the list. */ - if (WC->first_attachment == NULL) { - WC->first_attachment = att; - } - else { - aptr = WC->first_attachment; - while (aptr->next != NULL) aptr = aptr->next; - aptr->next = att; - } - } - + else { + FlushStrBuf(Msg->reply_to); + StrBufAppendBuf(Msg->reply_to, Msg->Rfca, 0); } } - -#ifdef HAVE_ICONV - if (ic != (iconv_t)(-1) ) { - iconv_close(ic); - } -#endif - - if (attachments != NULL) { - free(attachments); - } -} - -/** - * \brief Display one row in the mailbox summary view - * - * \param num The row number to be displayed - */ -void display_summarized(int num) { - char datebuf[64]; - - wprintf("", - WC->summ[num].msgnum, - (WC->summ[num].is_new ? "bold" : "normal"), - WC->summ[num].msgnum - ); - - wprintf("", SUBJ_COL_WIDTH_PCT); - - escputs(WC->summ[num].subj);//////////////////////////////////TODO: QP DECODE - wprintf(""); - - wprintf("", SENDER_COL_WIDTH_PCT); - escputs(WC->summ[num].from); - wprintf(""); - - wprintf("", DATE_PLUS_BUTTONS_WIDTH_PCT); - webcit_fmt_date(datebuf, WC->summ[num].date, 1); /* brief */ - escputs(datebuf); - wprintf(""); - - wprintf("\n"); -} - - - -/** - * \brief display the adressbook overview - * \param msgnum the citadel message number - * \param alpha what???? - */ -void display_addressbook(long msgnum, char alpha) { - char buf[SIZ]; - char mime_partnum[SIZ]; - char mime_filename[SIZ]; - char mime_content_type[SIZ]; - char mime_disposition[SIZ]; - int mime_length; - char vcard_partnum[SIZ]; - char *vcard_source = NULL; - struct message_summary summ; - - memset(&summ, 0, sizeof(summ)); - safestrncpy(summ.subj, _("(no subject)"), sizeof summ.subj); - - sprintf(buf, "MSG0 %ld|1", msgnum); /* ask for headers only */ - serv_puts(buf); - serv_getln(buf, sizeof buf); - if (buf[0] != '1') return; - - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - if (!strncasecmp(buf, "part=", 5)) { - extract_token(mime_filename, &buf[5], 1, '|', sizeof mime_filename); - extract_token(mime_partnum, &buf[5], 2, '|', sizeof mime_partnum); - extract_token(mime_disposition, &buf[5], 3, '|', sizeof mime_disposition); - extract_token(mime_content_type, &buf[5], 4, '|', sizeof mime_content_type); - mime_length = extract_int(&buf[5], 5); - - if ( (!strcasecmp(mime_content_type, "text/x-vcard")) - || (!strcasecmp(mime_content_type, "text/vcard")) ) { - strcpy(vcard_partnum, mime_partnum); - } - + else + { + if ((StrLength(Msg->OtherNode)>0) && + (strcasecmp(ChrPtr(Msg->OtherNode), serv_info.serv_nodename)) && + (strcasecmp(ChrPtr(Msg->OtherNode), serv_info.serv_humannode)) ) + { + if (Msg->reply_to == NULL) + Msg->reply_to = NewStrBuf(); + StrBufPrintf(Msg->reply_to, + "%s @ %s", + ChrPtr(Msg->from), + ChrPtr(Msg->OtherNode)); } - } - - if (!IsEmptyStr(vcard_partnum)) { - vcard_source = load_mimepart(msgnum, vcard_partnum); - if (vcard_source != NULL) { - - /** Display the summary line */ - display_vcard(vcard_source, alpha, 0, NULL); - - /** If it's my vCard I can edit it */ - if ( (!strcasecmp(WC->wc_roomname, USERCONFIGROOM)) - || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM)) - || (WC->wc_view == VIEW_ADDRESSBOOK) - ) { - wprintf("", - msgnum, vcard_partnum); - wprintf("[%s]", _("edit")); - } - - free(vcard_source); + else { + if (Msg->reply_to == NULL) + Msg->reply_to = NewStrBuf(); + FlushStrBuf(Msg->reply_to); + StrBufAppendBuf(Msg->reply_to, Msg->from, 0); } } + it = GetNewHashPos(Msg->AllAttach, 0); + while (GetNextHashPos(Msg->AllAttach, it, &len, &Key, &vMime) && + (vMime != NULL)) { + wc_mime_attachment *Mime = (wc_mime_attachment*) vMime; + evaluate_mime_part(Msg, Mime); + } + DeleteHashPos(&it); + DoTemplate(tmpl, tmpllen, Target, Msg, CTX_MAILSUM); + + DestroyMessageSummary(Msg); + FreeStrBuf(&FoundCharset); + FreeStrBuf(&HdrToken); + FreeStrBuf(&Buf); + return 1; } -/** - * \brief If it's an old "Firstname Lastname" style record, try to convert it. - * \param namebuf name to analyze, reverse if nescessary +/* + * Unadorned HTML output of an individual message, suitable + * for placing in a hidden iframe, for printing, or whatever + * + * msgnum_as_string == Message number, as a string instead of as a long int */ -void lastfirst_firstlast(char *namebuf) { - char firstname[SIZ]; - char lastname[SIZ]; - int i; - - if (namebuf == NULL) return; - if (strchr(namebuf, ';') != NULL) return; - - i = num_tokens(namebuf, ' '); - if (i < 2) return; +void embed_message(void) { + long msgnum = 0L; + const StrBuf *Tmpl = sbstr("template"); - extract_token(lastname, namebuf, i-1, ' ', sizeof lastname); - remove_token(namebuf, i-1, ' '); - strcpy(firstname, namebuf); - sprintf(namebuf, "%s; %s", lastname, firstname); + msgnum = StrTol(WC->UrlFragment2); + if (StrLength(Tmpl) > 0) + read_message(WC->WBuf, SKEY(Tmpl), msgnum, 0, NULL); + else + read_message(WC->WBuf, HKEY("view_message"), msgnum, 0, NULL); } -/** - * \brief fetch what??? name - * \param msgnum the citadel message number - * \param namebuf where to put the name in??? - */ -void fetch_ab_name(long msgnum, char *namebuf) { - char buf[SIZ]; - char mime_partnum[SIZ]; - char mime_filename[SIZ]; - char mime_content_type[SIZ]; - char mime_disposition[SIZ]; - int mime_length; - char vcard_partnum[SIZ]; - char *vcard_source = NULL; - int i, len; - struct message_summary summ; - - if (namebuf == NULL) return; - strcpy(namebuf, ""); - - memset(&summ, 0, sizeof(summ)); - safestrncpy(summ.subj, "(no subject)", sizeof summ.subj); - - sprintf(buf, "MSG0 %ld|0", msgnum); /** unfortunately we need the mime info now */ - serv_puts(buf); - serv_getln(buf, sizeof buf); - if (buf[0] != '1') return; - - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - if (!strncasecmp(buf, "part=", 5)) { - extract_token(mime_filename, &buf[5], 1, '|', sizeof mime_filename); - extract_token(mime_partnum, &buf[5], 2, '|', sizeof mime_partnum); - extract_token(mime_disposition, &buf[5], 3, '|', sizeof mime_disposition); - extract_token(mime_content_type, &buf[5], 4, '|', sizeof mime_content_type); - mime_length = extract_int(&buf[5], 5); - - if ( (!strcasecmp(mime_content_type, "text/x-vcard")) - || (!strcasecmp(mime_content_type, "text/vcard")) ) { - strcpy(vcard_partnum, mime_partnum); - } - - } - } - if (!IsEmptyStr(vcard_partnum)) { - vcard_source = load_mimepart(msgnum, vcard_partnum); - if (vcard_source != NULL) { - - /* Grab the name off the card */ - display_vcard(vcard_source, 0, 0, namebuf); +/* + * Printable view of a message + * + * msgnum_as_string == Message number, as a string instead of as a long int + */ +void print_message(void) { + long msgnum = 0L; - free(vcard_source); - } - } + msgnum = StrTol(WC->UrlFragment2); + output_headers(0, 0, 0, 0, 0, 0); - lastfirst_firstlast(namebuf); - striplt(namebuf); - len = strlen(namebuf); - for (i=0; iWBuf, HKEY("view_message_print"), msgnum, 1, NULL); -/** - * \brief Record compare function for sorting address book indices - * \param ab1 adressbook one - * \param ab2 adressbook two - */ -int abcmp(const void *ab1, const void *ab2) { - return(strcasecmp( - (((const struct addrbookent *)ab1)->ab_name), - (((const struct addrbookent *)ab2)->ab_name) - )); + wDumpContent(0); } - -/** - * \brief Helper function for do_addrbook_view() - * Converts a name into a three-letter tab label - * \param tabbuf the tabbuffer to add name to - * \param name the name to add to the tabbuffer +/* + * Mobile browser view of message + * + * @param msg_num_as_string Message number as a string instead of as a long int */ -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]); - tabbuf[3] = 0; +void mobile_message_view(void) { + long msgnum = 0L; + msgnum = StrTol(WC->UrlFragment2); + output_headers(1, 0, 0, 0, 0, 1); + begin_burst(); + do_template("msgcontrols", NULL); + read_message(WC->WBuf, HKEY("view_message"), msgnum,1, NULL); + wDumpContent(0); } - /** - * \brief Render the address book using info we gathered during the scan - * \param addrbook the addressbook to render - * \param num_ab the number of the addressbook + * \brief Display a message's headers + * + * \param msgnum_as_string Message number, as a string instead of as a long int */ -void do_addrbook_view(struct addrbookent *addrbook, int num_ab) { - int i = 0; - int displayed = 0; - int bg = 0; - static int NAMESPERPAGE = 60; - int num_pages = 0; - int tabfirst = 0; - char tabfirst_label[64]; - int tablast = 0; - char tablast_label[64]; - char this_tablabel[64]; - int page = 0; - char **tablabels; - - if (num_ab == 0) { - wprintf("


"); - wprintf(_("This address book is empty.")); - wprintf("
\n"); - return; - } - - if (num_ab > 1) { - qsort(addrbook, num_ab, sizeof(struct addrbookent), abcmp); - } +void display_headers(void) { + long msgnum = 0L; + char buf[1024]; - num_pages = (num_ab / NAMESPERPAGE) + 1; + msgnum = StrTol(WC->UrlFragment2); + output_headers(0, 0, 0, 0, 0, 0); - tablabels = malloc(num_pages * sizeof (char *)); - if (tablabels == NULL) { - wprintf("


"); - wprintf(_("An internal error has occurred.")); - wprintf("
\n"); - return; - } + hprintf("Content-type: text/plain\r\n" + "Server: %s\r\n" + "Connection: close\r\n", + PACKAGE_STRING); + begin_burst(); - for (i=0; i (num_ab - 1)) tablast = (num_ab - 1); - 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); + serv_printf("MSG2 %ld|3", msgnum); + serv_getln(buf, sizeof buf); + if (buf[0] == '1') { + while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { + wprintf("%s\n", buf); + } } - tabbed_dialog(num_pages, tablabels); - page = (-1); + wDumpContent(0); +} - for (i=0; i 0) { - wprintf("\n"); - end_tab(page-1, num_pages); - } - begin_tab(page, num_pages); - wprintf("\n"); - displayed = 0; - } +message_summary *ReadOneMessageSummary(StrBuf *RawMessage, const char *DefaultSubject, long MsgNum) +{ + void *vEval; + MsgPartEvaluatorFunc Eval; + message_summary *Msg; + StrBuf *Buf; + const char *buf; + const char *ebuf; + int nBuf; + long len; + + Buf = NewStrBuf(); - if ((displayed % 4) == 0) { - if (displayed > 0) { - wprintf("\n"); - } - bg = 1 - bg; - wprintf("", - (bg ? "DDDDDD" : "FFFFFF") - ); - } + serv_printf("MSG0 %ld|1", MsgNum); /* ask for headers only */ - wprintf("\n"); - ++displayed; - } + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) == 1) { + FreeStrBuf(&Buf); + return NULL; + } + + Msg = (message_summary*)malloc(sizeof(message_summary)); + memset(Msg, 0, sizeof(message_summary)); + while (len = StrBuf_ServGetln(Buf), + ((len != 3) || + strcmp(ChrPtr(Buf), "000")== 0)){ + buf = ChrPtr(Buf); + ebuf = strchr(ChrPtr(Buf), '='); + nBuf = ebuf - buf; + if (GetHash(MsgEvaluators, buf, nBuf, &vEval) && vEval != NULL) { + Eval = (MsgPartEvaluatorFunc) vEval; + StrBufCutLeft(Buf, nBuf + 1); + Eval(Msg, Buf); + } + else lprintf(1, "Don't know how to handle Message Headerline [%s]", ChrPtr(Buf)); + } + return Msg; +} - wprintf("
"); - - wprintf("", bstr("alpha")); - vcard_n_prettyize(addrbook[i].ab_name); - escputs(addrbook[i].ab_name); - wprintf("
\n"); - end_tab((num_pages-1), num_pages); - for (i=0; isumm != NULL) { - free(WC->summ); - WC->num_summ = 0; - WC->summ = NULL; + if (WCC->summ != NULL) { + if (WCC->summ != NULL) + DeleteHash(&WCC->summ); } - num_summ_alloc = 100; - WC->num_summ = 0; - WC->summ = malloc(num_summ_alloc * sizeof(struct message_summary)); - + WCC->summ = NewHash(1, Flathash); nummsgs = 0; - maxload = sizeof(WC->msgarr) / sizeof(long) ; + maxload = 10000; + + Buf = NewStrBuf(); serv_puts(servcmd); - serv_getln(buf, sizeof buf); - if (buf[0] != '1') { + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) != 1) { + FreeStrBuf(&Buf); return (nummsgs); } - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { +// TODO if (with_headers) { //// TODO: Have Attachments? + Buf2 = NewStrBuf(); + while (len = StrBuf_ServGetln(Buf), + ((len != 3) || + strcmp(ChrPtr(Buf), "000")!= 0)) + { if (nummsgs < maxload) { - WC->msgarr[nummsgs] = extract_long(buf, 0); - datestamp = extract_long(buf, 1); - extract_token(fullname, buf, 2, '|', sizeof fullname); - extract_token(nodename, buf, 3, '|', sizeof nodename); - extract_token(inetaddr, buf, 4, '|', sizeof inetaddr); - extract_token(subject, buf, 5, '|', sizeof subject); - ++nummsgs; - - if (with_headers) { - if (nummsgs > num_summ_alloc) { - num_summ_alloc *= 2; - WC->summ = realloc(WC->summ, - num_summ_alloc * sizeof(struct message_summary)); - } - ++WC->num_summ; + Msg = (message_summary*)malloc(sizeof(message_summary)); + memset(Msg, 0, sizeof(message_summary)); - memset(&WC->summ[nummsgs-1], 0, sizeof(struct message_summary)); - 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)) { + Msg->msgnum = StrBufExtract_long(Buf, 0, '|'); + Msg->date = StrBufExtract_long(Buf, 1, '|'); + + Msg->from = NewStrBufPlain(NULL, StrLength(Buf)); + StrBufExtract_token(Buf2, Buf, 2, '|'); + if (StrLength(Buf2) != 0) { /** 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); - safestrncpy(WC->summ[nummsgs-1].subj, subject, - sizeof WC->summ[nummsgs-1].subj); - } - sbjlen = Ctdl_Utf8StrLen(WC->summ[nummsgs-1].subj); - if (sbjlen > 75) { - char *ptr; - ptr = Ctdl_Utf8StrCut(WC->summ[nummsgs-1].subj, 72); + StrBuf_RFC822_to_Utf8(Msg->from, Buf2, WCC->DefaultCharset, FoundCharset); + } + + /** Nodename */ + StrBufExtract_token(Buf2, Buf, 3, '|'); + if ((StrLength(Buf2) !=0 ) && + ( ((WCC->room_flags & QR_NETWORK) + || ((strcasecmp(ChrPtr(Buf2), serv_info.serv_nodename) + && (strcasecmp(ChrPtr(Buf2), serv_info.serv_fqdn))))))) + { + StrBufAppendBufPlain(Msg->from, HKEY(" @ "), 0); + StrBufAppendBuf(Msg->from, Buf2, 0); + } - strcpy(ptr, "..."); - } + /** Not used: + StrBufExtract_token(Msg->inetaddr, Buf, 4, '|'); + */ - 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); - } + Msg->subj = NewStrBufPlain(NULL, StrLength(Buf)); + StrBufExtract_token(Buf2, Buf, 5, '|'); + if (StrLength(Buf2) == 0) + StrBufAppendBufPlain(Msg->subj, _("(no subj)"), 0, -1); + else { + StrBuf_RFC822_to_Utf8(Msg->subj, Buf2, WCC->DefaultCharset, FoundCharset); + if ((StrLength(Msg->subj) > 75) && + (StrBuf_Utf8StrLen(Msg->subj) > 75)) { + StrBuf_Utf8StrCut(Msg->subj, 72); + StrBufAppendBufPlain(Msg->subj, HKEY("..."), 0); } + } - 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], "..."); - } + + if ((StrLength(Msg->from) > 25) && + (StrBuf_Utf8StrLen(Msg->from) > 25)) { + StrBuf_Utf8StrCut(Msg->from, 23); + StrBufAppendBufPlain(Msg->from, HKEY("..."), 0); } + n = Msg->msgnum; + Put(WCC->summ, (const char *)&n, sizeof(n), Msg, DestroyMessageSummary); } + nummsgs++; } + FreeStrBuf(&Buf2); + FreeStrBuf(&Buf); 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 - */ -int longcmp_r(const void *s1, const void *s2) { - long l1; - long l2; - - l1 = *(long *)s1; - l2 = *(long *)s2; - - if (l1 > l2) return(-1); - if (l1 < l2) return(+1); - return(0); -} - - -/** - * \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 - */ -int summcmp_subj(const void *s1, const void *s2) { - struct message_summary *summ1; - struct message_summary *summ2; - - summ1 = (struct message_summary *)s1; - summ2 = (struct message_summary *)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 - */ -int summcmp_rsubj(const void *s1, const void *s2) { - struct message_summary *summ1; - struct message_summary *summ2; - - summ1 = (struct message_summary *)s1; - summ2 = (struct message_summary *)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 - */ -int summcmp_sender(const void *s1, const void *s2) { - struct message_summary *summ1; - struct message_summary *summ2; - - summ1 = (struct message_summary *)s1; - summ2 = (struct message_summary *)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 - */ -int summcmp_rsender(const void *s1, const void *s2) { - struct message_summary *summ1; - struct message_summary *summ2; - - summ1 = (struct message_summary *)s1; - summ2 = (struct message_summary *)s2; - return strcasecmp(summ2->from, summ1->from); +inline message_summary* GetMessagePtrAt(int n, HashList *Summ) +{ + const char *Key; + long HKLen; + void *vMsg; + + if (Summ == NULL) + return NULL; + GetHashAt(Summ, n, &HKLen, &Key, &vMsg); + return (message_summary*) vMsg; } -/** - * \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 - */ -int summcmp_date(const void *s1, const void *s2) { - struct message_summary *summ1; - struct message_summary *summ2; - - summ1 = (struct message_summary *)s1; - summ2 = (struct message_summary *)s2; - - if (summ1->date < summ2->date) return -1; - else if (summ1->date > summ2->date) return +1; - 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 - */ -int summcmp_rdate(const void *s1, const void *s2) { - struct message_summary *summ1; - struct message_summary *summ2; +void DrawMessageDropdown(StrBuf *Selector, long maxmsgs, long startmsg) +{ + StrBuf *TmpBuf; + struct wcsession *WCC = WC; + message_summary* Msg; + int lo, hi, n; + int i = 0; + long StartMsg; + void *vMsg; + long hklen; + const char *key; + int done = 0; + int nItems; + HashPos *At; + long vector[16]; + int nMessages = DEFAULT_MAXMSGS; + + TmpBuf = NewStrBuf(); + At = GetNewHashPos(WCC->summ, (lbstr("SortOrder") == 1)? -nMessages : nMessages); + nItems = GetCount(WCC->summ); - summ1 = (struct message_summary *)s1; - summ2 = (struct message_summary *)s2; + vector[0] = 7; + vector[1] = startmsg; + vector[2] = maxmsgs; + vector[3] = 0; + vector[4] = 1; - if (summ1->date < summ2->date) return +1; - else if (summ1->date > summ2->date) return -1; - else return 0; + while (!done) { + lo = GetHashPosCounter(At); + if (lo + nMessages > nItems) { + hi = nItems; + } + else { + hi = lo + nMessages; + } + done = !GetNextHashPos(WCC->summ, At, &hklen, &key, &vMsg); + Msg = (message_summary*) vMsg; + n = (Msg==NULL)? 0 : Msg->msgnum; + if (i == 0) + StartMsg = n; + vector[4] = lo; + vector[5] = hi; + vector[6] = n; + FlushStrBuf(TmpBuf); + DoTemplate(HKEY("select_messageindex"), TmpBuf, &vector, CTX_LONGVECTOR); + StrBufAppendBuf(Selector, TmpBuf, 0); + i++; + } + vector[6] = StartMsg; + FlushStrBuf(TmpBuf); + DoTemplate(HKEY("select_messageindex_all"), TmpBuf, &vector, CTX_LONGVECTOR); + StrBufAppendBuf(Selector, TmpBuf, 0); + FreeStrBuf(&TmpBuf); + DeleteHashPos(&At); } +extern readloop_struct rlid[]; -/** - * \brief command loop for reading messages +/* + * 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) +void readloop(long oper) { + StrBuf *MessageDropdown = NULL; + StrBuf *BBViewToolBar = NULL; + void *vMsg; + message_summary *Msg; char cmd[256] = ""; char buf[SIZ]; char old_msgs[SIZ]; - int a, b; + int a = 0; + ///int b = 0; int nummsgs; - long startmsg; - int maxmsgs; + long startmsg = 0; + int maxmsgs = 0; long *displayed_msgs = NULL; int num_displayed = 0; int is_summary = 0; int is_addressbook = 0; int is_singlecard = 0; int is_calendar = 0; + struct calview calv; int is_tasks = 0; int is_notes = 0; int is_bbview = 0; - int lo, hi; int lowest_displayed = (-1); int highest_displayed = 0; - struct addrbookent *addrbook = NULL; + 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; int bbs_reverse = 0; - struct wcsession *WCC = WC; /* This is done to make it run faster; WC is a function */ - - if (WCC->wc_view == VIEW_WIKI) { - sprintf(buf, "wiki?room=%s?page=home", WCC->wc_roomname); + struct wcsession *WCC = WC; + HashPos *at; + const char *HashKey; + long HKLen; + int care_for_empty_list = 0; + int load_seen = 0; + int sortit = 0; + + switch (WCC->wc_view) { + case 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("is_summary")); - 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); - - sortby = bstr("sortby"); - if ( (!IsEmptyStr(sortby)) && (strcasecmp(sortby, sortpref_value)) ) { - set_preference(sortpref_name, sortby, 1); - } - if (IsEmptyStr(sortby)) sortby = sortpref_value; - - /** mailbox sort */ - if (IsEmptyStr(sortby)) sortby = "rdate"; - - /** message board sort */ - if (!strcasecmp(sortby, "reverse")) { - bbs_reverse = 1; - } - else { - bbs_reverse = 0; - } - - 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. - */ - if (!strcmp(oper, "readnew")) { - strcpy(cmd, "MSGS NEW"); - } - else if (!strcmp(oper, "readold")) { - strcpy(cmd, "MSGS OLD"); - } - else if (!strcmp(oper, "do_search")) { - snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); - } - else { - strcpy(cmd, "MSGS ALL"); - } - - if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1)) { - is_summary = 1; - if (!strcmp(oper, "do_search")) { - snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); - } - else { - strcpy(cmd, "MSGS ALL"); - } - } - - if ((WCC->wc_view == VIEW_ADDRESSBOOK) && (maxmsgs > 1)) { - is_addressbook = 1; - if (!strcmp(oper, "do_search")) { - snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); - } - else { - strcpy(cmd, "MSGS ALL"); - } - maxmsgs = 9999999; - } - - if (is_summary) { /**< 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; - } - - /** - * 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) || (WCC->wc_default_view == VIEW_CALENDAR)){ - serv_puts("GTSN"); - serv_getln(buf, sizeof buf); - if (buf[0] == '2') { - strcpy(old_msgs, &buf[4]); - } - } - - is_singlecard = atoi(bstr("is_singlecard")); - - if (WCC->wc_default_view == VIEW_CALENDAR) { /**< calendar */ + case VIEW_CALENDAR: + load_seen = 1; is_calendar = 1; strcpy(cmd, "MSGS ALL|||1"); maxmsgs = 32767; - } - if (WCC->wc_default_view == VIEW_TASKS) { /**< tasks */ + parse_calendar_view_request(&calv); + break; + case VIEW_TASKS: is_tasks = 1; strcpy(cmd, "MSGS ALL"); maxmsgs = 32767; - } - if (WCC->wc_default_view == VIEW_NOTES) { /**< notes */ + break; + case VIEW_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); - if (nummsgs == 0) { - - if ((!is_tasks) && (!is_calendar) && (!is_notes) && (!is_addressbook)) { - wprintf("

"); - if (!strcmp(oper, "readnew")) { - wprintf(_("No new messages.")); - } else if (!strcmp(oper, "readold")) { - wprintf(_("No old messages.")); - } else { - wprintf(_("No messages here.")); + break; + case VIEW_ADDRESSBOOK: + is_singlecard = ibstr("is_singlecard"); + if (maxmsgs > 1) { + is_addressbook = 1; + if (oper == do_search) { + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); } - wprintf("
\n"); - } - - goto DONE; - } - - if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR)){ - 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, WCC->msgarr[a])) { - WCC->summ[a].is_new = 0; - } - else { - WCC->summ[a].is_new = 1; - } + else { + strcpy(cmd, "MSGS ALL"); } + maxmsgs = 9999999; + break; } - } - - if (startmsg == 0L) { - if (bbs_reverse) { - startmsg = WCC->msgarr[(nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0]; - } - else { - startmsg = WCC->msgarr[0]; - } - } - - 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 = "" ; - } - 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) { - wprintf("\n" - ); + default: + care_for_empty_list = 1; + startmsg = lbstr("startmsg"); + if (havebstr("maxmsgs")) + maxmsgs = ibstr("maxmsgs"); + is_summary = (ibstr("is_summary") && !WCC->is_mobile); + if (maxmsgs == 0) maxmsgs = DEFAULT_MAXMSGS; + - /** note that Date and Delete are now in the same column */ - wprintf("
" - "
" - "" - "" - ); - wprintf("" - "" - "" - "\n" - , - SUBJ_COL_WIDTH_PCT, - _("Subject"), subjsort_button, - SENDER_COL_WIDTH_PCT, - _("Sender"), sendsort_button, - DATE_PLUS_BUTTONS_WIDTH_PCT, - _("Date"), datesort_button, - _("Delete") - ); - wprintf("
%s %s%s %s%s %s" - " " - "" - "
\n"); + + /* + * When in summary mode, always show ALL messages instead of just + * new or old. Otherwise, show what the user asked for. + */ + rlid[oper].cmd(cmd, sizeof(cmd)); + + if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1) && !WCC->is_mobile) { + is_summary = 1; + if (oper != do_search) { + strcpy(cmd, "MSGS ALL"); + } + } - wprintf("
" + is_bbview = !is_summary; + if (is_summary) { /**< fetch header summary */ + load_seen = 1; + snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1", + (oper == do_search) ? "SEARCH" : "ALL", + (oper == do_search) ? bstr("query") : "" + ); + startmsg = 1; + maxmsgs = 9999999; + } - "
\n" + bbs_reverse = is_bbview && (lbstr("SortOrder") == 2); - "" - ); + if (is_bbview && (startmsg == 0L)) { + if (bbs_reverse) { + Msg = GetMessagePtrAt((nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0, WCC->summ); + startmsg = (Msg==NULL)? 0 : Msg->msgnum; + } + else { + Msg = GetMessagePtrAt(0, WCC->summ); + startmsg = (Msg==NULL)? 0 : Msg->msgnum; + } + } + sortit = is_summary || WCC->is_mobile; } - /** - * Set the "is_bbview" variable if it appears that we are looking at - * a classic bulletin board view. - */ - if ((!is_tasks) && (!is_calendar) && (!is_addressbook) - && (!is_notes) && (!is_singlecard) && (!is_summary)) { - is_bbview = 1; + output_headers(1, 1, 1, 0, 0, 0); + + /* + 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; } - /** - * If we're not currently looking at ALL requested - * messages, then display the selector bar + /* + * 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. */ - if (is_bbview) { - /** begin bbview scroller */ - wprintf(" \n

"); - wprintf(_("Reading #"), lowest_displayed, highest_displayed); - wprintf(" "); - wprintf(_("of %d messages."), nummsgs); - - /** forward/reverse */ - wprintf(""); - wprintf(_("oldest to newest")); - wprintf("    "); - - wprintf(""); - wprintf(_("newest to oldest")); - wprintf("\n"); - - wprintf("

\n"); - /** end bbview scroller */ + DeleteHashPos(&at); } - if (is_notes) - { - wprintf ("\n"); + if (sortit) { + CompareFunc SortIt; + SortIt = RetrieveSort(CTX_MAILSUM, NULL, + HKEY("date"), 2); + if (SortIt != NULL) + SortByPayload(WCC->summ, SortIt); } + if (is_summary) { + do_template("summary_header", NULL); + } else if (WCC->is_mobile) { + wprintf("
"); + } - for (a = 0; a < nummsgs; ++a) { - if ((WCC->msgarr[a] >= startmsg) && (num_displayed < maxmsgs)) { + /** + * If we're not currently looking at ALL requested + * messages, then display the selector bar + */ + if (is_bbview) { + BBViewToolBar = NewStrBuf(); + MessageDropdown = NewStrBuf(); + DrawMessageDropdown(MessageDropdown, maxmsgs, startmsg); + + DoTemplate(HKEY("msg_listselector_top"), BBViewToolBar, MessageDropdown, CTX_STRBUF); + StrBufAppendBuf(WCC->WBuf, BBViewToolBar, 0); + FlushStrBuf(BBViewToolBar); + } + + at = GetNewHashPos(WCC->summ, 0); + while (GetNextHashPos(WCC->summ, at, &HKLen, &HashKey, &vMsg)) { + Msg = (message_summary*) vMsg; + if ((Msg->msgnum >= startmsg) && (num_displayed < maxmsgs)) { + /** Display the message */ if (is_summary) { - display_summarized(a); + DoTemplate(HKEY("section_mailsummary"), NULL, Msg, CTX_MAILSUM); } else if (is_addressbook) { - fetch_ab_name(WCC->msgarr[a], buf); + fetch_ab_name(Msg, buf); ++num_ab; addrbook = realloc(addrbook, - (sizeof(struct addrbookent) * num_ab) ); + (sizeof(addrbookent) * num_ab) ); safestrncpy(addrbook[num_ab-1].ab_name, buf, - sizeof(addrbook[num_ab-1].ab_name)); - addrbook[num_ab-1].ab_msgnum = WCC->msgarr[a]; + sizeof(addrbook[num_ab-1].ab_name)); + addrbook[num_ab-1].ab_msgnum = Msg->msgnum; } else if (is_calendar) { - display_calendar(WCC->msgarr[a], WCC->summ[a].is_new); + load_calendar_item(Msg, Msg->is_new, &calv); } else if (is_tasks) { - display_task(WCC->msgarr[a], WCC->summ[a].is_new); + display_task(Msg, Msg->is_new); } else if (is_notes) { - display_note(WCC->msgarr[a], WCC->summ[a].is_new); + display_note(Msg, Msg->is_new); + } else if (WCC->is_mobile) { + DoTemplate(HKEY("section_mailsummary"), NULL, Msg, CTX_MAILSUM); } else { if (displayed_msgs == NULL) { displayed_msgs = malloc(sizeof(long) * (maxmsgsmsgarr[a]; + displayed_msgs[num_displayed] = Msg->msgnum; } - + if (lowest_displayed < 0) lowest_displayed = a; highest_displayed = a; - + ++num_displayed; } } + DeleteHashPos(&at); /** Output loop */ if (displayed_msgs != NULL) { if (bbs_reverse) { - qsort(displayed_msgs, num_displayed, sizeof(long), longcmp_r); + ////TODOqsort(displayed_msgs, num_displayed, sizeof(long), qlongcmp_r); } /** if we do a split bbview in the future, begin messages div here */ for (a=0; aWBuf, HKEY("view_message"), displayed_msgs[a], 0, NULL); } /** if we do a split bbview in the future, end messages div here */ @@ -2675,18 +830,9 @@ void readloop(char *oper) } if (is_summary) { - 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("
" - "

" - "
\n" - ); - - wprintf("
"); /**< The preview pane will initially be empty */ + do_template("summary_trailer", NULL); + } else if (WCC->is_mobile) { + wprintf("
"); } /** @@ -2702,124 +848,21 @@ void readloop(char *oper) */ if (is_bbview) { /** begin bbview scroller */ - wprintf("
\n

"); - wprintf(_("Reading #"), lowest_displayed, highest_displayed); - - wprintf(" "); - wprintf(_("of %d messages."), nummsgs); - - /** forward/reverse */ - wprintf(""); - wprintf(_("oldest to newest")); - wprintf("    "); - wprintf(""); - wprintf(_("newest to oldest")); - wprintf("\n"); + DoTemplate(HKEY("msg_listselector_bottom"), BBViewToolBar, MessageDropdown, CTX_STRBUF); + StrBufAppendBuf(WCC->WBuf, BBViewToolBar, 0); - wprintf("

\n"); - /** end bbview scroller */ + FreeStrBuf(&BBViewToolBar); + FreeStrBuf(&MessageDropdown); } - if (is_notes) - { -// wprintf ("\n"); - wprintf ("
Drop notes here to remove them.
\n"); - wprintf ("\n"); - } - - - DONE: if (is_tasks) { do_tasks_view(); /** Render the task list */ } if (is_calendar) { - do_calendar_view(); /** Render the calendar */ + render_calendar_view(&calv); } if (is_addressbook) { @@ -2832,24 +875,24 @@ DONE: /** free the summary */ if (WCC->summ != NULL) { - free(WCC->summ); - WCC->num_summ = 0; - WCC->summ = NULL; + DeleteHash(&WCC->summ); } if (addrbook != NULL) free(addrbook); + FreeStrBuf(&BBViewToolBar); } -/** - * \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) { + struct wcsession *WCC = WC; char top_boundary[SIZ]; char alt_boundary[SIZ]; int is_multipart = 0; static int seq = 0; - struct wc_attachment *att; + wc_mime_attachment *att; char *encoded; size_t encoded_length; size_t encoded_strlen; @@ -2866,25 +909,22 @@ void post_mime_to_server(void) { ++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: " PACKAGE_STRING); - /** If there are attachments, we have to do multipart/mixed */ - if (WC->first_attachment != NULL) { + /* If there are attachments, we have to do multipart/mixed */ + if (GetCount(WCC->attachments) > 0) { is_multipart = 1; } if (is_multipart) { - /** Remember, serv_printf() appends an extra newline */ - serv_printf("Content-type: multipart/mixed; " - "boundary=\"%s\"\n", top_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", top_boundary); } - - /* Remember, serv_printf() appends an extra newline */ serv_printf("Content-type: multipart/alternative; " "boundary=\"%s\"\n", alt_boundary); @@ -2895,7 +935,7 @@ void post_mime_to_server(void) { 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 */ + text_to_server_qp(txtmail); /* Transmit message in quoted-printable encoding */ free(txtmail); serv_printf("--%s", alt_boundary); @@ -2904,30 +944,29 @@ void post_mime_to_server(void) { 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 */ - for (att = WC->first_attachment; att!=NULL; att=att->next) { - + long len; + const char *Key; + void *vAtt; + HashPos *it; + + /* Add in the attachments */ + it = GetNewHashPos(WCC->attachments, 0); + while (GetNextHashPos(WCC->attachments, it, &len, &Key, &vAtt)) { + att = (wc_mime_attachment *)vAtt; encoded_length = ((att->length * 150) / 100); encoded = malloc(encoded_length); if (encoded == NULL) break; - encoded_strlen = CtdlEncodeBase64(encoded, att->data, att->length, 1); + encoded_strlen = CtdlEncodeBase64(encoded, ChrPtr(att->Data), StrLength(att->Data), 1); 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-type: %s", ChrPtr(att->ContentType)); + serv_printf("Content-disposition: attachment; filename=\"%s\"", ChrPtr(att->FileName)); serv_puts("Content-transfer-encoding: base64"); serv_puts(""); serv_write(encoded, encoded_strlen); @@ -2936,14 +975,15 @@ void post_mime_to_server(void) { free(encoded); } serv_printf("--%s--", top_boundary); + DeleteHashPos(&it); } 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 @@ -2956,102 +996,155 @@ 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; + wc_mime_attachment *att; int is_anonymous = 0; - char *display_name; - - if (!IsEmptyStr(bstr("force_room"))) { + 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) { + const char *pch; + int n; + char N[64]; - 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->next = NULL; - - /** And add it to the list. */ - if (WC->first_attachment == NULL) { - WC->first_attachment = att; - } - else { - aptr = WC->first_attachment; - while (aptr->next != NULL) aptr = aptr->next; - aptr->next = att; - } + att = malloc(sizeof(wc_mime_attachment)); + memset(att, 0, sizeof(wc_mime_attachment )); + att->length = WCC->upload_length; + att->ContentType = NewStrBufPlain(WCC->upload_content_type, -1); + att->FileName = NewStrBufPlain(WCC->upload_filename, -1); + + + if (WCC->attachments == NULL) + WCC->attachments = NewHash(1, NULL); + /* And add it to the list. */ + n = snprintf(N, sizeof N, "%d", GetCount(WCC->attachments) + 1); + Put(WCC->attachments, N, n, att, DestroyMime); /** * Mozilla sends a simple filename, which is what we want, * but Satan's Browser sends an entire pathname. Reduce * the path to just a filename if we need to. */ - while (num_tokens(att->filename, '/') > 1) { - remove_token(att->filename, 0, '/'); + pch = strrchr(ChrPtr(att->FileName), '/'); + if (pch != NULL) { + StrBufCutLeft(att->FileName, pch - ChrPtr(att->FileName)); } - while (num_tokens(att->filename, '\\') > 1) { - remove_token(att->filename, 0, '\\'); + pch = strrchr(ChrPtr(att->FileName), '\\'); + if (pch != NULL) { + StrBufCutLeft(att->FileName, pch - ChrPtr(att->FileName)); } /** * 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 = NewStrBufPlain(WCC->upload, WCC->upload_length); + free(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 { - webcit_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", ChrPtr(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]); @@ -3060,19 +1153,19 @@ void post_message(void) } } - free_attachments(WC); + DeleteHash(&WCC->attachments); /** * 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); } @@ -3080,7 +1173,7 @@ void post_message(void) * Otherwise, just go to the "read messages" loop. */ else { - readloop("readnew"); + readloop(readnew); } } @@ -3093,26 +1186,25 @@ void post_message(void) void display_enter(void) { char buf[SIZ]; - char ebuf[SIZ]; long now; - char *display_name; - struct wc_attachment *att; + const StrBuf *display_name = NULL; + /////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; } @@ -3124,8 +1216,8 @@ 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]); - readloop("readnew"); + sprintf(WCC->ImportantMessage, "%s", &buf[4]); + readloop(readnew); return; } @@ -3138,8 +1230,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; } @@ -3147,7 +1239,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; } @@ -3156,7 +1248,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; } @@ -3165,334 +1257,63 @@ void display_enter(void) * Otherwise proceed normally. * Do a custom room banner with no navbar... */ - output_headers(1, 1, 2, 0, 0, 0); - wprintf("
\n"); - embed_room_banner(NULL, navbar_none); - wprintf("
\n"); - wprintf("
\n" - "
"); - /** 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; } } else if (buf[0] != '2') { /** Any other error means that we cannot continue */ - wprintf("%s
\n", &buf[4]); - goto DONE; - } - } - - /** If we got this far, we can display the message entry screen. */ - - /** begin message entry screen */ - wprintf("
\n"); - wprintf("\n", now); - if (WC->wc_view == VIEW_WIKI) { - wprintf("\n", bstr("wikipage")); - } - wprintf("\n", bstr("return_to")); - wprintf("\n", WC->nonce); - wprintf("wc_roomname); - wprintf("\">\n"); - - /** submit or cancel buttons */ - wprintf("

"); - wprintf(" " - "\n", _("Cancel")); - wprintf("

"); - - /** header bar */ - - wprintf(""); - wprintf(" "); /** header bar */ - webcit_fmt_date(buf, now, 0); - wprintf("%s", buf); - wprintf("\n"); /** header bar */ - - wprintf(""); - wprintf(""); - wprintf(""); - - wprintf(""); - - if (recipient_required) { - char *ccraw; - char *copy; - size_t len; - wprintf("" - ""); - - wprintf("" - ""); - - wprintf("" - ""); - - /** Initialize the autocomplete ajax helpers (found in wclib.js) */ - wprintf(" \n" - ); - - } - - wprintf("" - ""); - - wprintf("
"); - - /* Allow the user to select any of his valid screen names */ - - wprintf("\n"); - - /* If this is an email (not a post), allow the user to select any of his - * valid email addresses. - */ - if (recipient_required) { - serv_puts("GVEA"); - serv_getln(buf, sizeof buf); - if (buf[0] == '1') { - wprintf("\n"); - } - } - - wprintf(_(" in ")); - escputs(WC->wc_roomname); - - wprintf("
"); - wprintf("
"); - wprintf("
"); - - /** Pop open an address book -- begin **/ - wprintf( - "" - "" - " %s", - _("To:"), _("CC:"), _("BCC:"), - _("Contacts"), _("Contacts") - ); - /** Pop open an address book -- end **/ - - wprintf("
"); - wprintf("
"); - wprintf("
"); - wprintf("
"); - wprintf("
" - "\n"); - wprintf("
\n"); - - wprintf("\n"); - - /** Make sure we only insert our signature once */ - /** We don't care if it was there or not before, it needs to be there now. */ - wprintf("\n"); - - /** - * The following template embeds the TinyMCE richedit control, and automatically - * transforms the textarea into a richedit textarea. - */ - do_template("richedit"); - - /** Enumerate any attachments which are already in place... */ - wprintf("
"); - wprintf(_("Attachments:")); - wprintf(" "); - wprintf(""); - - /** Now offer the ability to attach additional files... */ - wprintf("   "); - wprintf(_("Attach file:")); - wprintf(" \n  " - "\n", _("Add")); - wprintf("
"); /* End of "attachment buttons" div */ - - - wprintf("
"); - - wprintf("
\n"); - wprintf("
\n"); /* end of "fix_scrollbar_bug" div */ + begin_burst(); + output_headers(1, 0, 0, 0, 1, 0); + DoTemplate(HKEY("edit_message"), NULL, NULL, CTX_NONE); + end_burst(); - /* NOTE: address_book_popup() will close the "content" div. Don't close it here. */ -DONE: address_book_popup(); - wDumpContent(1); + return; } - /** * \brief delete a message */ @@ -3501,7 +1322,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); @@ -3513,7 +1334,7 @@ void delete_msg(void) serv_getln(buf, sizeof buf); sprintf(WC->ImportantMessage, "%s", &buf[4]); - readloop("readnew"); + readloop(readnew); } @@ -3525,9 +1346,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); @@ -3536,15 +1357,15 @@ void move_msg(void) sprintf(WC->ImportantMessage, (_("The message was not moved."))); } - readloop("readnew"); + readloop(readnew); } -/** - * \brief Confirm move of a message +/* + * Confirm move of a message */ void confirm_move_msg(void) { @@ -3552,7 +1373,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); @@ -3570,7 +1391,7 @@ void confirm_move_msg(void) wprintf("
\n"); wprintf("
\n"); - wprintf("\n", WC->nonce); + wprintf("\n", WC->nonce); wprintf("\n", bstr("msgid")); wprintf("