Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Alex Holst 2017-08-15 09:39:30 +02:00
commit 0839a3ecc2
14 changed files with 299 additions and 16 deletions

View File

@ -17,18 +17,18 @@ PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
MANDIR=$(PREFIX)/share/man
ALL = maddr magrep mdate mdeliver mdirs mexport mflag mgenmid mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
ALL = maddr magrep mdate mdeliver mdirs mexport mflag mflow mgenmid mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
SCRIPT = mcolor mcom mless mmkdir mquote museragent
all: $(ALL) museragent
$(ALL) : % : %.o
maddr magrep mdeliver mexport mflag mgenmid mhdr mpick mscan msed mshow \
maddr magrep mdeliver mexport mflag mflow mgenmid mhdr mpick mscan msed mshow \
msort mthread : blaze822.o mymemmem.o mytimegm.o
maddr magrep mexport mflag mgenmid mhdr mlist mpick mscan msed mseq mshow msort \
mthread : seq.o slurp.o
maddr magrep mhdr mpick mscan mshow : rfc2047.o
magrep mshow : rfc2045.o
maddr magrep mflow mhdr mpick mscan mshow : rfc2047.o
magrep mflow mshow : rfc2045.o
mshow : filter.o safe_u8putstr.o rfc2231.o pipeto.o
mscan : pipeto.o
msort : mystrverscmp.o

17
NEWS.md Normal file
View File

@ -0,0 +1,17 @@
## 0.2 (2017-07-17)
* New sequence syntax `m:+n` for `n` messages after message `m`.
* Threading shortcuts `=`, `_`, `^` for `.=`, `._`, `.^`.
* Sequence related errors are now reported.
* minc and mlist normalize slashes in paths.
* mfwd now generates conforming message/rfc822 parts.
* mthread can add optional folders (e.g. your outbox) to resolve message ids.
* mcom now adds Date: just before sending or cancelling the mail.
* VIOLATIONS.md documents how mblaze works with certain common mistakes.
* Full documentation revamp by Larry Hynes.
* Fix rare crash looking for mail body.
* Numerous small bug and portability fixes.
## 0.1 (2017-06-24)
* Initial release

1
README
View File

@ -18,6 +18,7 @@ DESCRIPTION
mdirs(1) find Maildir folders
mexport(1) export Maildir folders as mailboxes
mflag(1) change flags (marks) of mail
mflow(1) reflow format=flowed plain text mails
mfwd(1) forward mail
mgenmid(1) generate Message-IDs
mhdr(1) extract mail headers

View File

@ -1 +1 @@
0.1
0.2

View File

@ -8,9 +8,9 @@
mshow -t "$1" | awk -v "msg=$1" '
{ match($0, "^ *"); indent = RLENGTH }
$2 == "text/plain" { plain++ }
$2 == "multipart/signed" { signed = +$1; si = indent; next }
signed && !content && indent == si+2 { content = +$1; next }
signed && content && !signature && indent == si+2 { signature = +$1; type = $2 }
$2 == "multipart/signed" { signed = 0+$1; si = indent; next }
signed && !content && indent == si+2 { content = 0+$1; next }
signed && content && !signature && indent == si+2 { signature = 0+$1; type = $2 }
function q(a) { gsub("\\47", "\47\\\47\47", a); return "\47"a"\47" }
END {
if (type == "" && plain) { // guess plain text armored signature
@ -26,7 +26,7 @@ END {
exit(system("mshow -r -O " q(msg) " " q(signed) \
" | openssl smime -verify"))
} else {
print("Cant verify signatures of type " type ".")
print("Cannot verify signatures of type " type ".")
exit(2)
}
}

View File

@ -1,9 +1,13 @@
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@ -32,6 +36,10 @@ filter(char *input, size_t inlen, char *cmd, char **outputo, size_t *outleno)
if (pipe(pipe0) != 0 || pipe(pipe1) != 0)
goto fail;
int got = fcntl(pipe0[1], F_GETFL);
if (got > 0)
fcntl(pipe0[1], F_SETFL, got | O_NONBLOCK);
char *argv[] = { "/bin/sh", "-c", cmd, (char *)0 };
if (!(pid = fork())) {
@ -88,7 +96,9 @@ filter(char *input, size_t inlen, char *cmd, char **outputo, size_t *outleno)
input += ret;
inlen -= ret;
}
if (ret <= 0 || inlen == 0)
if (ret <= 0 && errno == EAGAIN) {
/* ignore */
} else if (ret <= 0 || inlen == 0)
close(fds[1].fd);
} else if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
fds[1].fd = -1;

