963 lines
18 KiB
C
963 lines
18 KiB
C
/*
|
|
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
|
|
** distribution information.
|
|
*/
|
|
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#if HAVE_STRINGS_H
|
|
#include <strings.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <pwd.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include "rfc2045.h"
|
|
#include "rfc822/rfc2047.h"
|
|
#include "rfc2045charset.h"
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if HAVE_SYS_WAIT_H
|
|
#include <sys/wait.h>
|
|
#endif
|
|
//#include "numlib/numlib.h"
|
|
|
|
#if HAS_GETHOSTNAME
|
|
#else
|
|
int gethostname(const char *, size_t);
|
|
#endif
|
|
|
|
|
|
static const char rcsid[]="$Id$";
|
|
|
|
void rfc2045_error(const char *errmsg)
|
|
{
|
|
fprintf(stderr, "reformime: %s\n", errmsg);
|
|
exit(1);
|
|
}
|
|
|
|
static void do_print_structure(struct rfc2045 *p, struct rfc2045id *id, void *ptr)
|
|
{
|
|
p=p;
|
|
ptr=p;
|
|
|
|
while (id)
|
|
{
|
|
printf("%d%c", id->idnum, id->next ? '.':'\n');
|
|
id=id->next;
|
|
}
|
|
}
|
|
|
|
static int decode_to_file(const char *p, size_t n, void *ptr)
|
|
{
|
|
FILE *fp=(FILE *)ptr;
|
|
|
|
while (n)
|
|
{
|
|
--n;
|
|
if (putc(*p++, fp) == -1)
|
|
{
|
|
perror("write");
|
|
exit(1);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "Usage: reformime [options]\n");
|
|
fprintf(stderr, " -d - parse a delivery status notification.\n");
|
|
fprintf(stderr, " -e - extract contents of MIME section.\n");
|
|
fprintf(stderr, " -x - extract MIME section to a file.\n");
|
|
fprintf(stderr, " -X - pipe MIME section to a program.\n");
|
|
fprintf(stderr, " -i - show MIME info.\n");
|
|
fprintf(stderr, " -s n.n.n.n - specify MIME section.\n");
|
|
fprintf(stderr, " -r - rewrite message, filling in missing MIME header.\n");
|
|
fprintf(stderr, " -r7 - also convert 8bit/raw encoding to quoted-printable, if possible.\n");
|
|
fprintf(stderr, " -r8 - also convert quoted-printable encoding to 8bit, if possible.\n");
|
|
fprintf(stderr, " -c charset - when rewriting, specify default charset.\n");
|
|
fprintf(stderr, " -m [file] [file]... - create a MIME message digest.\n");
|
|
exit(1);
|
|
}
|
|
|
|
static char *tempname(const char *tempdir)
|
|
{
|
|
char pidbuf[NUMBUFSIZE], timebuf[NUMBUFSIZE], hostnamebuf[256];
|
|
static unsigned counter=0;
|
|
time_t t;
|
|
char *p;
|
|
|
|
str_pid_t(getpid(), pidbuf);
|
|
time(&t);
|
|
str_time_t(t, timebuf);
|
|
hostnamebuf[sizeof(hostnamebuf)-1]=0;
|
|
if (gethostname(hostnamebuf, sizeof(hostnamebuf)))
|
|
hostnamebuf[0]=0;
|
|
p=malloc(strlen(tempdir)+strlen(pidbuf)+strlen(timebuf)+
|
|
strlen(hostnamebuf)+100);
|
|
if (!p) return (0);
|
|
sprintf(p, "%s/%s.%s-%u.%s", tempdir, timebuf, pidbuf, counter++,
|
|
hostnamebuf);
|
|
return (p);
|
|
}
|
|
|
|
struct rfc2045 *read_message()
|
|
{
|
|
char buf[BUFSIZ];
|
|
struct rfc2045 *p=rfc2045_alloc_ac();
|
|
FILE *tempfp=0;
|
|
|
|
if (fseek(stdin, 0L, SEEK_END) < 0 ||
|
|
fseek(stdin, 0L, SEEK_SET) < 0) /* Pipe, save to temp file */
|
|
{
|
|
tempfp=tmpfile();
|
|
}
|
|
|
|
while (fgets(buf, sizeof(buf), stdin))
|
|
{
|
|
int l=strlen(buf);
|
|
|
|
rfc2045_parse(p, buf, l);
|
|
if (tempfp && fwrite(buf, l, 1, tempfp) != 1)
|
|
{
|
|
perror("fwrite");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (tempfp) /* Replace stdin */
|
|
{
|
|
close(0);
|
|
dup(fileno(tempfp));
|
|
fclose(tempfp);
|
|
}
|
|
return (p);
|
|
}
|
|
|
|
void print_structure(struct rfc2045 *p)
|
|
{
|
|
rfc2045_decode(p, &do_print_structure, 0);
|
|
}
|
|
|
|
static void notfound(const char *p)
|
|
{
|
|
fprintf(stderr, "reformime: MIME section %s not found.\n", p);
|
|
exit(1);
|
|
}
|
|
|
|
static void do_print_info(struct rfc2045 *s)
|
|
{
|
|
const char *content_type, *transfer_encoding, *charset;
|
|
off_t start, end, body;
|
|
const char *disposition;
|
|
const char *disposition_name;
|
|
const char *disposition_filename;
|
|
const char *content_name;
|
|
off_t nlines, nbodylines;
|
|
const char *p;
|
|
|
|
rfc2045_mimeinfo(s, &content_type, &transfer_encoding, &charset);
|
|
rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines);
|
|
rfc2045_dispositioninfo(s, &disposition, &disposition_name,
|
|
&disposition_filename);
|
|
content_name=rfc2045_contentname(s);
|
|
printf("content-type: %s\n", content_type);
|
|
if (content_name)
|
|
{
|
|
char *s=rfc2047_decode_simple(content_name);
|
|
|
|
if (!s)
|
|
{
|
|
perror("rfc2047_decode_simple");
|
|
exit(1);
|
|
}
|
|
printf("content-name: %s\n", s);
|
|
free(s);
|
|
}
|
|
|
|
printf("content-transfer-encoding: %s\n", transfer_encoding);
|
|
printf("charset: %s\n", charset);
|
|
if (disposition && *disposition)
|
|
printf("content-disposition: %s\n", disposition);
|
|
if (disposition_name && *disposition_name)
|
|
{
|
|
char *s=rfc2047_decode_simple(disposition_name);
|
|
|
|
if (!s)
|
|
{
|
|
perror("rfc2047_decode_simple");
|
|
exit(1);
|
|
}
|
|
printf("content-disposition-name: %s\n", s);
|
|
free(s);
|
|
}
|
|
|
|
if (disposition_filename && *disposition_filename)
|
|
{
|
|
char *s=rfc2047_decode_simple(disposition_filename);
|
|
|
|
if (!s)
|
|
{
|
|
perror("rfc2047_decode_simple");
|
|
exit(1);
|
|
}
|
|
printf("content-disposition-filename: %s\n", s);
|
|
free(s);
|
|
}
|
|
|
|
if (*(p=rfc2045_content_id(s)))
|
|
printf("content-id: <%s>\n", p);
|
|
if (*(p=rfc2045_content_description(s)))
|
|
{
|
|
char *s=rfc2047_decode_simple(p);
|
|
|
|
if (!s)
|
|
{
|
|
perror("rfc2047_decode_simple");
|
|
exit(1);
|
|
}
|
|
printf("content-description: %s\n", s);
|
|
free(s);
|
|
}
|
|
if (*(p=rfc2045_content_language(s)))
|
|
printf("content-language: %s\n", p);
|
|
if (*(p=rfc2045_content_md5(s)))
|
|
printf("content-md5: %s\n", p);
|
|
|
|
printf("starting-pos: %lu\n", (unsigned long)start);
|
|
printf("starting-pos-body: %lu\n", (unsigned long)body);
|
|
printf("ending-pos: %lu\n", (unsigned long)end);
|
|
printf("line-count: %lu\n", (unsigned long)nlines);
|
|
printf("body-line-count: %lu\n", (unsigned long)nbodylines);
|
|
}
|
|
|
|
static void do_print_info_multiple(struct rfc2045 *p, struct rfc2045id *id,
|
|
void *ptr)
|
|
{
|
|
printf("section: ");
|
|
do_print_structure(p, id, ptr);
|
|
do_print_info(p);
|
|
printf("\n");
|
|
}
|
|
|
|
void print_info(struct rfc2045 *p, const char *mimesection)
|
|
{
|
|
struct rfc2045 *s;
|
|
|
|
if (mimesection)
|
|
{
|
|
s=rfc2045_find(p, mimesection);
|
|
if (!s)
|
|
notfound(mimesection);
|
|
printf("section: %s\n", mimesection);
|
|
do_print_info(s);
|
|
return;
|
|
}
|
|
rfc2045_decode(p, &do_print_info_multiple, 0);
|
|
}
|
|
|
|
static void do_print_section(struct rfc2045 *s, FILE *fp)
|
|
{
|
|
off_t start, end, body;
|
|
off_t nlines;
|
|
off_t nbodylines;
|
|
|
|
rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines);
|
|
|
|
if (fseek(stdin, body, SEEK_SET) == -1)
|
|
{
|
|
perror("fseek");
|
|
exit(1);
|
|
}
|
|
|
|
rfc2045_cdecode_start(s, &decode_to_file, fp);
|
|
while (body < end)
|
|
{
|
|
char buf[BUFSIZ];
|
|
size_t n=sizeof(buf);
|
|
|
|
if ((off_t)n > end-body) n=end-body;
|
|
n=fread(buf, 1, n, stdin);
|
|
if (n == 0)
|
|
{
|
|
perror("fread");
|
|
exit(1);
|
|
}
|
|
rfc2045_cdecode(s, buf, n);
|
|
body += n;
|
|
}
|
|
rfc2045_cdecode_end(s);
|
|
}
|
|
|
|
void print_decode(struct rfc2045 *p, const char *mimesection)
|
|
{
|
|
struct rfc2045 *s;
|
|
|
|
if (!mimesection)
|
|
usage();
|
|
|
|
s=rfc2045_find(p, mimesection);
|
|
if (!s)
|
|
notfound(mimesection);
|
|
|
|
do_print_section(s, stdout);
|
|
}
|
|
|
|
void rewrite(struct rfc2045 *p, int rwmode)
|
|
{
|
|
rfc2045_ac_check(p, rwmode);
|
|
if (rfc2045_rewrite(p, fileno(stdin), fileno(stdout),
|
|
"reformime (" RFC2045PKG " " RFC2045VER ")"))
|
|
{
|
|
perror("reformime");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static char *get_suitable_filename(struct rfc2045 *r, const char *pfix,
|
|
int ignore_filename)
|
|
{
|
|
const char *disposition_s;
|
|
const char *disposition_name_s;
|
|
const char *disposition_filename_s;
|
|
char *filename_buf;
|
|
const char *content_name_s;
|
|
char *p, *q;
|
|
char *dyn_disp_name=0;
|
|
|
|
rfc2045_dispositioninfo(r, &disposition_s, &disposition_name_s,
|
|
&disposition_filename_s);
|
|
|
|
content_name_s=rfc2045_contentname(r);
|
|
|
|
if (!disposition_filename_s || !*disposition_filename_s)
|
|
disposition_filename_s=disposition_name_s;
|
|
if (!disposition_filename_s || !*disposition_filename_s)
|
|
disposition_filename_s=content_name_s;
|
|
|
|
filename_buf=rfc2047_decode_simple(disposition_filename_s);
|
|
|
|
if (!filename_buf)
|
|
{
|
|
perror("rfc2047_decode_simple");
|
|
exit(1);
|
|
}
|
|
|
|
if (strlen(filename_buf) > 32)
|
|
{
|
|
p=filename_buf;
|
|
q=filename_buf + strlen(filename_buf)-32;
|
|
while ( (*p++ = *q++) != 0)
|
|
;
|
|
}
|
|
|
|
disposition_filename_s=filename_buf;
|
|
|
|
if (ignore_filename)
|
|
{
|
|
char numbuf[NUMBUFSIZE];
|
|
static size_t counter=0;
|
|
const char *p=str_size_t(++counter, numbuf);
|
|
|
|
dyn_disp_name=malloc(strlen(disposition_filename_s)
|
|
+ strlen(p)+2);
|
|
if (!dyn_disp_name)
|
|
{
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
disposition_filename_s=strcat(strcat(strcpy(
|
|
dyn_disp_name, p), "-"),
|
|
disposition_filename_s);
|
|
}
|
|
else if (!disposition_filename_s || !*disposition_filename_s)
|
|
{
|
|
dyn_disp_name=tempname(".");
|
|
disposition_filename_s=dyn_disp_name+2; /* Skip over ./ */
|
|
}
|
|
|
|
p=malloc((pfix ? strlen(pfix):0)+strlen(disposition_filename_s)+1);
|
|
if (!p)
|
|
{
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
*p=0;
|
|
if (pfix) strcpy(p, pfix);
|
|
q=p+strlen(p);
|
|
for (strcpy(q, disposition_filename_s); *q; q++)
|
|
if (!isalnum(*q) && *q != '.' && *q != '-')
|
|
*q='_';
|
|
|
|
if (dyn_disp_name) free(dyn_disp_name);
|
|
|
|
if (!pfix)
|
|
{
|
|
const char *content_type_s;
|
|
const char *content_transfer_encoding_s;
|
|
const char *charset_s;
|
|
int c;
|
|
static char filenamebuf[256];
|
|
char *t;
|
|
FILE *tty;
|
|
|
|
if ((tty=fopen("/dev/tty", "r+")) == 0)
|
|
{
|
|
perror("/dev/tty");
|
|
exit(1);
|
|
}
|
|
|
|
rfc2045_mimeinfo(r, &content_type_s,
|
|
&content_transfer_encoding_s, &charset_s);
|
|
|
|
fprintf (tty, "Extract %s? ", content_type_s);
|
|
fflush(tty);
|
|
c=getc(tty);
|
|
if (c != '\n' && c != EOF)
|
|
{
|
|
int cc;
|
|
|
|
while ((cc=getc(tty)) != '\n' && cc != EOF)
|
|
;
|
|
}
|
|
if (c != 'y' && c != 'Y')
|
|
{
|
|
free(p);
|
|
fclose(tty);
|
|
free(filename_buf);
|
|
return (0);
|
|
}
|
|
fprintf (tty, "Filename [%s]: ", p);
|
|
fgets(filenamebuf, sizeof(filenamebuf)-1, tty);
|
|
fclose(tty);
|
|
t=strchr(filenamebuf, '\n');
|
|
if (t) *t=0;
|
|
else
|
|
{
|
|
fprintf(stderr, "Filename too long.\n");
|
|
exit(1);
|
|
}
|
|
if (filenamebuf[0])
|
|
{
|
|
free(p);
|
|
p=strdup(filenamebuf);
|
|
if (!p)
|
|
{
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
free(filename_buf);
|
|
return (p);
|
|
}
|
|
|
|
static void extract_file(struct rfc2045 *p,
|
|
const char *filename, int argc, char **argv)
|
|
{
|
|
char *f;
|
|
FILE *fp;
|
|
int ignore=0;
|
|
|
|
for (;;)
|
|
{
|
|
int fd;
|
|
|
|
f=get_suitable_filename(p, filename, ignore);
|
|
if (!f) return;
|
|
|
|
fd=open(f, O_WRONLY|O_CREAT|O_EXCL, 0666);
|
|
if (fd < 0)
|
|
{
|
|
if (errno == EEXIST)
|
|
{
|
|
printf("%s exists.\n", f);
|
|
free(f);
|
|
ignore=1;
|
|
continue;
|
|
}
|
|
|
|
perror(f);
|
|
exit(1);
|
|
}
|
|
fp=fdopen(fd, "w");
|
|
if (!fp)
|
|
{
|
|
perror("fdopen");
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
do_print_section(p, fp);
|
|
if (fflush(fp) || ferror(fp))
|
|
{
|
|
perror("write");
|
|
exit(1);
|
|
}
|
|
fclose(fp);
|
|
free(f);
|
|
}
|
|
|
|
static void extract_pipe(struct rfc2045 *p,
|
|
const char *filename,
|
|
int argc, char **argv)
|
|
{
|
|
char *f=get_suitable_filename(p, "FILENAME=", 0);
|
|
int pipefd[2];
|
|
pid_t pid, p2;
|
|
FILE *fp;
|
|
int waitstat;
|
|
|
|
if (argc == 0)
|
|
{
|
|
fprintf(stderr, "reformime: Invalid -X option.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (pipe(pipefd))
|
|
{
|
|
perror("pipe");
|
|
exit(1);
|
|
}
|
|
|
|
if ((fp=fdopen(pipefd[1], "w")) == 0)
|
|
{
|
|
perror("fdopen");
|
|
exit(1);
|
|
}
|
|
|
|
while ((pid=fork()) == -1)
|
|
{
|
|
sleep(2);
|
|
}
|
|
|
|
if (pid == 0)
|
|
{
|
|
const char *content_type_s;
|
|
const char *content_transfer_encoding_s;
|
|
const char *charset_s;
|
|
|
|
if (!f) f="FILENAME=attachment.dat";
|
|
putenv(f);
|
|
rfc2045_mimeinfo(p, &content_type_s,
|
|
&content_transfer_encoding_s, &charset_s);
|
|
f=malloc(strlen(content_type_s)
|
|
+sizeof("CONTENT_TYPE="));
|
|
if (!f)
|
|
{
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
strcat(strcpy(f, "CONTENT_TYPE="), content_type_s);
|
|
putenv(f);
|
|
close(0);
|
|
dup(pipefd[0]);
|
|
close(pipefd[0]);
|
|
close(pipefd[1]);
|
|
execv(argv[0], argv);
|
|
perror("exec");
|
|
_exit(1);
|
|
}
|
|
close(pipefd[0]);
|
|
signal(SIGPIPE, SIG_IGN);
|
|
do_print_section(p, fp);
|
|
signal(SIGPIPE, SIG_DFL);
|
|
fclose(fp);
|
|
close(pipefd[1]);
|
|
|
|
while ((p2=wait(&waitstat)) != pid && p2 != -1)
|
|
;
|
|
free(f);
|
|
}
|
|
|
|
static void extract_section(struct rfc2045 *top_rfcp, const char *mimesection,
|
|
const char *extract_filename, int argc, char **argv,
|
|
void (*extract_func)(struct rfc2045 *, const char *,
|
|
int, char **))
|
|
{
|
|
if (mimesection)
|
|
{
|
|
top_rfcp=rfc2045_find(top_rfcp, mimesection);
|
|
if (!mimesection)
|
|
notfound(mimesection);
|
|
if (top_rfcp->firstpart)
|
|
{
|
|
fprintf(stderr, "reformime: MIME section %s is a compound section.\n", mimesection);
|
|
exit(1);
|
|
}
|
|
(*extract_func)(top_rfcp, extract_filename, argc, argv);
|
|
return;
|
|
}
|
|
|
|
/* Recursive */
|
|
|
|
if (top_rfcp->firstpart)
|
|
{
|
|
for (top_rfcp=top_rfcp->firstpart; top_rfcp;
|
|
top_rfcp=top_rfcp->next)
|
|
extract_section(top_rfcp, mimesection,
|
|
extract_filename, argc, argv, extract_func);
|
|
return;
|
|
}
|
|
|
|
if (!top_rfcp->isdummy)
|
|
(*extract_func)(top_rfcp, extract_filename, argc, argv);
|
|
}
|
|
|
|
static void print_dsn_recip(char *addr, char *action)
|
|
{
|
|
char *p, *q;
|
|
|
|
if (!action || !addr)
|
|
{
|
|
if (action) free(action);
|
|
if (addr) free(addr);
|
|
return;
|
|
}
|
|
|
|
for (p=action; *p; ++p)
|
|
*p=tolower((int)(unsigned char)*p);
|
|
|
|
for (p=addr; *p && isspace((int)(unsigned char)*p); ++p)
|
|
;
|
|
|
|
if (strncasecmp(p, "rfc822;", 7))
|
|
{
|
|
free(action);
|
|
free(addr);
|
|
return;
|
|
}
|
|
for (q=action; *q && isspace((int)(unsigned char)*q); ++q)
|
|
;
|
|
p += 7;
|
|
while (*p && isspace((int)(unsigned char)*p))
|
|
++p;
|
|
printf("%s %s\n", q, p);
|
|
free(action);
|
|
free(addr);
|
|
}
|
|
|
|
static void dsn(struct rfc2045 *p, int do_orig)
|
|
{
|
|
const char *content_type_s;
|
|
const char *content_transfer_encoding_s;
|
|
const char *charset_s;
|
|
off_t start_pos, end_pos, start_body;
|
|
off_t dummy;
|
|
const char *q;
|
|
char buf[BUFSIZ];
|
|
unsigned i;
|
|
int ch;
|
|
char *recip;
|
|
char *action;
|
|
char *orecip;
|
|
|
|
rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s,
|
|
&charset_s);
|
|
if (strcasecmp(content_type_s, "multipart/report") ||
|
|
(q=rfc2045_getattr(p->content_type_attr, "report-type")) == 0 ||
|
|
strcasecmp(q, "delivery-status") ||
|
|
!p->firstpart || !p->firstpart->next ||
|
|
!p->firstpart->next->next)
|
|
_exit(1);
|
|
p=p->firstpart->next->next;
|
|
rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s,
|
|
&charset_s);
|
|
rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy);
|
|
if (strcasecmp(content_type_s, "message/delivery-status") ||
|
|
fseek(stdin, start_body, SEEK_SET) == -1)
|
|
_exit(1);
|
|
|
|
i=0;
|
|
recip=0;
|
|
orecip=0;
|
|
action=0;
|
|
while (start_body < end_pos)
|
|
{
|
|
if ((ch=getchar()) == EOF) break;
|
|
++start_body;
|
|
if (i < sizeof(buf)-1)
|
|
buf[i++]= ch;
|
|
if (ch != '\n') continue;
|
|
ch=getchar();
|
|
if (ch != EOF) ungetc(ch, stdin);
|
|
if (ch != '\n' && isspace((int)(unsigned char)ch))
|
|
continue;
|
|
buf[i-1]=0;
|
|
if (buf[0] == 0)
|
|
{
|
|
if (orecip)
|
|
{
|
|
if (recip) free(recip);
|
|
recip=orecip;
|
|
orecip=0;
|
|
}
|
|
print_dsn_recip(recip, action);
|
|
recip=0;
|
|
action=0;
|
|
}
|
|
if (strncasecmp(buf, "Final-Recipient:", 16) == 0 &&
|
|
recip == 0)
|
|
{
|
|
recip=strdup(buf+16);
|
|
if (!recip)
|
|
{
|
|
perror("strdup");
|
|
exit(2);
|
|
}
|
|
}
|
|
if (strncasecmp(buf, "Original-Recipient:", 19) == 0 &&
|
|
orecip == 0 && do_orig)
|
|
{
|
|
orecip=strdup(buf+19);
|
|
if (!orecip)
|
|
{
|
|
perror("strdup");
|
|
exit(2);
|
|
}
|
|
}
|
|
if (strncasecmp(buf, "Action:", 7) == 0 && action == 0)
|
|
{
|
|
action=strdup(buf+7);
|
|
if (!action)
|
|
{
|
|
perror("strdup");
|
|
exit(2);
|
|
}
|
|
}
|
|
i=0;
|
|
}
|
|
if (orecip)
|
|
{
|
|
if (recip) free(recip);
|
|
recip=orecip;
|
|
orecip=0;
|
|
}
|
|
print_dsn_recip(recip, action);
|
|
}
|
|
|
|
static void mimedigest1(int, char **);
|
|
static char mimebuf[BUFSIZ];
|
|
|
|
static void mimedigest(int argc, char **argv)
|
|
{
|
|
char *p;
|
|
struct filelist { struct filelist *next; char *fn; } *first=0, *last=0;
|
|
unsigned pcnt=0;
|
|
char **l;
|
|
|
|
if (argc > 0)
|
|
{
|
|
mimedigest1(argc, argv);
|
|
return;
|
|
}
|
|
|
|
while (fgets(mimebuf, sizeof(mimebuf), stdin))
|
|
{
|
|
struct filelist *q;
|
|
|
|
if ((p=strchr(mimebuf, '\n')) != 0) *p=0;
|
|
q=malloc(sizeof(struct filelist));
|
|
if (!q || !(q->fn=strdup(mimebuf)))
|
|
{
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
|
|
if (last) last->next=q;
|
|
else first=q;
|
|
last=q;
|
|
q->next=0;
|
|
++pcnt;
|
|
}
|
|
if (pcnt == 0) return;
|
|
|
|
if ( (l=malloc(sizeof (char *) * pcnt)) == 0)
|
|
{
|
|
perror("malloc");
|
|
}
|
|
pcnt=0;
|
|
|
|
for (last=first; last; last=last->next)
|
|
l[pcnt++]=last->fn;
|
|
|
|
mimedigest1(pcnt, l);
|
|
}
|
|
|
|
static void mimedigest1(int argc, char **argv)
|
|
{
|
|
time_t t;
|
|
char boundarybuf[200];
|
|
unsigned boundarycnt=0;
|
|
int i;
|
|
FILE *fp;
|
|
|
|
time (&t);
|
|
|
|
/* Search for a suitable boundary */
|
|
|
|
do
|
|
{
|
|
int l;
|
|
|
|
sprintf(boundarybuf, "reformime_%lu_%u",
|
|
(unsigned long)t, ++boundarycnt);
|
|
|
|
l=strlen(boundarybuf);
|
|
|
|
for (i=0; i<argc; i++)
|
|
{
|
|
int err=0;
|
|
|
|
if ((fp=fopen(argv[i], "r")) == 0)
|
|
{
|
|
perror(argv[i]);
|
|
exit(1);
|
|
}
|
|
|
|
while (fgets(mimebuf, sizeof(mimebuf), fp))
|
|
{
|
|
if (mimebuf[0] != '-' || mimebuf[1] != '-')
|
|
continue;
|
|
|
|
if (strncasecmp(mimebuf+2, boundarybuf, l) == 0)
|
|
{
|
|
err=1;
|
|
break;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
if (err) break;
|
|
}
|
|
} while (i < argc);
|
|
|
|
printf("Mime-Version:1.0\n"
|
|
"Content-Type: multipart/digest; boundary=\"%s\"\n\n%s",
|
|
boundarybuf, RFC2045MIMEMSG);
|
|
|
|
for (i=0; i<argc; i++)
|
|
{
|
|
if ((fp=fopen(argv[i], "r")) == 0)
|
|
{
|
|
perror(argv[i]);
|
|
exit(1);
|
|
}
|
|
|
|
printf("\n--%s\nContent-Type: message/rfc822\n\n",
|
|
boundarybuf);
|
|
|
|
while (fgets(mimebuf, sizeof(mimebuf), fp))
|
|
printf("%s", mimebuf);
|
|
fclose(fp);
|
|
}
|
|
|
|
printf("\n--%s--\n", boundarybuf);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int argn;
|
|
char optc;
|
|
char *optarg;
|
|
char *mimesection=0;
|
|
int doinfo=0, dodecode=0, dorewrite=0, dodsn=0, domimedigest=0;
|
|
struct rfc2045 *p;
|
|
int rwmode=0;
|
|
void (*do_extract)(struct rfc2045 *, const char *, int, char **)=0;
|
|
const char *extract_filename=0;
|
|
|
|
for (argn=1; argn<argc; )
|
|
{
|
|
if (argv[argn][0] != '-') break;
|
|
optarg=0;
|
|
optc=argv[argn][1];
|
|
if (optc && argv[argn][2]) optarg=argv[argn]+2;
|
|
++argn;
|
|
switch (optc) {
|
|
case 'c':
|
|
if (!optarg && argn < argc)
|
|
optarg=argv[argn++];
|
|
if (optarg && *optarg)
|
|
rfc2045_setdefaultcharset(optarg);
|
|
break;
|
|
|
|
case 's':
|
|
if (!optarg && argn < argc)
|
|
optarg=argv[argn++];
|
|
if (optarg && *optarg) mimesection=optarg;
|
|
break;
|
|
case 'i':
|
|
doinfo=1;
|
|
break;
|
|
case 'e':
|
|
dodecode=1;
|
|
break;
|
|
case 'r':
|
|
dorewrite=1;
|
|
if (optarg && *optarg == '7')
|
|
rwmode=RFC2045_RW_7BIT;
|
|
if (optarg && *optarg == '8')
|
|
rwmode=RFC2045_RW_8BIT;
|
|
break;
|
|
case 'm':
|
|
domimedigest=1;
|
|
break;
|
|
case 'd':
|
|
dodsn=1;
|
|
break;
|
|
case 'D':
|
|
dodsn=2;
|
|
break;
|
|
case 'x':
|
|
do_extract=extract_file;
|
|
if (optarg)
|
|
extract_filename=optarg;
|
|
break;
|
|
case 'X':
|
|
do_extract=extract_pipe;
|
|
break;
|
|
case 'v':
|
|
printf("%s\n", rcsid);
|
|
exit(0);
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
|
|
if (domimedigest)
|
|
{
|
|
mimedigest(argc-argn, argv+argn);
|
|
return (0);
|
|
}
|
|
|
|
p=read_message();
|
|
|
|
if (doinfo)
|
|
print_info(p, mimesection);
|
|
else if (dodecode)
|
|
print_decode(p, mimesection);
|
|
else if (dorewrite)
|
|
rewrite(p, rwmode);
|
|
else if (dodsn)
|
|
dsn(p, dodsn == 2);
|
|
else if (do_extract)
|
|
extract_section(p, mimesection, extract_filename,
|
|
argc-argn, argv+argn, do_extract);
|
|
else
|
|
print_structure(p);
|
|
rfc2045_free(p);
|
|
exit(0);
|
|
return (0);
|
|
}
|