X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fmessages.c;h=7676c9dd80ad04b0cc36e88043a596d0c7078fba;hb=76f23da782e9e80dad0a8ae1336230da5a6fa124;hp=d12d54e99130a81e1b19abf767c3ad7e61df04e7;hpb=cf934431c7c8c1091b38c0b374f6a3b9293841ca;p=citadel.git diff --git a/webcit/messages.c b/webcit/messages.c index d12d54e99..7676c9dd8 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -13,7 +13,7 @@ #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) */ @@ -26,13 +26,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) { @@ -51,11 +51,27 @@ 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, *next, *nextend, *ptr; @@ -74,7 +90,7 @@ void utf8ify_rfc822_string(char *buf) { 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 @@ -88,10 +104,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; @@ -114,14 +131,14 @@ void utf8ify_rfc822_string(char *buf) { nextend = end = NULL; len = strlen(buf); start = strstr(buf, "=?"); - if (start != NULL) - end = strstr(start, "?="); + if (start != NULL) + end = FindNextEnd (start); while ((start != NULL) && (end != NULL)) { next = strstr(end, "=?"); if (next != NULL) - nextend = strstr(next, "?="); + nextend = FindNextEnd(next); if (nextend == NULL) next = NULL; @@ -158,10 +175,10 @@ void utf8ify_rfc822_string(char *buf) { end = nextend; } - /** Now we handle foreign character sets properly encoded - * in RFC2047 format. + /* 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); @@ -230,7 +247,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 @@ -257,58 +274,82 @@ inline void utf8ify_rfc822_string(char *a){}; * \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 webcit_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)) @@ -339,17 +380,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'; } @@ -431,8 +490,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; @@ -601,6 +661,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 */ } @@ -675,8 +743,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]; @@ -699,7 +769,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); @@ -740,6 +810,8 @@ void read_message(long msgnum, int printable_view, char *section) { 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; @@ -811,6 +883,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); @@ -952,7 +1030,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); @@ -985,7 +1072,7 @@ void read_message(long msgnum, int printable_view, char *section) { if (!printable_view) { wprintf("

