2018-01-06 22:26:05 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
#include <dirent.h>
|
2016-07-26 14:55:55 +00:00
|
|
|
#include <errno.h>
|
2018-01-06 22:26:05 +00:00
|
|
|
#include <fcntl.h>
|
2016-07-26 13:50:57 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <search.h>
|
2016-07-16 16:45:39 +00:00
|
|
|
#include <stdio.h>
|
2016-07-18 15:06:41 +00:00
|
|
|
#include <stdlib.h>
|
2017-08-31 15:30:17 +00:00
|
|
|
#include <string.h>
|
2016-07-18 15:06:41 +00:00
|
|
|
#include <unistd.h>
|
2016-07-16 16:45:39 +00:00
|
|
|
|
2016-07-17 19:51:41 +00:00
|
|
|
#include "blaze822.h"
|
2020-03-08 16:20:29 +00:00
|
|
|
#include "blaze822_priv.h"
|
2016-07-16 16:45:39 +00:00
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
static int fflag;
|
2016-07-22 14:51:47 +00:00
|
|
|
static int rflag;
|
2016-07-26 14:25:40 +00:00
|
|
|
static int Aflag;
|
2016-08-09 17:10:12 +00:00
|
|
|
static char *cflag;
|
2016-07-26 15:14:28 +00:00
|
|
|
static char *Cflag;
|
|
|
|
static int Sflag;
|
2016-07-20 11:46:39 +00:00
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
struct name {
|
|
|
|
char *id;
|
|
|
|
char *file;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *names;
|
|
|
|
|
|
|
|
int
|
|
|
|
nameorder(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
struct name *ia = (struct name *)a;
|
|
|
|
struct name *ib = (struct name *)b;
|
|
|
|
|
|
|
|
return strcmp(ia->id, ib->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
namefind(char *id)
|
|
|
|
{
|
|
|
|
struct name key, **result;
|
|
|
|
key.id = id;
|
|
|
|
|
|
|
|
if (!(result = tfind(&key, &names, nameorder)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (*result)->file;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
namescan(char *dir)
|
|
|
|
{
|
|
|
|
DIR *fd;
|
|
|
|
struct dirent *d;
|
|
|
|
|
|
|
|
fd = opendir(dir);
|
|
|
|
if (!fd)
|
|
|
|
return;
|
|
|
|
while ((d = readdir(fd))) {
|
2020-03-08 16:20:29 +00:00
|
|
|
if (!MAIL_DT(d->d_type))
|
2016-07-26 13:50:57 +00:00
|
|
|
continue;
|
2020-03-08 16:20:29 +00:00
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
if (d->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
char file[PATH_MAX];
|
|
|
|
snprintf(file, sizeof file, "%s/%s", dir, d->d_name);
|
|
|
|
|
|
|
|
char *e;
|
|
|
|
if ((e = strstr(d->d_name, ":2,")))
|
|
|
|
*e = 0;
|
|
|
|
|
|
|
|
struct name *c = malloc(sizeof (struct name));
|
|
|
|
c->id = strdup(d->d_name);
|
|
|
|
c->file = strdup(file);
|
|
|
|
tsearch(c, &names, nameorder);
|
|
|
|
}
|
|
|
|
closedir(fd);
|
|
|
|
|
|
|
|
// add dir so know we scanned it already
|
|
|
|
struct name *c = malloc(sizeof (struct name));
|
|
|
|
c->id = c->file = strdup(dir);
|
|
|
|
tsearch(c, &names, nameorder);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
search(char *file)
|
|
|
|
{
|
|
|
|
char dir[PATH_MAX];
|
|
|
|
char *e;
|
|
|
|
if ((e = strrchr(file, '/'))) {
|
|
|
|
snprintf(dir, sizeof dir, "%.*s", (int)(e-file), file);
|
|
|
|
file = e+1;
|
|
|
|
} else {
|
|
|
|
snprintf(dir, sizeof dir, ".");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!namefind(dir))
|
|
|
|
namescan(dir);
|
|
|
|
|
2017-06-24 22:11:06 +00:00
|
|
|
if ((e = strstr(file, ":2,")))
|
|
|
|
*e = 0;
|
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
return namefind(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strategy to find a Maildir file name:
|
|
|
|
- if file exists, all good
|
|
|
|
- try a few common different flags
|
|
|
|
- index the containing dir, try to search for the id
|
|
|
|
- if its in new/, try the same in cur/
|
|
|
|
*/
|
|
|
|
int
|
2016-07-26 14:25:40 +00:00
|
|
|
fix(FILE *out, char *file)
|
2016-07-26 13:50:57 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; *file == ' '; i++, file++)
|
|
|
|
;
|
|
|
|
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
char *bufptr = buf;
|
|
|
|
|
|
|
|
if (*file == '<' || access(file, F_OK) == 0) {
|
|
|
|
bufptr = file;
|
|
|
|
goto ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *e;
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
if ((e = strstr(file, ":2,"))) {
|
|
|
|
sep = "";
|
|
|
|
e[3] = 0;
|
|
|
|
} else {
|
|
|
|
sep = ":2,";
|
|
|
|
}
|
|
|
|
snprintf(buf, sizeof buf, "%s%s", file, sep);
|
|
|
|
if (access(buf, F_OK) == 0) goto ok;
|
|
|
|
snprintf(buf, sizeof buf, "%s%sS", file, sep);
|
|
|
|
if (access(buf, F_OK) == 0) goto ok;
|
|
|
|
snprintf(buf, sizeof buf, "%s%sRS", file, sep);
|
|
|
|
if (access(buf, F_OK) == 0) goto ok;
|
|
|
|
snprintf(buf, sizeof buf, "%s%sFS", file, sep);
|
|
|
|
if (access(buf, F_OK) == 0) goto ok;
|
|
|
|
|
|
|
|
if ((bufptr = search(file))) goto ok;
|
|
|
|
|
|
|
|
char *ee = strrchr(file, '/');
|
|
|
|
if (ee >= file + 3 && ee[-3] == 'n' && ee[-2] == 'e' && ee[-1] == 'w') {
|
|
|
|
ee[-3] = 'c'; ee[-2] = 'u'; ee[-1] = 'r';
|
2016-07-26 16:02:10 +00:00
|
|
|
return fix(out, file-i);
|
2016-07-26 13:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
ok:
|
2017-08-31 15:30:17 +00:00
|
|
|
while (i--)
|
2016-07-26 14:25:40 +00:00
|
|
|
putc(' ', out);
|
|
|
|
fprintf(out, "%s\n", bufptr);
|
2016-07-26 13:50:57 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-07-26 14:25:40 +00:00
|
|
|
void
|
|
|
|
cat(FILE *src, FILE *dst)
|
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
size_t rd;
|
|
|
|
|
|
|
|
rewind(src);
|
|
|
|
while ((rd = fread(buf, 1, sizeof buf, src)) > 0)
|
|
|
|
fwrite(buf, 1, rd, dst);
|
|
|
|
if (!feof(src)) {
|
2017-02-18 15:46:34 +00:00
|
|
|
perror("mseq: fread");
|
2016-07-26 14:25:40 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
int
|
|
|
|
stdinmode()
|
|
|
|
{
|
|
|
|
char *line = 0;
|
|
|
|
char *l;
|
|
|
|
size_t linelen = 0;
|
|
|
|
ssize_t rd;
|
2016-07-26 14:25:40 +00:00
|
|
|
FILE *outfile;
|
|
|
|
|
|
|
|
char tmpfile[PATH_MAX];
|
|
|
|
char oldfile[PATH_MAX];
|
|
|
|
char *seqfile = 0;
|
|
|
|
|
|
|
|
if (Sflag) {
|
2016-07-26 14:55:55 +00:00
|
|
|
seqfile = getenv("MAILSEQ");
|
2016-07-26 14:25:40 +00:00
|
|
|
if (!seqfile)
|
2016-09-01 23:50:20 +00:00
|
|
|
seqfile = blaze822_home_file("seq");
|
2016-07-26 14:25:40 +00:00
|
|
|
snprintf(tmpfile, sizeof tmpfile, "%s-", seqfile);
|
|
|
|
snprintf(oldfile, sizeof oldfile, "%s.old", seqfile);
|
2018-01-06 22:26:05 +00:00
|
|
|
int fd = open(tmpfile, O_RDWR | O_EXCL | O_CREAT, 0666);
|
|
|
|
if (fd < 0) {
|
2017-02-18 15:46:34 +00:00
|
|
|
fprintf(stderr,
|
2018-01-06 22:26:05 +00:00
|
|
|
"mseq: Could not create temporary sequence file '%s': %s.\n",
|
|
|
|
tmpfile, strerror(errno));
|
2017-02-18 15:46:34 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"mseq: Ensure %s exists and is writable.\n",
|
|
|
|
blaze822_home_file(""));
|
2016-07-26 14:25:40 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2018-01-06 22:26:05 +00:00
|
|
|
outfile = fdopen(fd, "w+");
|
2016-07-26 14:25:40 +00:00
|
|
|
if (Aflag) {
|
|
|
|
FILE *seq = fopen(seqfile, "r");
|
|
|
|
if (seq) {
|
|
|
|
cat(seq, outfile);
|
|
|
|
fclose(seq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
outfile = stdout;
|
|
|
|
}
|
2016-07-26 13:50:57 +00:00
|
|
|
|
2016-09-05 12:20:55 +00:00
|
|
|
while ((rd = getdelim(&line, &linelen, '\n', stdin)) != -1) {
|
2016-07-26 13:50:57 +00:00
|
|
|
if (line[rd-1] == '\n')
|
|
|
|
line[rd-1] = 0;
|
|
|
|
|
|
|
|
l = line;
|
|
|
|
if (rflag)
|
|
|
|
while (*l == ' ' || *l == '\t')
|
|
|
|
l++;
|
|
|
|
if (fflag)
|
2016-07-26 14:25:40 +00:00
|
|
|
fix(outfile, l);
|
2016-07-26 13:50:57 +00:00
|
|
|
else
|
2016-07-26 14:25:40 +00:00
|
|
|
fprintf(outfile, "%s\n", l);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Sflag) {
|
|
|
|
fflush(outfile);
|
2016-07-26 14:55:55 +00:00
|
|
|
if (rename(seqfile, oldfile) < 0 && errno != ENOENT) {
|
2017-02-18 15:46:34 +00:00
|
|
|
perror("mseq: rename");
|
2016-07-26 14:25:40 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
if (rename(tmpfile, seqfile) < 0) {
|
2017-02-18 15:46:34 +00:00
|
|
|
perror("mseq: rename");
|
2016-07-26 14:25:40 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isatty(1))
|
|
|
|
cat(outfile, stdout);
|
|
|
|
|
|
|
|
fclose(outfile);
|
2016-07-26 13:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(line);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-09 17:10:12 +00:00
|
|
|
void
|
|
|
|
overridecur(char *file)
|
|
|
|
{
|
2017-07-17 12:18:25 +00:00
|
|
|
static int once = 0;
|
|
|
|
if (once++)
|
|
|
|
return;
|
2016-08-09 17:10:12 +00:00
|
|
|
while (*file == ' ')
|
|
|
|
file++;
|
|
|
|
setenv("MAILDOT", file, 1);
|
|
|
|
}
|
|
|
|
|
2016-07-27 12:57:15 +00:00
|
|
|
void
|
2016-07-28 11:49:00 +00:00
|
|
|
setcur(char *file)
|
2016-07-27 12:57:15 +00:00
|
|
|
{
|
2017-07-17 12:18:25 +00:00
|
|
|
static int once = 0;
|
|
|
|
if (once++)
|
|
|
|
return;
|
2016-07-28 11:49:00 +00:00
|
|
|
while (*file == ' ')
|
|
|
|
file++;
|
2016-08-09 17:16:19 +00:00
|
|
|
unsetenv("MAILDOT");
|
2016-07-28 11:49:00 +00:00
|
|
|
blaze822_seq_setcur(file);
|
2016-07-27 12:57:15 +00:00
|
|
|
}
|
|
|
|
|
2016-07-16 16:45:39 +00:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
2016-07-20 11:46:39 +00:00
|
|
|
int c;
|
2016-08-09 17:03:59 +00:00
|
|
|
while ((c = getopt(argc, argv, "c:frAC:S")) != -1)
|
2017-08-31 15:30:17 +00:00
|
|
|
switch (c) {
|
2016-08-09 17:10:12 +00:00
|
|
|
case 'c': cflag = optarg; break;
|
2016-07-26 13:50:57 +00:00
|
|
|
case 'f': fflag = 1; break;
|
2016-07-22 14:51:47 +00:00
|
|
|
case 'r': rflag = 1; break;
|
2016-07-26 14:25:40 +00:00
|
|
|
case 'A': Sflag = Aflag = 1; break;
|
2016-07-26 15:14:28 +00:00
|
|
|
case 'C': Cflag = optarg; break;
|
|
|
|
case 'S': Sflag = 1; break;
|
2016-07-20 11:46:39 +00:00
|
|
|
default:
|
2017-08-31 15:30:17 +00:00
|
|
|
usage:
|
2016-07-26 20:09:02 +00:00
|
|
|
fprintf(stderr,
|
2016-08-09 17:10:12 +00:00
|
|
|
"Usage: mseq [-fr] [-c msg] [msgs...]\n"
|
2017-01-26 19:27:26 +00:00
|
|
|
" mseq -S [-fr] < sequence\n"
|
|
|
|
" mseq -A [-fr] < sequence\n"
|
|
|
|
" mseq -C msg\n"
|
2016-07-26 20:09:02 +00:00
|
|
|
);
|
2016-07-20 11:46:39 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2016-08-09 17:10:12 +00:00
|
|
|
if (cflag)
|
|
|
|
blaze822_loop1(cflag, overridecur);
|
|
|
|
|
2016-07-26 15:14:28 +00:00
|
|
|
if (Cflag) {
|
2016-07-27 12:57:15 +00:00
|
|
|
blaze822_loop1(Cflag, setcur);
|
2016-07-26 15:14:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-26 14:25:40 +00:00
|
|
|
if (Sflag && optind != argc) {
|
2016-07-26 20:09:02 +00:00
|
|
|
fprintf(stderr, "error: -S/-A doesn't take arguments.\n");
|
|
|
|
goto usage;
|
2016-07-26 14:25:40 +00:00
|
|
|
}
|
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
if (optind == argc && !isatty(0))
|
|
|
|
return stdinmode();
|
|
|
|
|
2016-07-26 14:55:55 +00:00
|
|
|
char *seq = blaze822_seq_open(0);
|
|
|
|
if (!seq)
|
2016-07-16 16:45:39 +00:00
|
|
|
return 1;
|
|
|
|
|
2016-07-17 22:09:23 +00:00
|
|
|
int i;
|
|
|
|
char *f;
|
2016-07-20 13:38:24 +00:00
|
|
|
char *a;
|
2016-07-17 22:09:23 +00:00
|
|
|
struct blaze822_seq_iter iter = { 0 };
|
2016-07-20 13:38:24 +00:00
|
|
|
|
2016-07-26 13:50:57 +00:00
|
|
|
if (optind == argc) {
|
2016-07-20 13:38:24 +00:00
|
|
|
a = ":";
|
|
|
|
i = argc;
|
|
|
|
goto hack;
|
|
|
|
}
|
2016-07-20 11:46:39 +00:00
|
|
|
for (i = optind; i < argc; i++) {
|
2016-07-20 13:38:24 +00:00
|
|
|
a = argv[i];
|
|
|
|
hack:
|
|
|
|
if (strchr(a, '/')) {
|
|
|
|
printf("%s\n", a);
|
2016-07-20 12:15:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-07-26 14:55:55 +00:00
|
|
|
while ((f = blaze822_seq_next(seq, a, &iter))) {
|
2016-07-31 17:46:43 +00:00
|
|
|
char *s = f;
|
|
|
|
if (rflag)
|
|
|
|
while (*s == ' ' || *s == '\t')
|
|
|
|
s++;
|
|
|
|
if (fflag)
|
|
|
|
fix(stdout, s);
|
|
|
|
else
|
|
|
|
printf("%s\n", s);
|
2016-07-17 22:09:23 +00:00
|
|
|
free(f);
|
2016-07-16 16:45:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|