* msgbase.c now contains both the new and old versions of CtdlOutputPreLoadedMsg...
authorArt Cancro <ajc@citadel.org>
Sun, 7 Mar 2010 00:19:01 +0000 (00:19 +0000)
committerArt Cancro <ajc@citadel.org>
Sun, 7 Mar 2010 00:19:01 +0000 (00:19 +0000)
citadel/msgbase.c

index 70b368f29025ef059406699387fd5536ef69ec96..35bd0b933f35fc0198cd819ecd8767b09b12fc67 100644 (file)
@@ -1711,6 +1711,8 @@ void sanitize_truncated_recipient(char *str)
 
 
 
+#ifdef NEW_COPLM
+
 /*
  * Get a message off disk.  (returns om_* values found in msgbase.h)
  */
@@ -2228,6 +2230,516 @@ DONE:   /* now we're done */
 }
 
 
+#else  /* NEW_COPLM */
+
+/*
+ * Get a message off disk.  (returns om_* values found in msgbase.h)
+ * THIS IS FROM r8422 AND WILL BE ELIMINATED ONCE THE NEW VERSION IS DEBUGGED
+ */
+int CtdlOutputPreLoadedMsg(
+               struct CtdlMessage *TheMessage,
+               int mode,               /* how would you like that message? */
+               int headers_only,       /* eschew the message body? */
+               int do_proto,           /* do Citadel protocol responses? */
+               int crlf,               /* Use CRLF newlines instead of LF? */
+               int flags               /* should the bessage be exported clean? */
+) {
+       int i, j, k;
+       char buf[SIZ];
+       cit_uint8_t ch, prev_ch;
+       char allkeys[30];
+       char display_name[256];
+       char *mptr, *mpptr;
+       const char *nl; /* newline string */
+       int suppress_f = 0;
+       int subject_found = 0;
+       struct ma_info ma;
+
+       /* Buffers needed for RFC822 translation.  These are all filled
+        * using functions that are bounds-checked, and therefore we can
+        * make them substantially smaller than SIZ.
+        */
+       char suser[100];
+       char luser[100];
+       char fuser[100];
+       char snode[100];
+       char mid[100];
+       char datestamp[100];
+
+       CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d\n",
+               ((TheMessage == NULL) ? "NULL" : "not null"),
+               mode, headers_only, do_proto, crlf);
+
+       strcpy(mid, "unknown");
+       nl = (crlf ? "\r\n" : "\n");
+
+       if (!is_valid_message(TheMessage)) {
+               CtdlLogPrintf(CTDL_ERR,
+                       "ERROR: invalid preloaded message for output\n");
+               cit_backtrace ();
+               return(om_no_such_msg);
+       }
+
+       /* Suppress envelope recipients if required to avoid disclosing BCC addresses.
+        * Pad it with spaces in order to avoid changing the RFC822 length of the message.
+        */
+       if ( (flags & SUPPRESS_ENV_TO) && (TheMessage->cm_fields['V'] != NULL) ) {
+               memset(TheMessage->cm_fields['V'], ' ', strlen(TheMessage->cm_fields['V']));
+       }
+               
+       /* Are we downloading a MIME component? */
+       if (mode == MT_DOWNLOAD) {
+               if (TheMessage->cm_format_type != FMT_RFC822) {
+                       if (do_proto)
+                               cprintf("%d This is not a MIME message.\n",
+                               ERROR + ILLEGAL_VALUE);
+               } else if (CC->download_fp != NULL) {
+                       if (do_proto) cprintf(
+                               "%d You already have a download open.\n",
+                               ERROR + RESOURCE_BUSY);
+               } else {
+                       /* Parse the message text component */
+                       mptr = TheMessage->cm_fields['M'];
+                       mime_parser(mptr, NULL, *mime_download, NULL, NULL, NULL, 0);
+                       /* If there's no file open by this time, the requested
+                        * section wasn't found, so print an error
+                        */
+                       if (CC->download_fp == NULL) {
+                               if (do_proto) cprintf(
+                                       "%d Section %s not found.\n",
+                                       ERROR + FILE_NOT_FOUND,
+                                       CC->download_desired_section);
+                       }
+               }
+               return((CC->download_fp != NULL) ? om_ok : om_mime_error);
+       }
+
+       /* MT_SPEW_SECTION is like MT_DOWNLOAD except it outputs the whole MIME part
+        * in a single server operation instead of opening a download file.
+        */
+       if (mode == MT_SPEW_SECTION) {
+               if (TheMessage->cm_format_type != FMT_RFC822) {
+                       if (do_proto)
+                               cprintf("%d This is not a MIME message.\n",
+                               ERROR + ILLEGAL_VALUE);
+               } else {
+                       /* Parse the message text component */
+                       int found_it = 0;
+
+                       mptr = TheMessage->cm_fields['M'];
+                       mime_parser(mptr, NULL, *mime_spew_section, NULL, NULL, (void *)&found_it, 0);
+                       /* If section wasn't found, print an error
+                        */
+                       if (!found_it) {
+                               if (do_proto) cprintf(
+                                       "%d Section %s not found.\n",
+                                       ERROR + FILE_NOT_FOUND,
+                                       CC->download_desired_section);
+                       }
+               }
+               return((CC->download_fp != NULL) ? om_ok : om_mime_error);
+       }
+
+       /* now for the user-mode message reading loops */
+       if (do_proto) cprintf("%d msg:\n", LISTING_FOLLOWS);
+
+       /* Does the caller want to skip the headers? */
+       if (headers_only == HEADERS_NONE) goto START_TEXT;
+
+       /* Tell the client which format type we're using. */
+       if ( (mode == MT_CITADEL) && (do_proto) ) {
+               cprintf("type=%d\n", TheMessage->cm_format_type);
+       }
+
+       /* nhdr=yes means that we're only displaying headers, no body */
+       if ( (TheMessage->cm_anon_type == MES_ANONONLY)
+          && ((mode == MT_CITADEL) || (mode == MT_MIME))
+          && (do_proto)
+          ) {
+               cprintf("nhdr=yes\n");
+       }
+
+       /* begin header processing loop for Citadel message format */
+
+       if ((mode == MT_CITADEL) || (mode == MT_MIME)) {
+
+               safestrncpy(display_name, "<unknown>", sizeof display_name);
+               if (TheMessage->cm_fields['A']) {
+                       strcpy(buf, TheMessage->cm_fields['A']);
+                       if (TheMessage->cm_anon_type == MES_ANONONLY) {
+                               safestrncpy(display_name, "****", sizeof display_name);
+                       }
+                       else if (TheMessage->cm_anon_type == MES_ANONOPT) {
+                               safestrncpy(display_name, "anonymous", sizeof display_name);
+                       }
+                       else {
+                               safestrncpy(display_name, buf, sizeof display_name);
+                       }
+                       if ((is_room_aide())
+                           && ((TheMessage->cm_anon_type == MES_ANONONLY)
+                            || (TheMessage->cm_anon_type == MES_ANONOPT))) {
+                               size_t tmp = strlen(display_name);
+                               snprintf(&display_name[tmp],
+                                        sizeof display_name - tmp,
+                                        " [%s]", buf);
+                       }
+               }
+
+               /* Don't show Internet address for users on the
+                * local Citadel network.
+                */
+               suppress_f = 0;
+               if (TheMessage->cm_fields['N'] != NULL)
+                  if (!IsEmptyStr(TheMessage->cm_fields['N']))
+                     if (haschar(TheMessage->cm_fields['N'], '.') == 0) {
+                       suppress_f = 1;
+               }
+
+               /* Now spew the header fields in the order we like them. */
+               safestrncpy(allkeys, FORDER, sizeof allkeys);
+               for (i=0; i<strlen(allkeys); ++i) {
+                       k = (int) allkeys[i];
+                       if (k != 'M') {
+                               if ( (TheMessage->cm_fields[k] != NULL)
+                                  && (msgkeys[k] != NULL) ) {
+                                       if ((k == 'V') || (k == 'R') || (k == 'Y')) {
+                                               sanitize_truncated_recipient(TheMessage->cm_fields[k]);
+                                       }
+                                       if (k == 'A') {
+                                               if (do_proto) cprintf("%s=%s\n",
+                                                       msgkeys[k],
+                                                       display_name);
+                                       }
+                                       else if ((k == 'F') && (suppress_f)) {
+                                               /* do nothing */
+                                       }
+                                       /* Masquerade display name if needed */
+                                       else {
+                                               if (do_proto) cprintf("%s=%s\n",
+                                                       msgkeys[k],
+                                                       TheMessage->cm_fields[k]
+                                       );
+                                       }
+                               }
+                       }
+               }
+
+       }
+
+       /* begin header processing loop for RFC822 transfer format */
+
+       strcpy(suser, "");
+       strcpy(luser, "");
+       strcpy(fuser, "");
+       strcpy(snode, NODENAME);
+       if (mode == MT_RFC822) {
+               for (i = 0; i < 256; ++i) {
+                       if (TheMessage->cm_fields[i]) {
+                               mptr = mpptr = TheMessage->cm_fields[i];
+                               
+                               if (i == 'A') {
+                                       safestrncpy(luser, mptr, sizeof luser);
+                                       safestrncpy(suser, mptr, sizeof suser);
+                               }
+                               else if (i == 'Y') {
+                                       if ((flags & QP_EADDR) != 0) {
+                                               mptr = qp_encode_email_addrs(mptr);
+                                       }
+                                       sanitize_truncated_recipient(mptr);
+                                       cprintf("CC: %s%s", mptr, nl);
+                               }
+                               else if (i == 'P') {
+                                       cprintf("Return-Path: %s%s", mptr, nl);
+                               }
+                               else if (i == 'L') {
+                                       cprintf("List-ID: %s%s", mptr, nl);
+                               }
+                               else if (i == 'V') {
+                                       if ((flags & QP_EADDR) != 0) 
+                                               mptr = qp_encode_email_addrs(mptr);
+                                       cprintf("Envelope-To: %s%s", mptr, nl);
+                               }
+                               else if (i == 'U') {
+                                       cprintf("Subject: %s%s", mptr, nl);
+                                       subject_found = 1;
+                               }
+                               else if (i == 'I')
+                                       safestrncpy(mid, mptr, sizeof mid);
+                               else if (i == 'F')
+                                       safestrncpy(fuser, mptr, sizeof fuser);
+                               /* else if (i == 'O')
+                                       cprintf("X-Citadel-Room: %s%s",
+                                               mptr, nl); */
+                               else if (i == 'N')
+                                       safestrncpy(snode, mptr, sizeof snode);
+                               else if (i == 'R')
+                               {
+                                       if (haschar(mptr, '@') == 0)
+                                       {
+                                               sanitize_truncated_recipient(mptr);
+                                               cprintf("To: %s@%s", mptr, config.c_fqdn);
+                                               cprintf("%s", nl);
+                                       }
+                                       else
+                                       {
+                                               if ((flags & QP_EADDR) != 0) {
+                                                       mptr = qp_encode_email_addrs(mptr);
+                                               }
+                                               sanitize_truncated_recipient(mptr);
+                                               cprintf("To: %s", mptr);
+                                               cprintf("%s", nl);
+                                       }
+                               }
+                               else if (i == 'T') {
+                                       datestring(datestamp, sizeof datestamp,
+                                               atol(mptr), DATESTRING_RFC822);
+                                       cprintf("Date: %s%s", datestamp, nl);
+                               }
+                               else if (i == 'W') {
+                                       cprintf("References: ");
+                                       k = num_tokens(mptr, '|');
+                                       for (j=0; j<k; ++j) {
+                                               extract_token(buf, mptr, j, '|', sizeof buf);
+                                               cprintf("<%s>", buf);
+                                               if (j == (k-1)) {
+                                                       cprintf("%s", nl);
+                                               }
+                                               else {
+                                                       cprintf(" ");
+                                               }
+                                       }
+                               }
+                               if (mptr != mpptr)
+                                       free (mptr);
+                       }
+               }
+               if (subject_found == 0) {
+                       cprintf("Subject: (no subject)%s", nl);
+               }
+       }
+
+       for (i=0; !IsEmptyStr(&suser[i]); ++i) {
+               suser[i] = tolower(suser[i]);
+               if (!isalnum(suser[i])) suser[i]='_';
+       }
+
+       if (mode == MT_RFC822) {
+               if (!strcasecmp(snode, NODENAME)) {
+                       safestrncpy(snode, FQDN, sizeof snode);
+               }
+
+               /* Construct a fun message id */
+               cprintf("Message-ID: <%s", mid);/// todo: this possibly breaks threadding mails.
+               if (strchr(mid, '@')==NULL) {
+                       cprintf("@%s", snode);
+               }
+               cprintf(">%s", nl);
+
+               if (!is_room_aide() && (TheMessage->cm_anon_type == MES_ANONONLY)) {
+                       cprintf("From: \"----\" <x@x.org>%s", nl);
+               }
+               else if (!is_room_aide() && (TheMessage->cm_anon_type == MES_ANONOPT)) {
+                       cprintf("From: \"anonymous\" <x@x.org>%s", nl);
+               }
+               else if (!IsEmptyStr(fuser)) {
+                       cprintf("From: \"%s\" <%s>%s", luser, fuser, nl);
+               }
+               else {
+                       cprintf("From: \"%s\" <%s@%s>%s", luser, suser, snode, nl);
+               }
+
+               /* Blank line signifying RFC822 end-of-headers */
+               if (TheMessage->cm_format_type != FMT_RFC822) {
+                       cprintf("%s", nl);
+               }
+       }
+
+       /* end header processing loop ... at this point, we're in the text */
+START_TEXT:
+       if (headers_only == HEADERS_FAST) goto DONE;
+       mptr = TheMessage->cm_fields['M'];
+
+       /* Tell the client about the MIME parts in this message */
+       if (TheMessage->cm_format_type == FMT_RFC822) {
+               if ( (mode == MT_CITADEL) || (mode == MT_MIME) ) {
+                       memset(&ma, 0, sizeof(struct ma_info));
+                       mime_parser(mptr, NULL,
+                               (do_proto ? *list_this_part : NULL),
+                               (do_proto ? *list_this_pref : NULL),
+                               (do_proto ? *list_this_suff : NULL),
+                               (void *)&ma, 0);
+               }
+               else if (mode == MT_RFC822) {   /* unparsed RFC822 dump */
+                       char *start_of_text = NULL;
+                       start_of_text = strstr(mptr, "\n\r\n");
+                       if (start_of_text == NULL) start_of_text = strstr(mptr, "\n\n");
+                       if (start_of_text == NULL) start_of_text = mptr;
+                       ++start_of_text;
+                       start_of_text = strstr(start_of_text, "\n");
+                       ++start_of_text;
+
+                       char outbuf[1024];
+                       int outlen = 0;
+                       int nllen = strlen(nl);
+                       prev_ch = 0;
+                       while (ch=*mptr, ch!=0) {
+                               if (ch==13) {
+                                       /* do nothing */
+                               }
+                               else {
+                                       if (
+                                               ((headers_only == HEADERS_NONE) && (mptr >= start_of_text))
+                                          ||   ((headers_only == HEADERS_ONLY) && (mptr < start_of_text))
+                                          ||   ((headers_only != HEADERS_NONE) && (headers_only != HEADERS_ONLY))
+                                       ) {
+                                               if (ch == 10) {
+                                                       sprintf(&outbuf[outlen], "%s", nl);
+                                                       outlen += nllen;
+                                               }
+                                               else {
+                                                       outbuf[outlen++] = ch;
+                                               }
+                                       }
+                               }
+                               if (flags & ESC_DOT)
+                               {
+                                       if ((prev_ch == 10) && (ch == '.') && ((*(mptr+1) == 13) || (*(mptr+1) == 10)))
+                                       {
+                                               outbuf[outlen++] = '.';
+                                       }
+                               }
+                               prev_ch = ch;
+                               ++mptr;
+                               if (outlen > 1000) {
+                                       client_write(outbuf, outlen);
+                                       outlen = 0;
+                               }
+                       }
+                       if (outlen > 0) {
+                               client_write(outbuf, outlen);
+                               outlen = 0;
+                       }
+
+                       goto DONE;
+               }
+       }
+
+       if (headers_only == HEADERS_ONLY) {
+               goto DONE;
+       }
+
+       /* signify start of msg text */
+       if ( (mode == MT_CITADEL) || (mode == MT_MIME) ) {
+               if (do_proto) cprintf("text\n");
+       }
+
+       /* If the format type on disk is 1 (fixed-format), then we want
+        * everything to be output completely literally ... regardless of
+        * what message transfer format is in use.
+        */
+       if (TheMessage->cm_format_type == FMT_FIXED) {
+               int buflen;
+               int xlline = 0;
+               int nllen = strlen (nl);
+               if (mode == MT_MIME) {
+                       cprintf("Content-type: text/plain\n\n");
+               }
+               *buf = '\0';
+               buflen = 0;
+               while (ch = *mptr++, ch > 0) {
+                       if (ch == '\n')
+                               ch = '\r';
+
+                       if ((buflen > 250) && (!xlline)){
+                               int tbuflen;
+                               tbuflen = buflen;
+
+                               while ((buflen > 0) && 
+                                      (!isspace(buf[buflen])))
+                                       buflen --;
+                               if (buflen == 0) {
+                                       xlline = 1;
+                               }
+                               else {
+                                       mptr -= tbuflen - buflen;
+                                       buf[buflen] = '\0';
+                                       ch = '\r';
+                               }
+                       }
+                       /* if we reach the outer bounds of our buffer, 
+                          abort without respect what whe purge. */
+                       if (xlline && 
+                           ((isspace(ch)) || 
+                            (buflen > SIZ - nllen - 2)))
+                               ch = '\r';
+
+                       if (ch == '\r') {
+                               memcpy (&buf[buflen], nl, nllen);
+                               buflen += nllen;
+                               buf[buflen] = '\0';
+
+                               client_write(buf, buflen);
+                               *buf = '\0';
+                               buflen = 0;
+                               xlline = 0;
+                       } else {
+                               buf[buflen] = ch;
+                               buflen++;
+                       }
+               }
+               buf[buflen] = '\0';
+               if (!IsEmptyStr(buf))
+                       cprintf("%s%s", buf, nl);
+       }
+
+       /* If the message on disk is format 0 (Citadel vari-format), we
+        * output using the formatter at 80 columns.  This is the final output
+        * form if the transfer format is RFC822, but if the transfer format
+        * is Citadel proprietary, it'll still work, because the indentation
+        * for new paragraphs is correct and the client will reformat the
+        * message to the reader's screen width.
+        */
+       if (TheMessage->cm_format_type == FMT_CITADEL) {
+               if (mode == MT_MIME) {
+                       cprintf("Content-type: text/x-citadel-variformat\n\n");
+               }
+               memfmout(mptr, nl);
+       }
+
+       /* If the message on disk is format 4 (MIME), we've gotta hand it
+        * off to the MIME parser.  The client has already been told that
+        * this message is format 1 (fixed format), so the callback function
+        * we use will display those parts as-is.
+        */
+       if (TheMessage->cm_format_type == FMT_RFC822) {
+               memset(&ma, 0, sizeof(struct ma_info));
+
+               if (mode == MT_MIME) {
+                       ma.use_fo_hooks = 0;
+                       strcpy(ma.chosen_part, "1");
+                       ma.chosen_pref = 9999;
+                       mime_parser(mptr, NULL,
+                               *choose_preferred, *fixed_output_pre,
+                               *fixed_output_post, (void *)&ma, 0);
+                       mime_parser(mptr, NULL,
+                               *output_preferred, NULL, NULL, (void *)&ma, CC->msg4_dont_decode);
+               }
+               else {
+                       ma.use_fo_hooks = 1;
+                       mime_parser(mptr, NULL,
+                               *fixed_output, *fixed_output_pre,
+                               *fixed_output_post, (void *)&ma, 0);
+               }
+
+       }
+
+DONE:  /* now we're done */
+       if (do_proto) cprintf("000\n");
+       return(om_ok);
+}
+
+#endif /* NEW_COPLM */
+
 
 /*
  * display a message (mode 0 - Citadel proprietary)