pull/2/head
Christian Neukirchen 8 years ago
parent 0ce958a22c
commit 3316cfbc22

@ -1,6 +1,6 @@
CFLAGS=-g -O1 -Wall -Wno-switch -Wextra -fstack-protector-strong -D_FORTIFY_SOURCE=2
ALL = maddr mdeliver mdirs mflag mhdr minc mlist mmime mpick mscan mseq mshow msort mthread
ALL = maddr mdeliver mdirs mflag mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
all: $(ALL)
@ -14,6 +14,7 @@ mlist: mlist.o
mmime: mmime.o
mpick: mpick.o blaze822.o seq.o rfc2047.c mymemmem.o
mscan: mscan.o blaze822.o seq.o rfc2047.o mymemmem.o
msed: msed.o blaze822.o seq.o mymemmem.o
mseq: mseq.o seq.o
mshow: mshow.o blaze822.o seq.o rfc2045.o rfc2047.c mymemmem.o filter.o
msort: msort.o blaze822.o seq.o mystrverscmp.o mymemmem.o

@ -24,6 +24,7 @@ DESCRIPTION
mpick(1) to filter mail
mrepl(1) to reply to mail
mscan(1) to generate single line summaries of mail
msed(1) to manipulate mail headers
mseq(1) to manipulate mail sequences
mshow(1) to render mail and extract attachments
msort(1) to sort mail
@ -52,10 +53,11 @@ PRINCIPLES
nonconforming, messages.
Santoku is written in portable C, using only POSIX functions (apart from
a tiny Linux-only optimization). It supports MIME and more than 7-bit
messages (everything the host iconv(3) can decode). It assumes you work
in a UTF-8 environment. Santoku works well together with other Unix mail
tools such as offlineimap(1), mairix(1), or mu(1).
a tiny Linux-only optimization), and has no external dependencies. It
supports MIME and more than 7-bit messages (everything the host iconv(3)
can decode). It assumes you work in a UTF-8 environment. Santoku works
well together with other Unix mail tools such as offlineimap(1),
mairix(1), or mu(1).
EXAMPLES
Santoku tools are designed to be composed together into a pipe. It is

@ -46,6 +46,8 @@ to filter mail
to reply to mail
.It Xr mscan 1
to generate single line summaries of mail
.It Xr msed 1
to manipulate mail headers
.It Xr mseq 1
to manipulate mail sequences
.It Xr mshow 1

293
msed.c