View File

@ -1,3 +1,4 @@
text/plain: mflow
text/html: lynx -dump -stdin -nomargins ${PIPE_CHARSET:+-assume_charset $PIPE_CHARSET}
application/pdf: pdftotext - - | par
application: file -b -

View File

@ -30,6 +30,8 @@ find Maildir folders
export Maildir folders as mailboxes
.It Xr mflag 1
change flags (marks) of mail
.It Xr mflow 1
reflow format=flowed plain text mails
.It Xr mfwd 1
forward mail
.It Xr mgenmid 1

55
man/mflow.1 Normal file
View File

@ -0,0 +1,55 @@
.Dd July 26, 2017
.Dt MFLOW 1
.Os
.Sh NAME
.Nm mflow
.Nd reflow format=flowed plain text mails
.Sh SYNOPSIS
.Nm
\&<
.Ar file
.Sh DESCRIPTION
.Nm
reformats the standard input according to the rules
of RFC 3676.
.Ev PIPE_CONTENTTYPE
is inspected, making this a suitable filter
for
.Sq text/plain
messages for
.Xr mshow 1 .
Mails not using
.Sq format=flowed
are output as is.
.Pp
Text is reflowed (where allowed) to
fit the width given in the environment variable
.Ev COLUMNS ,
the terminal width, or 80 characters by default.
.Pp
If defined,
the environment variable
.Ev MAXCOLUMNS
specifies the maximum line length.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr mshow 1
.Rs
.%A R. Gellens
.%D February 2004
.%R RFC 3676
.%T The Text/Plain Format and DelSp Parameters
.Re
.Sh AUTHORS
.An Leah Neukirchen Aq Mt leah@vuxu.org
.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/

2
mcom
View File

@ -51,7 +51,7 @@ case "$0" in
shift
resume=1
if [ "$#" -gt 0 ]; then
echo "used dreaft $1"
echo "used draft $1"
draft="$1"
shift
fi

187
mflow.c Normal file
View File

