add mexport

This commit is contained in:
Christian Neukirchen 2016-08-19 17:53:40 +02:00
parent 7c9a5c9c76
commit d71a1fbe44
6 changed files with 211 additions and 1 deletions

View File

@ -5,7 +5,7 @@ PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
MANDIR=$(PREFIX)/share/man
ALL = maddr magrep mdate mdeliver mdirs mflag mgenmid mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
ALL = maddr magrep mdate mdeliver mdirs mexport mflag mgenmid mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
SCRIPT = mcolor mcom mless mquote
all: $(ALL)
@ -15,6 +15,7 @@ magrep: magrep.o blaze822.o seq.o rfc2045.o rfc2047.o mymemmem.o mytimegm.o
mdate: mdate.o
mdeliver: mdeliver.o blaze822.o mymemmem.o mytimegm.o
mdirs: mdirs.o
mexport: mexport.c blaze822.o seq.o mymemmem.o mytimegm.o
mflag: mflag.o blaze822.o seq.o mymemmem.o mytimegm.o
mgenmid: mgenmid.o blaze822.o seq.o mymemmem.o mytimegm.o
mhdr: mhdr.o blaze822.o seq.o rfc2047.o mymemmem.o mytimegm.o

1
README
View File

@ -16,6 +16,7 @@ DESCRIPTION
mcom(1) to write and send mail
mdeliver(1) to deliver messages or import mailboxes
mdirs(1) to find Maildirs
mexport(1) to export mailboxes
mflag(1) to change flags (marks) of mail
mgenmid(1) to generate Message-IDs
mhdr(1) to extract mail headers

View File

@ -26,6 +26,8 @@ to write and send mail
to deliver messages or import mailboxes
.It Xr mdirs 1
to find Maildirs
.It Xr mexport 1
to export mailboxes
.It Xr mflag 1
to change flags (marks) of mail
.It Xr mgenmid 1

View File

@ -70,6 +70,7 @@ the flags of the new message file to be
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr mexport 1 ,
.Xr maildir 5 ,
.Xr mbox 5
.Pp

66
man/mexport.1 Normal file
View File

@ -0,0 +1,66 @@
.Dd August 19, 2016
.Dt MEXPORT 1
.Os
.Sh NAME
.Nm mexport
.Nd export messages as mbox file
.Sh SYNOPSIS
.Nm
.Op Fl S
.Ar msgs\ ...
.Sh DESCRIPTION
.Nm
exports the given messages as a MBOXRD file to standard output.
See
.Xr mmsg 7
for the message argument syntax.
.Pp
If no
.Ar msgs
are passed,
.Nm
reads file names from standard input,
or uses the mails in the current sequence when used interactively.
.Pp
.Nm
uses the
.Sq Li "Return-Path:"
(or
.Sq Li "X-Envelope-To:" )
and the
.Sq Li "Date:"
from the message for the
.Sq Li "From "
line.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl S
Add
.Sq Li "Status:"
and
.Sq Li "X-Status:"
headers according to the Maildir flags.
.El
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr mdeliver 1 ,
.Xr maildir 5 ,
.Xr mbox 5
.Pp
.Lk http://www.digitalpreservation.gov/formats/fdd/fdd000385.shtml "MBOXRD Email Format"
.Pp
.Lk https://cr.yp.to/proto/maildir.html "Using maildir format"
.Sh AUTHORS
.An Christian Neukirchen Aq Mt chneukirchen@gmail.com
.Sh LICENSE
.Nm
is in the public domain.
.Pp
To the extent possible under law,
the creator of this work
has waived all copyright and related or
neighboring rights to this work.
.Pp
.Lk http://creativecommons.org/publicdomain/zero/1.0/

139
mexport.c Normal file
View File

@ -0,0 +1,139 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "blaze822.h"
static int Sflag;
static int status;
void
export(char *file)
{
struct message *msg;
while (*file == ' ' || *file == '\t')
file++;
msg = blaze822(file);
if (!msg)
return;
char from[1024] = "nobody";
char *v;
if ((v = blaze822_hdr(msg, "return-path")) ||
(v = blaze822_hdr(msg, "x-envelope-from"))) {
char *s = strchr(v, '<');
char *e = strchr(s, '>');
if (s && e) {
e++;
memcpy(from, s, e-s);
from[e-s] = 0;
}
}
time_t date = -1;
if ((v = blaze822_hdr(msg, "date"))) {
date = blaze822_date(v);
}
char *line = 0;
size_t linelen = 0;
FILE *infile = fopen(file, "r");
if (!infile) {
status = 1;
return;
}
printf("From %s %s", from, ctime(&date));
int in_header = 1;
int final_nl = 0;
while (1) {
errno = 0;
ssize_t rd = getline(&line, &linelen, infile);
if (rd == -1) {
if (errno == 0)
break;
// XXX print error?
status = 1;
return;
}
if (in_header && line[0] == '\n' && !line[1]) {
if (Sflag) {
char *flags = strstr(file, ":2,");
if (!flags)
flags = "";
fputs("Status: ", stdout);
if (strchr(flags, 'S'))
putchar('R');
char *ee = strrchr(file, '/');
if (!ee ||
!(ee >= file + 3 && ee[-3] == 'n' && ee[-2] == 'e' && ee[-1] == 'w'))
putchar('O');
putchar('\n');
fputs("X-Status: ", stdout);
if (strchr(flags, 'R')) putchar('A');
if (strchr(flags, 'T')) putchar('D');
if (strchr(flags, 'F')) putchar('F');
putchar('\n');
}
in_header = 0;
}
// MBOXRD: add first > to >>..>>From
char *s = line;
while (*s == '>')
s++;
if (strncmp("From ", s, 5) == 0)
putchar('>');
fputs(line, stdout);
final_nl = (line[rd-1] == '\n');
}
// ensure trailing newline
if (!final_nl)
putchar('\n');
fclose(infile);
blaze822_free(msg);
}
int
main(int argc, char *argv[])
{
int c;
while ((c = getopt(argc, argv, "S")) != -1)
switch(c) {
case 'S': Sflag = 1; break;
default:
fprintf(stderr, "Usage: mexport [-S] [msgs...]\n");
exit(2);
}
status = 0;
if (argc == optind && isatty(0))
blaze822_loop1(":", export);
else
blaze822_loop(argc-optind, argv+optind, export);
return status;
}