@ -0,0 +1,293 @@
#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 <regex.h>
#include <unistd.h>
#include "blaze822.h"
static char *expr;
char *
subst(char *str, char *srch, char *repl, char *flags)
{
static char buf[4096];
char *bufe = buf + sizeof buf;
int iflag = !!strchr(flags, 'i');
int gflag = !!strchr(flags, 'g');
#define APP(o,l) do {if(bufe-b<(ssize_t)l) return str; memcpy(b,str+i+o,l); b+=l;} while(0)
#define APPC(c) do {if(b>=bufe) return str; *b++=c;} while(0)
regex_t srchrx;
regmatch_t pmatch[10];
if (regcomp(&srchrx, srch, iflag ? REG_ICASE : 0) != 0)
return str;
char *b = buf;
regoff_t i = 0;
while (1) {
if (regexec(&srchrx, str+i, 9, pmatch, 0) != 0)
break;
APP(0, pmatch[0].rm_so);
char *t = repl;
while (*t) {
// & == \0
if (*t == '&' || (*t == '\\' && isdigit(*(t+1)))) {
int n;
if (*t == '&') {
t++;
n = 0;
} else {
t++;
n = *t++ - '0';
}
APP(pmatch[n].rm_so,
pmatch[n].rm_eo - pmatch[n].rm_so);
} else if (*t == '\\' && *(t+1)) {
t++;
APPC(*t++);
} else {
APPC(*t++);
}
}
i += pmatch[0].rm_eo; // advance to end of match
if (!gflag)
break;
}
if (i > 0) { // any match?
APP(0, strlen(str + i));
*b = 0;
return buf;
}
return str;
}
void
printhdr(char *hdr, int rest)
{
int uc = 1;
while (*hdr && *hdr != ':') {
putc(uc ? toupper(*hdr) : *hdr, stdout);
uc = (*hdr == '-');
hdr++;
}
if (rest) {
printf("%s\n", hdr);
}
}
void
sed(char *file)
{
struct message *msg = blaze822_file(file);
if (!msg)
return;
char *h = 0;
while ((h = blaze822_next_header(msg, h))) {
regex_t headerrx;
char headersel[1024];
char *v = strchr(h, ':');
if (!v)
continue;
v++;
while (*v && (*v == ' ' || *v == '\t'))
v++;
v = strdup(v);
char *e = expr;
while (*e) {
while (*e &&
(*e == ' ' || *e == '\t' || *e == '\n' || *e == ';'))
e++;
*headersel = 0;
if (*e == '/') {
e++;
char *s = e;
// parse_headers, sets headersel
while (*e && *e != '/')
e++;
snprintf(headersel, sizeof headersel,
"^(%.*s)*:", e-s, s);
for (s = headersel; *s && *(s+1); s++)
if (*s == ':')
*s = '|';
regcomp(&headerrx, headersel, REG_EXTENDED);
if (*e)
e++;
}
char sep;
char *s;
if (!*headersel || regexec(&headerrx, h, 0, 0, 0) == 0) {
switch (*e) {
case 'd':
free(v);
v = 0;
break;
case 'a':
// skipped here;
sep = *++e;
if (!sep) {
fprintf(stderr, "unterminated a command\n");
exit(1);
}
while (*e && *e != sep)
e++;
break;
if (!(*e == ' ' || *e == ';' || *e == '\n' || !*e)) {
fprintf(stderr, "unterminated a command\n");
exit(1);
}
case 'c':
sep = *++e;
s = ++e;
while (*e && *e != sep)
e++;
free(v);
v = strndup(s, e-s);
break;
case 's':
sep = *++e;
s = ++e;
while (*e && *e != sep)
e++;
char *t = ++e;
while (*e && *e != sep)
e++;
char *u = ++e;
while (*e == 'i' || *e == 'g')
e++;
if (!(*e == ' ' || *e == ';' || *e == '\n' || !*e)) {
fprintf(stderr, "unterminated s command\n");
exit(1);
}
// XXX stack allocate
char *from = strndup(s, t-s-1);
char *to = strndup(t, u-t-1);
char *flags = strndup(u, e-u);
char *ov = v;
v = strdup(subst(ov, from, to, flags));
free(ov);
free(from);
free(to);
free(flags);
break;
default:
fprintf(stderr, "unknown command: '%c'\n", *e);
exit(1);
}
}
while (*e && *e != ';')
e++;
}
if (v) {
printhdr(h, 0);
printf(": %s\n", v);
free(v);
}
}
// loop, do all a//
char *hs, *he;
char *e = expr;
while (*e) {
while (*e &&
(*e == ' ' || *e == '\t' || *e == '\n' || *e == ';'))
e++;
hs = he = 0;
if (*e == '/') {
e++;
hs = e;
// parse_headers, sets headersel
while (*e && *e != '/')
e++;
he = e;
if (*e)
e++;
}
char sep;
char *s;
switch (*e) {
case 'a':
sep = *++e;
if (!sep) {
fprintf(stderr, "unterminated a command\n");
exit(1);
}
s = ++e;
while (*e && *e != sep)
e++;
if (he != hs) {
char *h = strndup(hs, he-hs);
char *v = strndup(s, e-s);
printhdr(h, 0);
printf(": %s\n", v);
}
break;
case 'c':
case 'd':
case 's':
// ignore here;
break;
}
while (*e && *e != ';')
e++;
}
printf("\n");
fwrite(blaze822_body(msg), 1, blaze822_bodylen(msg), stdout);
}
int
main(int argc, char *argv[])
{
int c;
while ((c = getopt(argc, argv, "")) != -1)
switch(c) {
default:
fprintf(stderr, "Usage: msed [expr] [msgs...]\n");
exit(1);
}
expr = argv[optind];
optind++;
if (argc == optind && isatty(0))
blaze822_loop1(".", sed);
else
blaze822_loop(argc-optind, argv+optind, sed);
return 0;
}
Loading…
Cancel
Save