Skip to content

Commit d21e59c

Browse files
committed
neatmail: the birth
This is my new attempt to create a neat mail client. Some of the code is based on my old mailx clone.
0 parents  commit d21e59c

File tree

10 files changed

+1180
-0
lines changed

10 files changed

+1180
-0
lines changed

Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CC = cc
2+
CFLAGS = -Wall -O2
3+
LDFLAGS =
4+
OBJS = mail.o ex.o mk.o mbox.o msg.o util.o sbuf.o
5+
6+
all: mail
7+
%.o: %.c mail.h
8+
$(CC) -c $(CFLAGS) $<
9+
mail: $(OBJS)
10+
$(CC) -o $@ $(OBJS) $(LDFLAGS)
11+
clean:
12+
rm -f *.o mail

README

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
NEATMAIL
2+
========
3+
4+
Neatmail is a mail client.

ex.c

+356
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
#include <ctype.h>
2+
#include <fcntl.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
#include <unistd.h>
7+
#include <sys/stat.h>
8+
#include "mail.h"
9+
#include "regex.h"
10+
11+
#define EXLEN 512
12+
13+
static struct mbox *mbox;
14+
static int pos;
15+
static char kwd[EXLEN];
16+
static char kwd_hdr[EXLEN];
17+
static regex_t kwd_re;
18+
19+
static char *ex_loc(char *s, char *loc)
20+
{
21+
while (*s == ':' || isspace((unsigned char) *s))
22+
s++;
23+
while (*s && !isalpha((unsigned char) *s)) {
24+
if (*s == '/' || *s == '?') {
25+
int d = *s;
26+
*loc++ = *s++;
27+
while (*s && *s != d) {
28+
if (*s == '\\' && s[1])
29+
*loc++ = *s++;
30+
*loc++ = *s++;
31+
}
32+
}
33+
if (*s)
34+
*loc++ = *s++;
35+
}
36+
*loc = '\0';
37+
return s;
38+
}
39+
40+
static char *ex_cmd(char *s, char *cmd)
41+
{
42+
while (isspace((unsigned char) *s))
43+
s++;
44+
while (isalpha((unsigned char) *s))
45+
*cmd++ = *s++;
46+
*cmd = '\0';
47+
return s;
48+
}
49+
50+
static char *ex_arg(char *s, char *arg)
51+
{
52+
while (isspace((unsigned char) *s))
53+
s++;
54+
if (*s == '"') {
55+
s++;
56+
while (*s && *s != '"') {
57+
if (*s == '\\' && s[1])
58+
s++;
59+
*arg++ = *s++;
60+
}
61+
s++;
62+
} else {
63+
while (*s && !isspace((unsigned char) *s)) {
64+
if (*s == '\\' && s[1])
65+
s++;
66+
*arg++ = *s++;
67+
}
68+
}
69+
*arg = '\0';
70+
return s;
71+
}
72+
73+
static int ex_keyword(char *pat)
74+
{
75+
struct sbuf *sb;
76+
char *b = pat;
77+
char *e = b;
78+
regex_t re;
79+
sb = sbuf_make();
80+
while (*++e) {
81+
if (*e == *pat)
82+
break;
83+
sbuf_chr(sb, (unsigned char) *e);
84+
if (*e == '\\' && e[1])
85+
e++;
86+
}
87+
if (sbuf_len(sb)) {
88+
if (kwd[0])
89+
regfree(&kwd_re);
90+
snprintf(kwd, sizeof(kwd), "%s", sbuf_buf(sb));
91+
if (regcomp(&re, kwd, REG_EXTENDED | REG_ICASE))
92+
kwd[0] = '\0';
93+
}
94+
sbuf_free(sb);
95+
if (kwd[0] == '^' && isalpha((unsigned char) (kwd[1])) &&
96+
strchr(kwd, ':')) {
97+
int len = strchr(kwd, ':') - kwd;
98+
memcpy(kwd_hdr, kwd + 1, len);
99+
kwd_hdr[len] = '\n';
100+
} else {
101+
strcpy(kwd_hdr, "subject:");
102+
}
103+
return !kwd[0];
104+
}
105+
106+
static int ex_match(int i)
107+
{
108+
char *msg;
109+
long msglen;
110+
char *hdr;
111+
char *buf;
112+
int len, ret;
113+
if (i < 0 || i >= mbox_len(mbox))
114+
return 1;
115+
mbox_get(mbox, i, &msg, &msglen);
116+
hdr = msg_get(msg, msglen, kwd_hdr);
117+
if (!hdr)
118+
return 1;
119+
len = hdrlen(hdr, msg + msglen - hdr);
120+
buf = malloc(len + 1);
121+
memcpy(buf, hdr, len);
122+
buf[len] = '\0';
123+
ret = regexec(&kwd_re, buf, 0, NULL, 0);
124+
free(buf);
125+
return ret != 0;
126+
}
127+
128+
static int ex_search(char *pat)
129+
{
130+
int dir = *pat == '/' ? +1 : -1;
131+
int i = pos + dir;
132+
if (ex_keyword(pat))
133+
return 1;
134+
while (i >= 0 && i < mbox_len(mbox)) {
135+
if (!ex_match(i))
136+
return i;
137+
i += dir;
138+
}
139+
return pos;
140+
}
141+
142+
static int ex_lineno(char *num)
143+
{
144+
int n = pos;
145+
if (!num[0] || num[0] == '.')
146+
n = pos;
147+
if (isdigit(num[0]))
148+
n = atoi(num);
149+
if (num[0] == '$')
150+
n = mbox_len(mbox) - 1;
151+
if (num[0] == '-')
152+
n = pos - (num[1] ? ex_lineno(num + 1) : 1);
153+
if (num[0] == '+')
154+
n = pos + (num[1] ? ex_lineno(num + 1) : 1);
155+
if (num[0] == '/' && num[1])
156+
n = ex_search(num);
157+
if (num[0] == '?' && num[1])
158+
n = ex_search(num);
159+
return n;
160+
}
161+
162+
static int ex_region(char *loc, int *beg, int *end)
163+
{
164+
if (loc[0] == '%') {
165+
*beg = 0;
166+
*end = mbox_len(mbox);
167+
return 0;
168+
}
169+
if (!*loc || loc[0] == ';') {
170+
*beg = pos;
171+
*end = pos == mbox_len(mbox) ? pos : pos + 1;
172+
return 0;
173+
}
174+
*beg = ex_lineno(loc);
175+
while (*loc && *loc != ',' && *loc != ';')
176+
loc++;
177+
if (*loc == ',')
178+
*end = ex_lineno(++loc);
179+
else
180+
*end = *beg == mbox_len(mbox) ? *beg : *beg + 1;
181+
if (*beg < 0 || *beg >= mbox_len(mbox))
182+
return 1;
183+
if (*end < *beg || *end > mbox_len(mbox))
184+
return 1;
185+
return 0;
186+
}
187+
188+
static int ec_rm(char *arg)
189+
{
190+
mbox_set(mbox, pos, "", 0);
191+
return 0;
192+
}
193+
194+
static int ec_cp(char *arg)
195+
{
196+
char box[EXLEN];
197+
char *msg;
198+
long msz;
199+
int fd;
200+
arg = ex_arg(arg, box);
201+
fd = open(box, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
202+
mbox_get(mbox, pos, &msg, &msz);
203+
xwrite(fd, msg, msz);
204+
close(fd);
205+
return 0;
206+
}
207+
208+
static int ec_mv(char *arg)
209+
{
210+
ec_cp(arg);
211+
ec_rm("");
212+
return 0;
213+
}
214+
215+
static int ec_hd(char *arg)
216+
{
217+
char hdr[EXLEN];
218+
char val[EXLEN];
219+
char *msg, *mod;
220+
long msglen, modlen;
221+
struct sbuf *sb = sbuf_make();
222+
arg = ex_arg(arg, hdr);
223+
arg = ex_arg(arg, val);
224+
mbox_get(mbox, pos, &msg, &msglen);
225+
sbuf_printf(sb, "%s %s\n", hdr, val);
226+
if (msg_set(msg, msglen, &mod, &modlen, hdr, sbuf_buf(sb)))
227+
return 1;
228+
sbuf_free(sb);
229+
mbox_set(mbox, pos, mod, modlen);
230+
free(mod);
231+
return 0;
232+
}
233+
234+
static int ec_ft(char *arg)
235+
{
236+
char *msg, *mod;
237+
long msglen, modlen;
238+
mbox_get(mbox, pos, &msg, &msglen);
239+
if (xpipe(arg, msg, msglen, &mod, &modlen))
240+
return 1;
241+
mbox_set(mbox, pos, mod, modlen);
242+
free(mod);
243+
return 0;
244+
}
245+
246+
static int ec_wr(char *arg)
247+
{
248+
char box[EXLEN];
249+
arg = ex_arg(arg, box);
250+
if (box[0])
251+
mbox_copy(mbox, box);
252+
else
253+
mbox_save(mbox);
254+
return 0;
255+
}
256+
257+
static int ex_exec(char *ec);
258+
259+
static int ec_g(char *arg)
260+
{
261+
while (isspace((unsigned char) *arg))
262+
arg++;
263+
if (arg[0] != '/' || ex_keyword(arg))
264+
return 1;
265+
arg++;
266+
while (arg[0] && arg[0] != '/')
267+
arg++;
268+
if (kwd[0]) {
269+
if (!ex_match(pos))
270+
ex_exec(arg);
271+
return 0;
272+
}
273+
return 1;
274+
}
275+
276+
static int ex_exec(char *ec)
277+
{
278+
char cmd[EXLEN];
279+
char *arg = ex_cmd(ec, cmd);
280+
if (!strcmp("rm", cmd))
281+
return ec_rm(arg);
282+
if (!strcmp("cp", cmd))
283+
return ec_cp(arg);
284+
if (!strcmp("mv", cmd))
285+
return ec_mv(arg);
286+
if (!strcmp("hd", cmd) || !strcmp("set", cmd))
287+
return ec_hd(arg);
288+
if (!strcmp("ft", cmd) || !strcmp("filt", cmd))
289+
return ec_ft(arg);
290+
if (!strcmp("w", cmd))
291+
return ec_wr(arg);
292+
if (!strcmp("g", cmd))
293+
return ec_g(arg);
294+
return 1;
295+
}
296+
297+
static int ec_stat(char *ec)
298+
{
299+
char *val;
300+
char newval[16];
301+
char c = ec[0];
302+
char i = atoi(ec + 1);
303+
char *msg, *mod;
304+
long msglen, modlen;
305+
if (i < 0 || i >= mbox_len(mbox))
306+
return 1;
307+
pos = i;
308+
mbox_get(mbox, pos, &msg, &msglen);
309+
val = msg_get(msg, msglen, "status:");
310+
if (val) {
311+
val += strlen("status:");
312+
while (isspace((unsigned char) val[0]))
313+
val++;
314+
}
315+
if ((!val && c == 'N') || (val && val[0] == c))
316+
return 0;
317+
sprintf(newval, "Status: %c\n", c);
318+
if (msg_set(msg, msglen, &mod, &modlen, "status:", newval))
319+
return 1;
320+
mbox_set(mbox, pos, mod, modlen);
321+
free(mod);
322+
return 0;
323+
}
324+
325+
int ex(char *argv[])
326+
{
327+
char ec[EXLEN];
328+
char loc[EXLEN];
329+
int beg, end, i;
330+
char *cmd;
331+
mbox = mbox_open(argv[0]);
332+
while (fgets(ec, sizeof(ec), stdin)) {
333+
char *cur = loc;
334+
if (isupper((unsigned char) ec[0]))
335+
ec_stat(ec);
336+
if (ec[0] != ':')
337+
continue;
338+
cmd = ex_loc(ec, loc);
339+
do {
340+
if (!ex_region(cur, &beg, &end)) {
341+
for (i = beg; i < end; i++) {
342+
pos = i;
343+
ex_exec(cmd);
344+
}
345+
}
346+
while (*cur && *cur != ';')
347+
cur++;
348+
if (*cur == ';')
349+
cur++;
350+
} while (*cur);
351+
}
352+
mbox_free(mbox);
353+
if (kwd[0])
354+
regfree(&kwd_re);
355+
return 0;
356+
}

0 commit comments

Comments
 (0)