@ -0,0 +1,187 @@
#include <sys/ioctl.h>
#include <sys/stat.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"
int column = 0;
int maxcolumn = 80;
void
chgquote(int quotes)
{
static int oquotes;
if (quotes != oquotes) {
if (column)
putchar('\n');
column = 0;
oquotes = quotes;
}
}
void
fixed(int quotes, char *line, size_t linelen)
{
chgquote(quotes);
if (linelen > (size_t)(maxcolumn - column)) {
putchar('\n');
column = 0;
}
if (column == 0) {
for (; column < quotes; column++)
putchar('>');
if (quotes)
putchar(' ');
}
fwrite(line, 1, linelen, stdout);
putchar('\n');
column = 0;
}
void
flowed(int quotes, char *line, ssize_t linelen)
{
chgquote(quotes);
int done = 0;
while (!done) {
if (column == 0) {
for (; column < quotes; column++)
putchar('>');
column++;
if (quotes)
putchar(' ');
}
char *eow;
if (*line == ' ')
eow = memchr(line + 1, ' ', linelen - 1);
else
eow = memchr(line, ' ', linelen);
if (!eow) {
eow = line + linelen;
done = 1;
}
if (column + (eow - line) > maxcolumn) {
putchar('\n');
column = 0;
if (*line == ' ') {
line++;
linelen--;
}
} else {
fwrite(line, 1, eow - line, stdout);
column += eow - line;
linelen -= eow - line;
line = eow;
}
}
}
int
main()
{
char *linebuf = 0;
char *line;
size_t linelen = 0;
int quotes = 0;
int reflow = 1; // re-evaluated on $PIPE_CONTENTTYPE
int delsp = 0;
char *ct = getenv("PIPE_CONTENTTYPE");
if (ct) {
char *s, *se;
blaze822_mime_parameter(ct, "format", &s, &se);
reflow = s && (strncasecmp(s, "flowed", 6) == 0);
blaze822_mime_parameter(ct, "delsp", &s, &se);
delsp = s && (strncasecmp(s, "yes", 3) == 0);
}
char *cols = getenv("COLUMNS");
if (cols && isdigit(*cols)) {
maxcolumn = atoi(cols);
} else {
struct winsize w;
int fd = open("/dev/tty", O_RDONLY | O_NOCTTY);
if (fd >= 0) {
if (ioctl(fd, TIOCGWINSZ, &w) == 0)
maxcolumn = w.ws_col;
close(fd);
}
}
char *maxcols = getenv("MAXCOLUMNS");
if (maxcols && isdigit(*maxcols)) {
int m = atoi(maxcols);
if (maxcolumn > m)
maxcolumn = m;
}
while (1) {
errno = 0;
ssize_t rd = getdelim(&linebuf, &linelen, '\n', stdin);
if (rd == -1) {
if (errno == 0)
break;
fprintf(stderr, "mflow: error reading: %s\n",
strerror(errno));
exit(1);
}
line = linebuf;
if (!reflow) {
fwrite(line, 1, rd, stdout);
continue;
}
if (rd > 0 && line[rd-1] == '\n')
line[--rd] = 0;
if (rd > 0 && line[rd-1] == '\r')
line[--rd] = 0;
quotes = 0;
while (*line == '>') { // measure quote depth
line++;
quotes++;
rd--;
}
if (*line == ' ') { // space stuffing
line++;
rd--;
}
if (strcmp(line, "-- ") == 0) { // usenet signature convention
if (column)
fixed(quotes, "", 0); // flush paragraph
fixed(quotes, line, rd);
continue;
}
if (rd > 0 && line[rd-1] == ' ') { // flowed line
if (delsp)
line[--rd] = 0;
flowed(quotes, line, rd);
} else {
fixed(quotes, line, rd);
}
}
if (reflow && column != 0)
putchar('\n');
}

6
mseq.c
View File

@ -252,6 +252,9 @@ stdinmode()
void
overridecur(char *file)
{
static int once = 0;
if (once++)
return;
while (*file == ' ')
file++;
setenv("MAILDOT", file, 1);
@ -260,6 +263,9 @@ overridecur(char *file)
void
setcur(char *file)
{
static int once = 0;
if (once++)
return;
while (*file == ' ')
file++;
unsetenv("MAILDOT");

View File

@ -29,6 +29,8 @@ static char *hflag = defaulthflags;
static char *xflag;
static char *Oflag;
static char fallback_ct[] = "text/plain";
struct message *filters;
static int mimecount;
@ -182,7 +184,7 @@ render_mime(int depth, struct message *msg, char *body, size_t bodylen)
{
char *ct = blaze822_hdr(msg, "content-type");
if (!ct)
ct = "text/x-unknown";
ct = fallback_ct;
char *mt = mimetype(ct);
char *tlmt = tlmimetype(ct);
char *filename = mime_filename(msg);
@ -310,7 +312,7 @@ choose_alternative(struct message *msg, int depth)
m++;
char *ict = blaze822_hdr(imsg, "content-type");
if (!ict)
ict = "text/x-unknown";
ict = fallback_ct;
char *imt = mimetype(ict);
char *s = strstr(Aflag, imt);
@ -367,7 +369,7 @@ list_mime(int depth, struct message *msg, char *body, size_t bodylen)
char *ct = blaze822_hdr(msg, "content-type");
if (!ct)
ct = "text/x-unknown";
ct = fallback_ct;
char *mt = mimetype(ct);
char *filename = mime_filename(msg);

View File

@ -75,7 +75,7 @@ blaze822_decode_b64(char *s, char *e, char **deco, size_t *decleno)
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
};
char *buf = malloc((e - s) / 4 * 3);
char *buf = malloc((e - s) / 4 * 3 + 1);
if (!buf)
return 0;
@ -118,6 +118,8 @@ error:
if (c3 != '=') *buf++ = d2;
}
*buf = 0;
*decleno = buf - *deco;
return 1;
}