static char rcsid[] = "@(#)$Id: fileio.c,v 1.65 2006/10/30 18:01:09 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.65 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
******************************************************************************
* The Elm Mail System
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*****************************************************************************/
/** File I/O routines, including deletion from the folder!
**/
#include "def_elm.h"
#include "s_elm.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"mbox");
DEBUG_VAR(PgpDebug,__FILE__,"pgp");
DEBUG_VAR(MimeDebug,__FILE__,"mime");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
#ifdef USE_PGP
/* Prototype */
static int copy_pgp P_((char *,out_state_t *,int, struct header_rec *,
FILE *));
static int copy_pgp(prefix,dest_file,cm_options,current_header, infile)
char *prefix;
out_state_t *dest_file;
int cm_options;
struct header_rec *current_header;
FILE * infile;
{
int body_bytes = 0;
FILE *fpin = NULL, *fpout = NULL;
char buffer[VERY_LONG_STRING];
int buf_len=0,err,code = -1;
struct run_state RS;
int stat;
int pgp_seen = !pgp_noarmor && current_header->pgp != PGP_PUBLIC_KEY;
enum pgp_version v = pgp2;
enum pgp_version version;
int armor_header = 0;
int ret = 1;
int raw = sr_call_RawState ();
DPRINT(PgpDebug,5,(&PgpDebug,
"copy_pgp called: Need read %d bytes\n",
current_header->content_length));
if (current_header->pgp & PGP_PUBLIC_KEY) {
state_printf(dest_file,CATGETS(elm_msg_cat, MeSet, MePgpPublicKeys,
"(** This message contains PGP public key(s) **)\n"));
state_nlputs("\n",dest_file);
}
/* default-nomime-charset gives assumed charset */
if (current_header->override_charset) {
dest_file -> filter = current_header->override_charset;
DPRINT(PgpDebug,5,(&PgpDebug,
"Override charset %s given\n",
current_header->override_charset->MIME_name ?
current_header->override_charset->MIME_name :
"<none>"));
} else
dest_file -> filter = default_nomime_charset;
if(pgp_seen) {
buf_len = mail_gets(buffer, VERY_LONG_STRING, infile);
} else {
while (body_bytes < current_header->content_length) {
if (! (buf_len = mail_gets(buffer, sizeof buffer, infile)))
break;
if (strncmp(buffer, "-----BEGIN PGP", 14) == 0) {
pgp_seen = 1;
break;
}
/* text before PGP section */
if (0 == body_bytes)
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MePgpBefore,
"[ There is text before PGP section. ]\n"));
body_bytes += buf_len;
/* Take care of CRLF => LF conversion or
LF -> CRLF conversion
*/
state_convert_EOLN(buffer,&buf_len,sizeof buffer,dest_file);
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_put(buffer, buf_len, dest_file);
if (err != buf_len) {
DPRINT(PgpDebug,1,(&PgpDebug,
"copy_pgp fails (err=%d != %d=buf_len)\n",
err,buf_len));
goto fail;
}
}
}
dest_file -> filter = NULL;
if (buf_len <= 0 || body_bytes >= current_header->content_length) {
return 1;
} else {
int l = ftell(infile);
int len1;
char buf[STRING];
/*
* On PGP 2 messages these is empty line immediately after
* -----BEGIN PGP SIGNED MESSAGE----
*
* If there is something other such as
* Hash: SHA1
* PGP 2 does not understand message.
*/
while (0 < (len1 =
mail_gets (buf, sizeof (buf), infile))) {
if ((len1 == 1 && buf[0] == '\n') ||
(len1 == 2 && buf[0] == '\r' && buf[1] == '\n'))
break;
if (current_header->pgp == PGP_SIGNED_MESSAGE) {
DPRINT(PgpDebug,4,(&PgpDebug,
"copy_pgp: peek: Header on armor -- requires PGP 5 or GnuPG\n" ));
v = gpg;
armor_header++;
break;
}
if (0 == strncmp("Version: ",buf,9)) {
char *c = buf+9;
v = decode_pgp_version(c);
if (armor_header && pgp2 == v)
v = gpg;
}
}
/* Look also for -----BEGIN PGP SIGNATURE----- ... */
if (current_header->pgp == PGP_SIGNED_MESSAGE && len1 > 0) {
DPRINT(PgpDebug,4,(&PgpDebug,
"copy_pgp: Looking for -----BEGIN PGP SIGNATURE\n"));
while ((len1 = mail_gets (buf, sizeof (buf), infile)) > 0) {
if (len1 > 24 &&
0 == strncmp(buf,
"-----BEGIN PGP SIGNATURE",24))
break;
}
while ((len1 = mail_gets (buf, sizeof (buf), infile)) > 0) {
if ((len1 == 1 && buf[0] == '\n') ||
(len1 == 2 && buf[0] == '\r' && buf[1] == '\n'))
break;
if (0 == strncmp("Version: ",buf,9)) {
char *c = buf+9;
v = decode_pgp_version(c);
if (armor_header && pgp2 == v)
v = gpg;
}
}
}
fseek(infile,l,SEEK_SET);
}
version = have_pgp(v);
if (!version) {
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MePgpNotAvailRawdata,
"[ PGP not available, raw data follows ]\n"));
goto raw;
}
if ((current_header->pgp & PGP_MESSAGE) && pgp_keeppass) {
if (!pgp_goodPassphrase(version)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmDecryptBadPGP,
"Decrypting message... Bad PGP passphrase."));
state_puts("[ ",dest_file);
state_printf(dest_file,CATGETS(elm_msg_cat, ElmSet,
ElmDecryptBadPGP,
"Decrypting message... Bad PGP passphrase."));
state_nlputs(" ]\n",dest_file);
return 1;
}
}
if (!(code=pgp_decrypt_init(&fpin, &fpout, current_header->pgp,
version,&RS))) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmDecryptFailInitPGP,
"Decrypting message... Failed to init PGP."));
state_printf(dest_file,
CATGETS(elm_msg_cat, ElmSet, ElmDecryptFailInitPGPRaw,
"[ Decrypting message... Failed to init PGP. Raw data follows. ]\n"));
raw:
while (body_bytes < current_header->content_length) {
body_bytes += buf_len;
/* Take care of CRLF => LF conversion or
LF -> CRLF conversion
*/
state_convert_EOLN(buffer,&buf_len,sizeof buffer,dest_file);
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_put(buffer, buf_len, dest_file);
if (err != buf_len) {
DPRINT(PgpDebug,4,(&PgpDebug,
"copy_pgp fails (err=%d != %d=buf_len)\n",
err,buf_len));
goto fail;
}
if (! (buf_len = mail_gets(buffer, VERY_LONG_STRING, infile)))
break;
}
state_printf(dest_file,
CATGETS(elm_msg_cat, ElmSet, ElmDecryptEndRaw,
"[ Decrypting message... End of raw data. ]\n"));
return 1;
}
/* Pass PGP section to pgp */
while (body_bytes < current_header->content_length) {
if (EOF == fputs(buffer, fpout)) {
DPRINT(PgpDebug,4,(&PgpDebug,
"copy_pgp fails\n"));
goto fail;
}
body_bytes += buf_len;
if (! (buf_len = mail_gets(buffer, VERY_LONG_STRING, infile)))
break;
}
if (fclose(fpout) == EOF) {
fpout = NULL;
DPRINT(PgpDebug,1,(&PgpDebug,
"copy_pgp fails\n"));
goto fail;
}
fpout = NULL;
DPRINT(PgpDebug,5,(&PgpDebug,
"copy_pgp: Passed %d bytes to PGP.\n",
body_bytes));
if (body_bytes != current_header->content_length) {
DPRINT(PgpDebug,1,(&PgpDebug,
"copy_pgp: ERROR: read bytes %d != content-length %d\n",
body_bytes,current_header->content_length));
ret = 0;
}
body_bytes = 0;
if (current_header->pgp & PGP_MESSAGE)
state_printf(dest_file,CATGETS(elm_msg_cat, MeSet, MePgpStartEncoded,
"-- Start of PGP encoded section.\n"));
else if (current_header->pgp & PGP_SIGNED_MESSAGE)
state_printf(dest_file,CATGETS(elm_msg_cat, MeSet, MePgpStartSigned,
"-- Start of PGP signed section.\n"));
else if (current_header->pgp & PGP_PUBLIC_KEY)
state_printf(dest_file,CATGETS(elm_msg_cat, MeSet, MePgpStartOutput,
"-- Start of PGP output.\n"));
else
state_printf(dest_file,CATGETS(elm_msg_cat, MeSet, MePgpStart,
"-- Start of PGP section.\n"));
retry:
while (0 < (buf_len = mail_gets(buffer, VERY_LONG_STRING, fpin))) {
body_bytes += buf_len;
/* Take care of CRLF => LF conversion or
LF -> CRLF conversion
*/
state_convert_EOLN(buffer,&buf_len,sizeof buffer,dest_file);
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_put(buffer, buf_len, dest_file);
if (err != buf_len) {
DPRINT(PgpDebug,1,(&PgpDebug,
"copy_pgp fails (err=%d != %d=buf_len)\n",
err,buf_len));
goto fail;
}
}
if (ferror(fpin) && EINTR == errno) {
clearerr(fpin);
DPRINT(PgpDebug,5,(&PgpDebug,
"Reading of result interrupted (EINTR) -- retrying\n"));
if (0 == code) {
code = run_already_done(&RS,&stat);
if (0 != code) {
DPRINT(PgpDebug,5,(&PgpDebug,
"now pgp/gpg is completing\n"));
}
}
goto retry;
}
fclose(fpin); fpin = NULL;
if (0 == code)
code = wait_end(&RS,&stat);
call_print_status_cooked(&RS,code < 0 ? -code : 0,stat);
if (raw)
sr_call_Raw (ON);
if (current_header->pgp & PGP_MESSAGE)
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MePgpEndEncoded,
"-- End of PGP encoded section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
else if (current_header->pgp & PGP_SIGNED_MESSAGE)
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MePgpEndSigned,
"-- End of PGP signed section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
else if (current_header->pgp & PGP_PUBLIC_KEY)
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MePgpEndOutput,
"-- End of PGP output%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
else
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MePgpEnd,
"-- End of PGP section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
DPRINT(PgpDebug,5,(&PgpDebug,
"copy_pgp=%d: Read %d bytes from PGP.\n",
ret,body_bytes));
return ret;
fail:
if (fpout)
fclose(fpout);
if (fpin)
fclose(fpin);
if (0 == code)
code = wait_end(&RS,&stat);
return 0;
}
#endif /* USE_PGP */
/* Prototype */
int copy_mime P_((char *,out_state_t *,int, struct header_rec *, FILE *));
int copy_mime(prefix,dest_file,cm_options,current_header, infile)
char *prefix;
out_state_t *dest_file;
int cm_options;
struct header_rec *current_header;
FILE *infile;
{
in_state_t state_in;
in_state_clear(&state_in, STATE_in_file);
DPRINT(MimeDebug,5,(&MimeDebug,
"copy_mime called: Need read %d bytes\n",
current_header->content_length));
if (!current_header->mime_parsed) {
DPRINT(MimeDebug,1,(&MimeDebug,"mime_parse_routine was not called\n"));
mime_parse_routine(NULL,current_header,infile);
}
set_in_state_file(infile,&state_in);
dest_file->prefix = prefix;
dest_file->displaying = (cm_options & CM_DISPLAYING) ? 1 : 0;
mime_decode(&(current_header->mime_rec), &state_in,
dest_file,current_header->header_charset,
current_header, mime_signature_mismatch);
DPRINT(MimeDebug,5,(&MimeDebug,
"copy_mime: mail decoded\n"));
in_state_destroy(&state_in);
dest_file->prefix = NULL;
return 1;
}
/* Prototype */
static int copy_encrypted P_((char *,out_state_t *,int, struct header_rec *,
FILE *));
static int copy_encrypted(prefix,dest_file,cm_options,current_header,infile)
char *prefix;
out_state_t *dest_file;
int cm_options;
struct header_rec *current_header;
FILE *infile;
{
char buffer[VERY_LONG_STRING];
long body_bytes = 0;
int crypted = OFF;
int buf_len;
int ok;
DPRINT(Debug,5,(&Debug,
"copy_encrypted called: Need read %d bytes\n",
current_header->content_length));
ok = getkey(OFF);
/* default-nomime-charset gives assumed charset */
if (current_header->override_charset) {
dest_file -> filter = current_header->override_charset;
DPRINT(Debug,5,(&Debug,
"Override charset %s given\n",
current_header->override_charset->MIME_name ?
current_header->override_charset->MIME_name :
"<none>"));
} else
dest_file -> filter = default_nomime_charset;
while (body_bytes < current_header->content_length) {
int err;
if (! (buf_len = mail_gets(buffer, sizeof buffer, infile)))
break;
if (body_bytes + buf_len >= current_header->content_length) {
DPRINT(Debug,5,(&Debug,
"copy_encrypted: Readed past of end of body\n"));
if (buf_len > 0 &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -1 == current_header->content_length) {
DPRINT(Debug,5,(&Debug,
" ... ignoring NL\n"));
buf_len -= 1;
} else if (buf_len > 1 &&
'\r' == buffer[buf_len-2] &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -2 ==
current_header->content_length
) {
DPRINT(Debug,5,(&Debug,
" ... ignoring CR NL\n"));
buf_len -= 2;
}
}
body_bytes += buf_len;
/* Take care of CRLF => LF conversion or
LF -> CRLF conversion
*/
state_convert_EOLN(buffer,&buf_len,sizeof buffer,dest_file);
if (ok > 0) {
if (mime_body_keywords && !strncmp(buffer, START_ENCODE, strlen(START_ENCODE))) {
crypted = ON;
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MeDecodeStartElmEncoded,
"-- Start of (Elm) encoded section.\n"));
continue;
} else if (mime_body_keywords && !strncmp(buffer, END_ENCODE, strlen(END_ENCODE))) {
crypted = OFF;
state_printf(dest_file,
CATGETS(elm_msg_cat, MeSet, MeDecodeEndElmEncoded,
"-- End of (Elm) encoded section.\n"));
continue;
} else if (crypted) {
no_ret(buffer);
encode(buffer);
if (dest_file->EOLN_is_CRLF)
strfcat(buffer, "\r\n", sizeof buffer);
else
strfcat(buffer, "\n", sizeof buffer);
}
}
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_puts(buffer,dest_file);
if (err == EOF) {
DPRINT(Debug,1,(&Debug,
"copy_encrypted fails\n"));
goto fail;
}
}
DPRINT(Debug,5,(&Debug,
"copy_encrypted: Read %d bytes from body\n",body_bytes));
if (body_bytes != current_header->content_length) {
DPRINT(Debug,1,(&Debug,
"copy_encrypted: ERROR: read bytes %d != content-length %d\n",
body_bytes,current_header->content_length));
return 0;
}
return 1;
fail:
return 0;
}
/* Prototype */
int copy_plain P_((char *,out_state_t *,int, struct header_rec *, FILE *));
int copy_plain(prefix,dest_file,cm_options,current_header, infile)
char *prefix;
out_state_t *dest_file;
int cm_options;
struct header_rec *current_header;
FILE *infile;
{
char buffer[VERY_LONG_STRING];
int body_bytes = 0;
int buf_len, err;
DPRINT(Debug,5, (&Debug,
"copy_plain called: Need read %d bytes\n",
current_header->content_length));;
/* default-nomime-charset gives assumed charset */
if (current_header->override_charset) {
dest_file -> filter = current_header->override_charset;
DPRINT(Debug,5,(&Debug,
"Override charset %s given\n",
current_header->override_charset->MIME_name ?
current_header->override_charset->MIME_name :
"<none>"));
} else
dest_file -> filter = default_nomime_charset;
while (body_bytes < current_header->content_length) {
if (! (buf_len = mail_gets(buffer, VERY_LONG_STRING, infile)))
break;
if (body_bytes + buf_len >= current_header->content_length) {
DPRINT(Debug,5,(&Debug,
"copy_plain: Readed past of end of body\n"));
if (buf_len > 0 &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -1 == current_header->content_length) {
DPRINT(Debug,5,(&Debug,
" ... ignoring NL\n"));
buf_len -= 1;
} else if (buf_len > 1 &&
'\r' == buffer[buf_len-2] &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -2 ==
current_header->content_length
) {
DPRINT(Debug,5,(&Debug,
" ... ignoring CR NL\n"));
buf_len -= 2;
}
}
body_bytes += buf_len;
/* Take care of CRLF => LF conversion or
LF -> CRLF conversion
*/
state_convert_EOLN(buffer,&buf_len,sizeof buffer,dest_file);
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_put(buffer, buf_len, dest_file);
if (err != buf_len) {
DPRINT(Debug,1,(&Debug,
"copy_plain fails (err=%d != %d=buf_len)\n",
err,buf_len));
goto fail;
}
}
DPRINT(Debug,5,(&Debug,
"copy_plain: Read %d bytes from body\n",
body_bytes));
if (body_bytes != current_header->content_length) {
DPRINT(Debug,1,(&Debug,
"copy_plain: ERROR: read bytes %d != content-length %d\n",
body_bytes,current_header->content_length));
return 0;
}
return 1;
fail:
return 0;
}
/* Prototype */
int copy_binary P_((char *,out_state_t *,int, struct header_rec *, FILE *));
int copy_binary(prefix,dest_file,cm_options,current_header, infile)
char *prefix;
out_state_t *dest_file;
int cm_options;
struct header_rec *current_header;
FILE *infile;
{
char buffer[VERY_LONG_STRING];
int body_bytes = 0;
int buf_len, err;
DPRINT(Debug,5, (&Debug,
"copy_binary called: Need read %d bytes\n",
current_header->content_length));;
/* No filtering or charset handling ... */
dest_file -> filter = NULL;
while (body_bytes < current_header->content_length) {
if (! (buf_len = mail_gets(buffer, VERY_LONG_STRING, infile)))
break;
if (body_bytes + buf_len >= current_header->content_length) {
DPRINT(Debug,5,(&Debug,
"copy_binary: Readed past of end of body\n"));
if (buf_len > 0 &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -1 == current_header->content_length) {
DPRINT(Debug,5,(&Debug,
" ... ignoring NL\n"));
buf_len -= 1;
} else if (buf_len > 1 &&
'\r' == buffer[buf_len-2] &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -2 ==
current_header->content_length
) {
DPRINT(Debug,5,(&Debug,
" ... ignoring CR NL\n"));
buf_len -= 2;
}
}
body_bytes += buf_len;
/* NO CONVERSIONS! */
DPRINT(Debug,15,(&Debug,
"copy_binary: -> %.*s",buf_len,buffer));
if (buf_len < 1 || buffer[buf_len-1] != '\n') {
DPRINT(Debug,15,(&Debug,
"\ncopy_binary <-- NO NEWLINE\n"));
}
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_put(buffer, buf_len, dest_file);
if (err != buf_len) {
DPRINT(Debug,1,(&Debug,
"copy_binary fails (err=%d != %d=buf_len)\n",
err,buf_len));
goto fail;
}
}
DPRINT(Debug,5,(&Debug,
"copy_binary: Read %d bytes from body\n",body_bytes));
if (body_bytes != current_header->content_length) {
DPRINT(Debug,1,(&Debug,
"copy_binary: ERROR: read bytes %d != content-length %d\n",
body_bytes,current_header->content_length));
return 0;
}
return 1;
fail:
return 0;
}
/* Prototype */
int copy_cooked P_((char *,out_state_t *,int, struct header_rec *, FILE *));
int copy_cooked(prefix,dest_file,cm_options,current_header, infile)
char *prefix;
out_state_t *dest_file;
int cm_options;
struct header_rec *current_header;
FILE *infile;
{
char buffer[VERY_LONG_STRING];
int body_bytes = 0;
int buf_len, err;
DPRINT(Debug,5, (&Debug,
"copy_cooked called: Need read %d bytes\n",
current_header->content_length));;
/* No filtering or charset handling ... */
dest_file -> filter = NULL;
while (body_bytes < current_header->content_length) {
if (! (buf_len = mail_gets(buffer, sizeof buffer, infile)))
break;
if (body_bytes + buf_len >= current_header->content_length) {
DPRINT(Debug,5,(&Debug,
"copy_cooked: Readed past of end of body\n"));
if (buf_len > 0 &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -1 == current_header->content_length) {
DPRINT(Debug,5,(&Debug,
" ... ignoring NL\n"));
buf_len -= 1;
} else if (buf_len > 1 &&
'\r' == buffer[buf_len-2] &&
'\n' == buffer[buf_len-1] &&
body_bytes + buf_len -2 ==
current_header->content_length
) {
DPRINT(Debug,5,(&Debug,
" ... ignoring CR NL\n"));
buf_len -= 2;
}
}
body_bytes += buf_len;
DPRINT(Debug,15,(&Debug,
"copy_cooked: -> %.*s",buf_len,buffer));
if (buf_len < 1 || buffer[buf_len-1] != '\n') {
DPRINT(Debug,15,(&Debug,
"\ncopy_cooked <-- NO NEWLINE\n"));
} else {
/* Take care of CRLF => LF conversion or
LF -> CRLF conversion
*/
state_convert_EOLN(buffer,&buf_len,sizeof buffer,dest_file);
}
err = state_puts(prefix,dest_file);
if (err != EOF)
err = state_put(buffer, buf_len, dest_file);
if (err != buf_len) {
DPRINT(Debug,1,(&Debug,
"copy_cooked fails (err=%d != %d=buf_len)\n",
err,buf_len));
goto fail;
}
}
DPRINT(Debug,5,(&Debug,
"copy_cooked: Read %d bytes from body\n",body_bytes));
if (body_bytes != current_header->content_length) {
DPRINT(Debug,1,(&Debug,
"copy_cooked: ERROR: read bytes %d != content-length %d\n",
body_bytes,current_header->content_length));
return 0;
}
return 1;
fail:
return 0;
}
copy_decoder_t select_copy_decoder (current_header)
struct header_rec * current_header;
{
if (current_header->status & MIME_MESSAGE)
return copy_mime;
#ifdef USE_PGP
else if (current_header->pgp & (PGP_MESSAGE|PGP_SIGNED_MESSAGE|PGP_PUBLIC_KEY))
return copy_pgp;
#endif
else if (current_header -> encrypted)
return copy_encrypted;
else
return copy_plain;
}
int copy_message_d(infolder,current_header,prefix,dir,dest,cm_options,
file_set)
struct folder_info *infolder;
struct header_rec *current_header;
char * prefix;
struct folder_browser *dir;
WRITE_STATE dest;
int cm_options;
charset_t file_set;
{
FILE * infile;
int remove_envelope = cm_options & CM_REMOVE_ENVELOPE;
int decode = cm_options & CM_DECODE;
int ret = 0;
int env_flags = 0;
out_state_t buffer;
charset_t charset_vector[2];
if (decode && !file_set)
panic("FILE PANIC",__FILE__,__LINE__,
"copy_message_d",
"decode set but not file_set",0);
/* Needed by STATE_out_dir */
charset_vector[0] = decode ? file_set : RAW_BUFFER;
charset_vector[1] = NULL;
if (decode) {
DPRINT(MimeDebug,5,
(&MimeDebug, "Decoding message to %s charset\n",
charset_vector[0] -> MIME_name ?
charset_vector[0] -> MIME_name :
"<no MIME name>"));
}
if (!prepare_message_access(infolder,
current_header,
parse_header_routine,
parse_body_routine,
NULL,
decode ? mime_parse_routine : NO_mime_parse)) {
DPRINT(Debug,5, (&Debug,
"copy_message_d: prepare_message_access failed\n"));
return 0;
}
infile = folder_to_fd(infolder,current_header->offset);
if (!infile) {
DPRINT(Debug,1,
(&Debug,
"ERROR: Attempt to seek %d bytes into file failed (%s)",
current_header->offset, "copy_message_d"));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSeekFailed,
"ELM [seek] failed trying to read %d bytes into file."),
current_header->offset);
return 0;
}
if (!write_envelope_start(dir,dest,!remove_envelope,
current_header,&env_flags))
goto fail;
out_state_clear(&buffer,STATE_out_dir);
buffer.display_charset = charset_vector;
set_out_state_dir(dir,dest,&buffer);
ret = copy_message_2(infile,current_header,prefix,&buffer,cm_options,
env_flags);
out_state_destroy(&buffer);
if (!write_envelope_end(dir,dest,!remove_envelope,
current_header))
ret = 0;
fail:
if (!ret) {
DPRINT(Debug,1,(&Debug,
"copy_message_d fails\n"));
}
return ret;
}
int copy_message_df(infile,current_header,prefix,dir,dest,cm_options,
file_set)
FILE *infile;
struct header_rec *current_header;
char * prefix;
struct folder_browser *dir;
WRITE_STATE dest;
int cm_options;
charset_t file_set;
{
int remove_envelope = cm_options & CM_REMOVE_ENVELOPE;
int decode = cm_options & CM_DECODE;
int ret = 0;
int env_flags = 0;
out_state_t buffer;
charset_t charset_vector[2];
if (decode && !file_set)
panic("FILE PANIC",__FILE__,__LINE__,
"copy_message_df",
"decode set but not file_set",0);
/* Needed by STATE_out_dir */
charset_vector[0] = decode ? file_set : RAW_BUFFER;
charset_vector[1] = NULL;
if (decode) {
DPRINT(MimeDebug,5,
(&MimeDebug, "Decoding message to %s charset\n",
charset_vector[0] -> MIME_name ?
charset_vector[0] -> MIME_name :
"<no MIME name>"));
}
/* FILE * should be laready seeked to correct position, but
this is extra assurance in case of it is readed meanwhile
*/
if (0 != fseek(infile,current_header->offset,SEEK_SET)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeFailedSeekEnvelope,
"Failed to seek beginning of mail envelope (%ld)"),
current_header->offset);
goto fail;
}
if (!write_envelope_start(dir,dest,!remove_envelope,
current_header,&env_flags))
goto fail;
out_state_clear(&buffer,STATE_out_dir);
buffer.display_charset = charset_vector;
set_out_state_dir(dir,dest,&buffer);
ret = copy_message_2(infile,current_header,prefix,&buffer,cm_options,
env_flags);
out_state_destroy(&buffer);
if (!write_envelope_end(dir,dest,!remove_envelope,
current_header))
ret = 0;
fail:
if (!ret) {
DPRINT(Debug,1,(&Debug,
"copy_message_df fails\n"));
}
return ret;
}
int copy_message_f(infile,
current_header,
prefix,
dest_file,
cm_options,
file_set)
FILE *infile;
struct header_rec *current_header;
char *prefix;
FILE *dest_file;
int cm_options;
charset_t file_set;
{
int ret = 0;
struct folder_browser *dir = NULL;
WRITE_STATE dest = NULL;
int env_flags = 0;
out_state_t buffer;
start_fd_write_state(dest_file,&dir,&dest);
ret = copy_message_df(infile,current_header,prefix,dir,dest,cm_options,
file_set);
end_fd_write_state(&dir,&dest);
/* Since fprintf is buffered, its return value is only useful for
* writes which exceed the blocksize. Do a fflush to ensure that
* the message has, in fact, been written.
*/
if (fflush(dest_file) == EOF) {
DPRINT(Debug,1, (&Debug,
"copy_message_f: Final fflush failed!\n"));
ret = 0;
}
if (!ret) {
DPRINT(Debug,1,(&Debug,
"copy_message_f fails\n"));
}
return ret;
}
#if 0 /* NOT USED */
int copy_message(infolder,
current_header,
prefix,
dest_file,
cm_options,
file_set)
struct folder_info *infolder;
struct header_rec *current_header;
char *prefix;
FILE *dest_file;
int cm_options;
charset_t file_set;
{
int ret = 0;
struct folder_browser *dir = NULL;
WRITE_STATE dest = NULL;
start_fd_write_state(dest_file,&dir,&dest);
ret = copy_message_d(infolder,current_header,prefix,
dir, dest, cm_options, file_set);
end_fd_write_state(&dir,&dest);
/* Since fprintf is buffered, its return value is only useful for
* writes which exceed the blocksize. Do a fflush to ensure that
* the message has, in fact, been written.
*/
if (fflush(dest_file) == EOF) {
DPRINT(Debug,1, (&Debug,
"copy_message: Final fflush failed!\n"));
ret = 0;
}
return ret;
}
#endif
/* Assumes that headers are already copied ------------------- */
int copy_body(infile,current_header,prefix,dest_file,cm_options)
FILE *infile;
struct header_rec *current_header;
char *prefix;
out_state_t *dest_file;
int cm_options;
{
int ret = 0;
int decode = cm_options & CM_DECODE;
int j;
DPRINT(Debug,5, (&Debug,
"copy_body: decode=%d\n",decode));
for (j = 0; dest_file->display_charset[j]; j++) {
DPRINT(Debug,5, (&Debug,
" : 'display charset[%d]'=%s\n",
j,
dest_file->display_charset[j]->MIME_name ?
dest_file->display_charset[j]->MIME_name :
"<no MIME name>"));
}
if (decode) {
copy_decoder_t decoder = select_copy_decoder(current_header);
ret = decoder(prefix,dest_file,cm_options,current_header,infile);
dest_file -> filter = NULL;
} else if (cm_options & CM_CRLF ||
cm_options & CM_LF) {
ret = copy_cooked(prefix,dest_file,cm_options,current_header,infile);
} else
ret = copy_binary(prefix,dest_file,cm_options,current_header,infile);
if (!ret) {
DPRINT(Debug,1,(&Debug,
"copy_body fails\n"));
}
return ret;
}
int copy_message_2(infile,current_header,prefix,dest_file,cm_options,
env_flags)
FILE *infile;
struct header_rec *current_header;
char *prefix;
out_state_t *dest_file;
int cm_options;
int env_flags;
{
/** Copy current message to destination file, with optional 'prefix'
as the prefix for each line. If remove_header is true, it will
skip lines in the message until it finds the end of header line...
then it will start copying into the file... If remote is true
then it will append "remote from <hostname>" at the end of the
very first line of the file (for remailing)
If "filter_header" is true then it'll do some nice things to
ensure that the forwarded message looks pleasant; e.g. remove
stuff like ">From " lines and "Received:" lines.
If "update_status" is true then it will write a new Status:
line at the end of the headers. It never copies an existing one.
If "decode" decode MIME, PGP and elm's (unsafe) own decoding.
**/
int first_line = TRUE;
int remove_header = cm_options & CM_REMOVE_HEADER;
int remove_envelope = cm_options & CM_REMOVE_ENVELOPE;
int update_status = cm_options & CM_UPDATE_STATUS;
int remail = cm_options & CM_REMAIL;
int decode = cm_options & CM_DECODE;
int filter_headers = cm_options & CM_FILT_HDR;
int bytes_seen = 0;
int content_length_seen = FALSE;
int return_path_seen = FALSE;
long CL_pos = -1L, BODY_pos = -1L, END_pos = -1L;
int was_binary = current_header -> binary && !decode;
long R1, R2;
header_list_ptr all_headers = NULL, next_hdr;
int buf_len;
int i;
DPRINT(Debug,5, (&Debug,
"copy_message_2: cm_options=(%d)%s%s%s%s%s%s%s%s%s \n",
cm_options,
remove_header ? " CM_REMOVE_HEADER" : "",
remove_envelope ? " CM_REMOVE_ENVELOPE" : "",
update_status ? " CM_UPDATE_STATUS" : "",
remail ? " CM_REMAIL" : "",
decode ? " CM_DECODE" : "",
filter_headers ? " CM_FILT_HDR" : "",
(cm_options & CM_DISPLAYING) ? " CM_DISPLAYING" : "",
(cm_options & CM_CRLF) ? " CM_CRLF" : "",
(cm_options & CM_LF) ? " CM_LF" : ""));
DPRINT(Debug,5, (&Debug,
"copy_message_2: env_flags=(%d)%s%s\n",
env_flags,
(env_flags & WE_ADD_RETURN_PATH) ? " WE_ADD_RETURN_PATH" : "",
(env_flags & WE_USE_CRLF) ? " WE_USE_CRLF" : ""));
if (was_binary && (cm_options & CM_LF) &&
current_header->mime_rec.encoding != ENCODING_BINARY) {
DPRINT(Debug,5,(&Debug,
"copy_message_2: cm_options: CM_LF set, encoding not binary (%s), resetting binary flag\n",
ENCODING(current_header->mime_rec.encoding)
));
was_binary = 0;
}
if (was_binary && !dest_file->EOLN_is_CRLF) {
dest_file->EOLN_is_CRLF = 1;
DPRINT(Debug,5,(&Debug,
"copy_message_2: binary: Setting EOLN_is_CRLF\n"));
}
if (was_binary && (cm_options & CM_LF)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBinaryMailNoConvert,
"Binary mail -- can not convert CRLF -> LF"));
DPRINT(Debug,5,(&Debug,
"copy_message_2: binary: Resetting CM_LF\n"));
cm_options &= ~CM_LF;
}
if ((env_flags & WE_USE_CRLF) && ! (cm_options & CM_CRLF)) {
cm_options |= CM_CRLF;
DPRINT(Debug,5,(&Debug,
"copy_message_2: env_flags: Setting cm_options CM_CRLF\n"));
}
if ((cm_options & CM_CRLF) && !dest_file->EOLN_is_CRLF) {
dest_file->EOLN_is_CRLF = 1;
DPRINT(Debug,5,(&Debug,
"copy_message_2: cm_options: Setting EOLN_is_CRLF\n"));
}
if ((cm_options & CM_CRLF) && (cm_options & CM_LF)) {
DPRINT(Debug,1,(&Debug,
"copy_message_2: cm_options: Conflicting CM_CRLF and CM_LF -- resetting CM_LF\n"));
cm_options &= ~CM_LF;
}
if ((cm_options & CM_LF) && dest_file->EOLN_is_CRLF) {
dest_file->EOLN_is_CRLF = 1;
DPRINT(Debug,1,(&Debug,
"copy_message_2: cm_options: CM_LF conflict with EOLN_is_CRLF -- resetting CM_LF\n"));
cm_options &= ~CM_LF;
}
if (was_binary && (cm_options & CM_CRLF)) {
cm_options &= ~CM_CRLF;
DPRINT(Debug,5,(&Debug,
"copy_message_2: binary: Resetting cm_options CM_CRLF flag (no conversion!)\n"));
}
/** get to the first line of the message desired **/
/* No filter on here ... */
dest_file->filter = NULL;
if (decode) {
/* HACK:
Required by
state_write_header so
that 8bit headers are
printed correctly
*/
dest_file->filter = dest_file->display_charset[0] ;
}
/* now while not EOF & still in message... copy it! */
DPRINT(Debug,5,(&Debug,
"copy_message_2: [%ld] start mailbox separator section\n",
ftell(infile)));
while (1) {
char buffer[1024];
long last_pos = ftell(infile);
if (last_pos < 0) {
DPRINT(Debug,5,(&Debug,
"copy_message: ftell(infile) failed!\n"));
break;
}
if (! (buf_len = mail_gets(buffer, sizeof(buffer), infile)))
break;
#ifdef MMDF
if (strcmp(buffer, MSG_SEPARATOR) == 0)
continue; /* MSG SEPRATOR is already written */
#endif /* MMDF */
if(buffer[buf_len - 1] == '\n') {
no_ret(buffer);
if (first_word(buffer, "From ")) {
first_line = FALSE;
continue;
}
if (!first_line && first_word_nc(buffer, ">From")) {
#if 0
if (!filter_headers && !remove_header && !remove_envelope) {
if (state_printf(dest_file,
FRM("%s%s\n"),
prefix, buffer) == EOF) {
DPRINT(Debug,1,(&Debug,
"copy_message_2 fails\n"));
goto fail;
}
}
#endif
continue;
}
/* fall thru */
}
DPRINT(Debug,5,(&Debug,
"copy_message: Not a mailbox line -- seeking back!\n"));
DPRINT(Debug,5,(&Debug,
"copy_message- Line was: %s\n",buffer));
if (0 != fseek(infile,last_pos,SEEK_SET)) {
DPRINT(Debug,5,(&Debug,
"copy_message: seek failed!\n"));
DPRINT(Debug,1,(&Debug,
"copy_message_2 fails\n"));
goto fail;
}
break; /* Go out of loop */
}
R1 = ftell(infile);
DPRINT(Debug,5,(&Debug,
"copy_message: [%ld] start header section\n",
R1));
all_headers = file_read_headers(infile,RHL_CHECK_HEADER|RHL_MARK_FOLDING);
R2 = ftell(infile);
bytes_seen = R2 - R1;
DPRINT(Debug,5,(&Debug,
"copy_message: [%ld] end of headers. Read ~ %d bytes.\n",
R2, bytes_seen));
if (!remove_header) {
for (next_hdr = all_headers;
next_hdr;
next_hdr = next_hdr -> next_header) {
CONST char * hdr_name = give_header_name(next_hdr->header_name);
if ((remail) && 0 == istrcmp("Sender",hdr_name)) {
continue;
}
if(0 == istrcmp(hdr_name, "Content-Length")) {
/* make correct Content-Length later */
content_length_seen = TRUE;
continue;
}
if (0 == istrcmp(hdr_name, "Return-Path"))
return_path_seen = TRUE;
if (!filter_headers) {
if (0 == istrcmp(hdr_name,"Status"))
continue; /* we will output a new Status: line later, if desired. */
} else { /* filter_headers */
if (0 == istrcmp(hdr_name, "Received") ||
0 == istrcmp(hdr_name, "Status") ||
0 == istrcmp(hdr_name, "Return-Path") ||
0 == istrcmp("X-UIDL",hdr_name) || /* Gen. by some POP deamons */
0 == istrcmp("X-UID",hdr_name) || /* Gen. by some IMAP deamons */
0 == istrcmp("X-Status",hdr_name)) /* Gen. by some IMAP deamons */
continue;
if (remail && 0 == istrcmp(hdr_name, "To"))
hdr_name = "Orig-To"; /* Works only if NOT decode */
}
/* These headers are incorrect after decoding ... */
if (decode) {
if ((current_header->status & MIME_MESSAGE) &&
(0 == istrcmp(hdr_name, "MIME-Version") ||
0 == istrcmp(hdr_name, "Content-Type") ||
0 == istrcmp(hdr_name, "Content-Transfer-Encoding")))
continue;
state_write_header(dest_file,next_hdr,
!(current_header -> status & NOHDRENCODING),
current_header -> header_charset);
} else {
/* NOT decode */
state_write_raw_header(dest_file,next_hdr);
}
}
/* Make artificial Return-Path header */
if ((remove_envelope || 0 != (env_flags & WE_ADD_RETURN_PATH))
&& !return_path_seen && !filter_headers) {
if (state_printf (dest_file,
FRM("%sReturn-Path: <%s>\n"),
prefix,current_header->env_from) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
}
if (out_state_seekable(dest_file) &&
((!filter_headers && content_length_seen) ||
(!remove_envelope && (current_header->have_from || decode)))) {
if (state_printf (dest_file,
FRM("Content-Length: ")) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
CL_pos = out_state_ftell(dest_file);
if (state_printf (dest_file,
FRM("%5d\n"),
current_header->content_length) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
}
if (remail) {
if (state_printf (dest_file,
FRM("%sSender: %s\n"),
prefix,username) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
}
if (update_status) {
char buffer[WLEN+10]; /* Enough space for status letters */
if (state_printf (dest_file,
FRM("%sStatus: "),
prefix) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
if (status_2_mailbox(current_header,buffer,sizeof buffer) > 0) {
if (state_printf (dest_file,
FRM("%s"),
buffer) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
}
/* Must use state_printf so EOLN_is_CRLF conversion occurs! */
if (state_printf(dest_file,
FRM("\n")) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
}
dest_file->filter = NULL; /* End HACK */
/*
* Add empty line between headers and body (that was not copied
* in above)
*/
/* Must use state_printf so EOLN_is_CRLF conversion occurs! */
if (state_printf(dest_file,
FRM("\n")) == EOF) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
}
}
DPRINT(Debug,5,(&Debug,
"copy_message_2: [%ld] Starting reading of body: %d bytes expected\n",
ftell(infile),
current_header->content_length));
if (out_state_seekable(dest_file)) {
BODY_pos = out_state_ftell(dest_file);
DPRINT(Debug,5,(&Debug,
"copy_message> output offset=[%ld]\n",BODY_pos));
}
if (!copy_body(infile,current_header,prefix,dest_file,cm_options)) {
DPRINT(Debug,1,(&Debug, "copy_message_2 fails (copy_body fails)\n"));
goto fail;
}
DPRINT(Debug,5,(&Debug,
"copy_message: [%ld] Body read.\n",
ftell(infile)));
if (out_state_seekable(dest_file)) {
FILE * f1 = out_state_FILE(dest_file);
END_pos = out_state_ftell(dest_file);
DPRINT(Debug,5,(&Debug,
"copy_message> output offset=[%ld]\n",END_pos));
if (CL_pos > 0 && BODY_pos > 0 && END_pos >= BODY_pos) {
/* Actually written content length is good if conversions are
* not done and there was no errors ...
*/
if (f1)
clearerr(f1);
/* Notice that these tests indicates failure */
if (0 != out_state_fseek(dest_file,CL_pos) ||
out_state_ftell(dest_file) != CL_pos ||
EOF == state_printf (dest_file,
FRM("%5d"), (int) (END_pos - BODY_pos)) ||
0 != out_state_fseek(dest_file,END_pos)) {
DPRINT(Debug,5,(&Debug,
"copy_message: Writing Content-length -- writing or seeking failed.\n"));
DPRINT(Debug,1,(&Debug, "copy_message_2 fails\n"));
goto fail;
} else {
DPRINT(Debug,1,(&Debug,
"copy_message: Content-length fixed: %d bytes.\n",
(int) (END_pos - BODY_pos)));
}
}
}
if (all_headers)
delete_headers(&all_headers);
return 1;
fail:
if (all_headers)
delete_headers(&all_headers);
return 0;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1