+ if (outlen > 0) {
+ client_write(outbuf, outlen);
+ }
+}
+
+
+
+/* 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.
+ */
+void DumpFormatFixed(
+ struct CtdlMessage *TheMessage,
+ int mode, /* how would you like that message? */
+ const char *nl)
+{
+ cit_uint8_t ch;
+ char buf[SIZ];
+ int buflen;
+ int xlline = 0;
+ int nllen = strlen (nl);
+ char *mptr;
+
+ mptr = TheMessage->cm_fields['M'];
+
+ 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';
+
+ if (client_write(buf, buflen) == -1)
+ {
+ struct CitContext *CCC = CC;
+ MSGM_syslog(LOG_ERR, "DumpFormatFixed(): aborting due to write failure.\n");
+ return;
+ }
+ *buf = '\0';
+ buflen = 0;
+ xlline = 0;
+ } else {
+ buf[buflen] = ch;
+ buflen++;
+ }
+ }
+ buf[buflen] = '\0';
+ if (!IsEmptyStr(buf))
+ cprintf("%s%s", buf, nl);
+}
+
+/*
+ * Get a message off disk. (returns om_* values found in msgbase.h)
+ */
+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? */
+) {
+ struct CitContext *CCC = CC;
+ int i;
+ char *mptr = NULL;
+ const char *nl; /* newline string */
+ 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];
+
+ MSG_syslog(LOG_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)) {
+ MSGM_syslog(LOG_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 (CCC->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 (CCC->download_fp == NULL) {
+ if (do_proto) cprintf(
+ "%d Section %s not found.\n",
+ ERROR + FILE_NOT_FOUND,
+ CCC->download_desired_section);
+ }
+ }
+ return((CCC->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,
+ CCC->download_desired_section);
+ }
+ }
+ return((CCC->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");
+ }
+
+ if ((mode == MT_CITADEL) || (mode == MT_MIME))
+ OutputCtdlMsgHeaders(TheMessage, do_proto);
+
+
+ /* begin header processing loop for RFC822 transfer format */
+ strcpy(suser, "");
+ strcpy(luser, "");
+ strcpy(fuser, "");
+ strcpy(snode, NODENAME);
+ if (mode == MT_RFC822)
+ OutputRFC822MsgHeaders(
+ TheMessage,
+ flags,
+ nl,
+ mid, sizeof(mid),
+ suser, sizeof(suser),
+ luser, sizeof(luser),
+ fuser, sizeof(fuser),
+ snode, sizeof(snode)
+ );
+