\n",msgnum); - /** Reply */ + /* Reply */ if ( (WC->wc_view == VIEW_MAILBOX) || (WC->wc_view == VIEW_BBS) ) { wprintf("is_mailbox) { @@ -995,13 +1082,19 @@ void read_message(long msgnum, int printable_view, char *section) { urlescputs(reply_to); if (!IsEmptyStr(m_subject)) { wprintf("?subject="); - if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%20"); + if (strncasecmp(m_subject, "Re:", 3)) wprintf("Re:%%20"); urlescputs(m_subject); } + wprintf("?references="); + if (!IsEmptyStr(reply_references)) { + 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] ", @@ -1055,12 +1160,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")); @@ -1085,10 +1190,10 @@ 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"); @@ -1128,7 +1233,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")) @@ -1143,12 +1248,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'; @@ -1185,22 +1290,22 @@ 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")) { + /* HTML is fun, but we've got to strip it first */ + else if (!strcasecmp(mime_content_type, "text/html")) { output_html(mime_charset, (WC->wc_view == VIEW_WIKI ? 1 : 0)); } - /** Unknown weirdness */ + /* Unknown weirdness */ else { wprintf(_("I don't know how to display %s"), mime_content_type); - wprintf("
\n", mime_content_type); + wprintf("
\n"); while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { } } @@ -1217,7 +1322,7 @@ ENDBODY: /* If there are attached submessages, display them now... */ } - /** Afterwards, offer links to download attachments 'n' such */ + /* Afterwards, offer links to download attachments 'n' such */ if ( (num_attach_links > 0) && (!section[0]) ) { for (i=0; 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); } } @@ -1263,7 +1366,7 @@ ENDBODY: /* If there are attached submessages, display them now... */ wprintf("
\n"); - /** end everythingamundo table */ + /* end everythingamundo table */ if (!printable_view) { wprintf("\n"); } @@ -1281,31 +1384,29 @@ ENDBODY: /* If there are attached submessages, display them now... */ -/** - * \brief Unadorned HTML output of an individual message, suitable +/* + * Unadorned HTML output of an individual message, suitable * for placing in a hidden iframe, for printing, or whatever * - * \param msgnum_as_string Message number, as a string instead of as a long int + * msgnum_as_string == Message number, as a string instead of as a long int */ -void embed_message(char *msgnum_as_string) { +void embed_message(void) { long msgnum = 0L; - msgnum = atol(msgnum_as_string); - begin_ajax_response(); + msgnum = StrTol(WC->UrlFragment1); read_message(msgnum, 0, ""); - end_ajax_response(); } -/** - * \brief Printable view of a message +/* + * Printable view of a message * - * \param msgnum_as_string Message number, as a string instead of as a long int + * msgnum_as_string == Message number, as a string instead of as a long int */ -void print_message(char *msgnum_as_string) { +void print_message(void) { long msgnum = 0L; - msgnum = atol(msgnum_as_string); + msgnum = StrTol(WC->UrlFragment1); output_headers(0, 0, 0, 0, 0, 0); wprintf("Content-type: text/html\r\n" @@ -1314,8 +1415,9 @@ void print_message(char *msgnum_as_string) { PACKAGE_STRING); begin_burst(); - wprintf("\r\n\r\n\n" - "Printable view\n" + wprintf("\r\n\r\n\n"); + escputs(WC->wc_fullname); + wprintf("\n" "\n" ); @@ -1332,11 +1434,11 @@ void print_message(char *msgnum_as_string) { * * \param msgnum_as_string Message number, as a string instead of as a long int */ -void display_headers(char *msgnum_as_string) { +void display_headers(void) { long msgnum = 0L; char buf[1024]; - msgnum = atol(msgnum_as_string); + msgnum = StrTol(WC->UrlFragment1); output_headers(0, 0, 0, 0, 0, 0); wprintf("Content-type: text/plain\r\n" @@ -1381,7 +1483,7 @@ 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]; @@ -1455,7 +1557,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) @@ -1605,7 +1706,7 @@ void pullquote_message(long msgnum, int forward_attachments, int include_headers bq = 0; } wprintf(""); - url(buf); + url(buf, sizeof(buf)); msgescputs1(buf); wprintf("
"); } @@ -1618,7 +1719,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 { @@ -1695,7 +1796,6 @@ ENDBODY: */ void display_summarized(int num) { char datebuf[64]; - wprintf("", WC->summ[num].msgnum, @@ -1719,8 +1819,26 @@ void display_summarized(int num) { 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("
"); + wprintf(WC->summ[num].subj); + wprintf("
",WC->summ[num].msgnum); +} /** * \brief display the adressbook overview @@ -1767,7 +1885,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)) @@ -1858,7 +1976,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); } @@ -2013,8 +2131,10 @@ int load_msg_ptrs(char *servcmd, int with_headers) char fullname[128]; char nodename[128]; char inetaddr[128]; - char subject[256]; + char subject[1024]; + char *ptr; int nummsgs; + int sbjlen; int maxload = 0; int num_summ_alloc = 0; @@ -2057,45 +2177,49 @@ int load_msg_ptrs(char *servcmd, int with_headers) WC->summ[nummsgs-1].msgnum = WC->msgarr[nummsgs-1]; safestrncpy(WC->summ[nummsgs-1].subj, _("(no subject)"), sizeof WC->summ[nummsgs-1].subj); - if (!IsEmptyStr(fullname)) { - /** Handle senders with RFC2047 encoding */ - utf8ify_rfc822_string(fullname); - safestrncpy(WC->summ[nummsgs-1].from, - fullname, sizeof WC->summ[nummsgs-1].from); - } if (!IsEmptyStr(subject)) { /** Handle subjects with RFC2047 encoding */ utf8ify_rfc822_string(subject); safestrncpy(WC->summ[nummsgs-1].subj, subject, sizeof WC->summ[nummsgs-1].subj); } - if (strlen(WC->summ[nummsgs-1].subj) > 75) { - strcpy(&WC->summ[nummsgs-1].subj[72], "..."); - } + 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; - + if (!IsEmptyStr(fullname)) { /** 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], "..."); + 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); } + +typedef int (*QSortFunction) (const void*, const void*); /** * \brief qsort() compatible function to compare two longs in descending order. * @@ -2212,6 +2336,84 @@ int summcmp_rdate(const void *s1, const void *s2) { } +enum { + eUp, + eDown, + eNone +}; + +const char* SortIcons[3] = { + "static/up_pointer.gif", + "static/down_pointer.gif", + "static/sort_none.gif" +}; + + enum {/// SortByEnum + eDate, + eRDate, + eSubject, + eRSubject, + eSender, + eRSender, + eReverse, + eUnSet +}; + +/** SortEnum to plain string representation */ +static const char* SortByStrings[] = { + "date", + "rdate", + "subject", + "rsubject", + "sender", + "rsender", + "reverse", + "unset" +}; + +/** SortEnum to sort-Function Table */ +const QSortFunction SortFuncs[eUnSet] = { + summcmp_date, + summcmp_rdate, + summcmp_subj, + summcmp_rsubj, + summcmp_sender, + summcmp_rsender, + summcmp_rdate +}; + +/** given a SortEnum, which icon should we choose? */ +const int SortDateToIcon[eUnSet] = { eUp, eDown, eNone, eNone, eNone, eNone, eNone}; +const int SortSubjectToIcon[eUnSet] = { eNone, eNone, eUp, eDown, eNone, eNone, eNone}; +const int SortSenderToIcon[eUnSet] = { eNone, eNone, eNone, eNone, eUp, eDown, eNone}; + +/** given a SortEnum, which would be the "opposite" search option? */ +const int DateInvertSortString[eUnSet] = { eRDate, eDate, eDate, eDate, eDate, eDate, eDate}; +const int SubjectInvertSortString[eUnSet] = { eSubject, eSubject, eRSubject, eUnSet, eSubject, eSubject, eSubject}; +const int SenderInvertSortString[eUnSet] = { eSender, eSender, eSender, eSender, eRSender, eUnSet, eSender}; + + +/** + * \Brief Translates sortoption String to its SortEnum representation + * \param SortBy string to translate + * \return the enum matching the string; defaults to RDate + */ +//SortByEnum +int StrToESort (StrBuf *sortby) +{ + int result = eDate; + + if (!IsEmptyStr(ChrPtr(sortby))) while (result < eUnSet){ + if (!strcasecmp(ChrPtr(sortby), + SortByStrings[result])) + return result; + result ++; + } + return eRDate; +} + + + /** * \brief command loop for reading messages @@ -2220,7 +2422,7 @@ int summcmp_rdate(const void *s1, const void *s2) { */ void readloop(char *oper) { - char cmd[256]; + char cmd[256] = ""; char buf[SIZ]; char old_msgs[SIZ]; int a, b; @@ -2241,12 +2443,11 @@ void readloop(char *oper) int highest_displayed = 0; struct addrbookent *addrbook = NULL; int num_ab = 0; - char *sortby = NULL; - char sortpref_name[128]; - char sortpref_value[128]; - char *subjsort_button; - char *sendsort_button; - char *datesort_button; + StrBuf *sortby = NULL; + //SortByEnum + int SortBy = eRDate; + StrBuf *sortpref_name; + StrBuf *sortpref_value; int bbs_reverse = 0; struct wcsession *WCC = WC; /* This is done to make it run faster; WC is a function */ @@ -2256,25 +2457,27 @@ void readloop(char *oper) return; } - startmsg = atol(bstr("startmsg")); - maxmsgs = atoi(bstr("maxmsgs")); - is_summary = atoi(bstr("is_summary")); + startmsg = lbstr("startmsg"); + maxmsgs = ibstr("maxmsgs"); + is_summary = (ibstr("is_summary") && !WCC->is_mobile); if (maxmsgs == 0) maxmsgs = DEFAULT_MAXMSGS; - snprintf(sortpref_name, sizeof sortpref_name, "sort %s", WCC->wc_roomname); - get_preference(sortpref_name, sortpref_value, sizeof sortpref_value); + sortpref_name = NewStrBuf (); + StrBufPrintf(sortpref_name, "sort %s", WCC->wc_roomname); + get_pref(sortpref_name, &sortpref_value); - sortby = bstr("sortby"); - if ( (!IsEmptyStr(sortby)) && (strcasecmp(sortby, sortpref_value)) ) { - set_preference(sortpref_name, sortby, 1); + sortby = NewStrBufPlain(bstr("sortby"), -1); + if ( (!IsEmptyStr(ChrPtr(sortby))) && + (strcasecmp(ChrPtr(sortby), ChrPtr(sortpref_value)) != 0)) { + set_pref(sortpref_name, sortby, 1); + sortpref_value = NULL; + sortpref_value = sortby; } - if (IsEmptyStr(sortby)) sortby = sortpref_value; - - /** mailbox sort */ - if (IsEmptyStr(sortby)) sortby = "rdate"; - + + FreeStrBuf(&sortpref_name); + SortBy = StrToESort(sortpref_value); /** message board sort */ - if (!strcasecmp(sortby, "reverse")) { + if (SortBy == eReverse) { bbs_reverse = 1; } else { @@ -2294,16 +2497,16 @@ 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 ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1)) { + if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1) && !WCC->is_mobile) { is_summary = 1; if (!strcmp(oper, "do_search")) { - sprintf(cmd, "MSGS SEARCH|%s", bstr("query")); + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); } else { strcpy(cmd, "MSGS ALL"); @@ -2313,7 +2516,7 @@ void readloop(char *oper) 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"); @@ -2321,13 +2524,17 @@ void readloop(char *oper) maxmsgs = 9999999; } - if (is_summary) { /**< fetch header summary */ - snprintf(cmd, sizeof cmd, "MSGS %s|%s||1", + if (is_summary || WCC->is_mobile) { /**< fetch header summary */ + snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1", (!strcmp(oper, "do_search") ? "SEARCH" : "ALL"), (!strcmp(oper, "do_search") ? bstr("query") : "") ); startmsg = 1; maxmsgs = 9999999; + } + if (WCC->is_mobile) { + maxmsgs = 20; + SortBy = eRDate; } /** @@ -2336,7 +2543,7 @@ void readloop(char *oper) * new messages. */ strcpy(old_msgs, ""); - if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR)){ + if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){ serv_puts("GTSN"); serv_getln(buf, sizeof buf); if (buf[0] == '2') { @@ -2344,7 +2551,7 @@ void readloop(char *oper) } } - is_singlecard = atoi(bstr("is_singlecard")); + is_singlecard = ibstr("is_singlecard"); if (WCC->wc_default_view == VIEW_CALENDAR) { /**< calendar */ is_calendar = 1; @@ -2363,11 +2570,10 @@ void readloop(char *oper) } 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)) { @@ -2385,7 +2591,7 @@ void readloop(char *oper) goto DONE; } - if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR)){ + if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){ for (a = 0; a < nummsgs; ++a) { /** Are you a new message, or an old message? */ if (is_summary) { @@ -2408,62 +2614,11 @@ void readloop(char *oper) } } - if (is_summary) { - if (!strcasecmp(sortby, "subject")) { - qsort(WCC->summ, WCC->num_summ, - sizeof(struct message_summary), summcmp_subj); - } - else if (!strcasecmp(sortby, "rsubject")) { - qsort(WCC->summ, WCC->num_summ, - sizeof(struct message_summary), summcmp_rsubj); - } - else if (!strcasecmp(sortby, "sender")) { - qsort(WCC->summ, WCC->num_summ, - sizeof(struct message_summary), summcmp_sender); - } - else if (!strcasecmp(sortby, "rsender")) { - qsort(WCC->summ, WCC->num_summ, - sizeof(struct message_summary), summcmp_rsender); - } - else if (!strcasecmp(sortby, "date")) { - qsort(WCC->summ, WCC->num_summ, - sizeof(struct message_summary), summcmp_date); - } - else if (!strcasecmp(sortby, "rdate")) { - qsort(WCC->summ, WCC->num_summ, - sizeof(struct message_summary), summcmp_rdate); - } - } - - if (!strcasecmp(sortby, "subject")) { - subjsort_button = "" ; - } - else if (!strcasecmp(sortby, "rsubject")) { - subjsort_button = "" ; - } - else { - subjsort_button = "" ; + if (is_summary || WCC->is_mobile) { + qsort(WCC->summ, WCC->num_summ, + sizeof(struct message_summary), SortFuncs[SortBy]); } - 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) { @@ -2481,9 +2636,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("
"); } @@ -2527,7 +2688,7 @@ void readloop(char *oper) if (is_bbview) { /** begin bbview scroller */ wprintf("
\n

"); - wprintf(_("Reading #"), lowest_displayed, highest_displayed); + wprintf(_("Reading #"));//// TODO this isn't used, should it? : , lowest_displayed, highest_displayed); 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("
" @@ -2682,6 +2837,8 @@ void readloop(char *oper) ); wprintf("
"); /**< The preview pane will initially be empty */ + } else if (WCC->is_mobile) { + wprintf("
"); } /** @@ -2698,7 +2855,7 @@ void readloop(char *oper) if (is_bbview) { /** begin bbview scroller */ wprintf(" \n

"); - wprintf(_("Reading #"), lowest_displayed, highest_displayed); + wprintf(_("Reading #")); /// TODO: this isn't used: , lowest_displayed, highest_displayed); 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); + escputs(WCC->wc_roomname); + wprintf("\">\n"); + wprintf("\n"); /** submit or cancel buttons */ @@ -3256,9 +3461,9 @@ void display_enter(void) } } - if (WC->room_flags & QR_ANONOPT) { + if (WCC->room_flags & QR_ANONOPT) { wprintf("\n", - ((!strcasecmp(bstr("__ANONYMOUS__"), WC->wc_fullname)) ? "selected" : ""), + ((!strcasecmp(bstr("__ANONYMOUS__"), WCC->wc_fullname)) ? "selected" : ""), _("Anonymous") ); } @@ -3285,7 +3490,7 @@ void display_enter(void) } wprintf(_(" in ")); - escputs(WC->wc_roomname); + escputs(WCC->wc_roomname); wprintf(""); @@ -3297,8 +3502,7 @@ void display_enter(void) wprintf(_("To:")); wprintf("" "" "" " 0L) { + if (lbstr("fwdquote") > 0L) { wprintf("

"); wprintf(_("--- forwarded message ---")); wprintf("

"); - pullquote_message(atol(bstr("fwdquote")), 1, 1); + pullquote_message(lbstr("fwdquote"), 1, 1); } /** If we're replying quoted, insert the quote here... */ - else if (atol(bstr("replyquote")) > 0L) { + else if (lbstr("replyquote") > 0L) { wprintf("
" "
"); - pullquote_message(atol(bstr("replyquote")), 0, 1); + pullquote_message(lbstr("replyquote"), 0, 1); wprintf("

"); } /** If we're editing a wiki page, insert the existing page here... */ - else if (WC->wc_view == VIEW_WIKI) { + else if (WCC->wc_view == VIEW_WIKI) { safestrncpy(buf, bstr("wikipage"), sizeof buf); str_wiki_index(buf); existing_page = locate_message_by_uid(buf); @@ -3407,36 +3609,42 @@ void display_enter(void) } /** Insert our signature if appropriate... */ - if ( (WC->is_mailbox) && (strcmp(bstr("sig_inserted"), "yes")) ) { - get_preference("use_sig", buf, sizeof buf); - if (!strcasecmp(buf, "yes")) { - int len; - get_preference("signature", ebuf, sizeof ebuf); - euid_unescapize(buf, ebuf); + if ( (WCC->is_mailbox) && !yesbstr("sig_inserted") ) { + int UseSig; + get_pref_yesno("use_sig", &UseSig, 0); + if (UseSig) { + StrBuf *Sig; + const char *sig, *esig; + + get_preference("signature", &ebuf); + Sig = NewStrBuf(); + StrBufEUid_unescapize(Sig, ebuf); + sig = ChrPtr(Sig); + esig = sig + StrLength(Sig); wprintf("
--
"); - len = strlen(buf); - for (i=0; i"); } - else if (buf[i] == '<') { + else if (*sig == '<') { wprintf("<"); } - else if (buf[i] == '>') { + else if (*sig == '>') { wprintf(">"); } - else if (buf[i] == '&') { + else if (*sig == '&') { wprintf("&"); } - else if (buf[i] == '\"') { + else if (*sig == '\"') { wprintf("""); } - else if (buf[i] == '\'') { + else if (*sig == '\'') { wprintf("'"); } - else if (isprint(buf[i])) { - wprintf("%c", buf[i]); - } + else /* since we're utf 8, is this a good idea? if (isprint(*sig))*/ { + wprintf("%c", *sig); + } + sig ++; } } } @@ -3458,7 +3666,7 @@ void display_enter(void) wprintf(_("Attachments:")); wprintf(" "); wprintf("\n", WC->nonce); + wprintf("\n", WC->nonce); wprintf("\n", bstr("msgid")); wprintf("