13 static struct mbox
*mbox
;
15 static char kwd
[EXLEN
];
16 static char kwd_hdr
[EXLEN
];
17 static regex_t kwd_re
;
19 static char *ex_loc(char *s
, char *loc
)
21 while (*s
== ':' || isspace((unsigned char) *s
))
23 while (*s
&& !isalpha((unsigned char) *s
)) {
24 if (*s
== '/' || *s
== '?') {
27 while (*s
&& *s
!= d
) {
28 if (*s
== '\\' && s
[1])
40 static char *ex_cmd(char *s
, char *cmd
)
42 while (isspace((unsigned char) *s
))
44 while (isalpha((unsigned char) *s
))
50 static char *ex_arg(char *s
, char *arg
)
52 while (isspace((unsigned char) *s
))
56 while (*s
&& *s
!= '"') {
57 if (*s
== '\\' && s
[1])
63 while (*s
&& !isspace((unsigned char) *s
)) {
64 if (*s
== '\\' && s
[1])
73 static int ex_keyword(char *pat
)
82 if (*e
== '\\' && e
[1])
84 sbuf_chr(sb
, (unsigned char) *e
);
86 if (sbuf_len(sb
) && strcmp(kwd
, sbuf_buf(sb
))) {
89 snprintf(kwd
, sizeof(kwd
), "%s", sbuf_buf(sb
));
90 if (regcomp(&kwd_re
, kwd
, REG_EXTENDED
| REG_ICASE
))
92 if (kwd
[0] == '^' && isalpha((unsigned char) (kwd
[1])) &&
94 int len
= strchr(kwd
, ':') - kwd
;
95 memcpy(kwd_hdr
, kwd
+ 1, len
);
98 strcpy(kwd_hdr
, "subject:");
105 static int ex_match(int i
)
112 if (mbox_get(mbox
, i
, &msg
, &msglen
))
114 hdr
= msg_get(msg
, msglen
, kwd_hdr
);
117 len
= hdrlen(hdr
, msg
+ msglen
- hdr
);
118 buf
= malloc(len
+ 1);
119 memcpy(buf
, hdr
, len
);
121 ret
= regexec(&kwd_re
, buf
, 0, NULL
, 0);
126 static int ex_search(char *pat
)
128 int dir
= *pat
== '/' ? +1 : -1;
132 while (i
>= 0 && i
< mbox_len(mbox
)) {
140 static int ex_lineno(char *num
)
143 if (!num
[0] || num
[0] == '.')
148 n
= mbox_len(mbox
) - 1;
150 n
= pos
- (num
[1] ? ex_lineno(num
+ 1) : 1);
152 n
= pos
+ (num
[1] ? ex_lineno(num
+ 1) : 1);
153 if (num
[0] == '/' && num
[1])
155 if (num
[0] == '?' && num
[1])
160 static int ex_region(char *loc
, int *beg
, int *end
)
164 *end
= mbox_len(mbox
);
167 if (!*loc
|| loc
[0] == ';') {
169 *end
= pos
== mbox_len(mbox
) ? pos
: pos
+ 1;
172 *beg
= ex_lineno(loc
);
173 while (*loc
&& *loc
!= ',' && *loc
!= ';')
176 *end
= ex_lineno(++loc
) + 1;
178 *end
= *beg
== mbox_len(mbox
) ? *beg
: *beg
+ 1;
179 if (*beg
< 0 || *beg
>= mbox_len(mbox
))
181 if (*end
< *beg
|| *end
> mbox_len(mbox
))
186 static int ec_rm(char *arg
)
188 mbox_set(mbox
, pos
, "", 0);
192 static int ec_cp(char *arg
)
198 arg
= ex_arg(arg
, box
);
199 fd
= open(box
, O_WRONLY
| O_APPEND
| O_CREAT
, S_IRUSR
| S_IWUSR
);
200 mbox_get(mbox
, pos
, &msg
, &msz
);
201 xwrite(fd
, msg
, msz
);
206 static int ec_mv(char *arg
)
213 static int ec_hd(char *arg
)
219 struct sbuf
*sb
= sbuf_make();
220 arg
= ex_arg(arg
, hdr
);
221 arg
= ex_arg(arg
, val
);
222 mbox_get(mbox
, pos
, &msg
, &msglen
);
223 sbuf_printf(sb
, "%s %s\n", hdr
, val
);
224 if (msg_set(msg
, msglen
, &mod
, &modlen
, hdr
, sbuf_buf(sb
)))
227 mbox_set(mbox
, pos
, mod
, modlen
);
232 static int ec_ft(char *arg
)
237 arg
= ex_arg(arg
, cmd
);
238 mbox_get(mbox
, pos
, &msg
, &msglen
);
239 if (xpipe(cmd
, msg
, msglen
, &mod
, &modlen
))
241 mbox_set(mbox
, pos
, mod
, modlen
);
246 static int ec_threadjoin(char *arg
)
248 char *th
, *msg
, *mod
;
249 long thlen
, msglen
, modlen
;
252 if (mbox_get(mbox
, atoi(arg
), &th
, &thlen
))
254 if (mbox_get(mbox
, pos
, &msg
, &msglen
))
256 id
= msg_get(th
, thlen
, "message-id:");
259 id_end
= id
+ hdrlen(id
, th
+ thlen
- id
);
260 id
= strchr(id
, ':') + 1;
262 sbuf_str(sb
, "In-Reply-To:");
263 sbuf_mem(sb
, id
, id_end
- id
);
264 if (msg_set(msg
, msglen
, &mod
, &modlen
, "in-reply-to:", sbuf_done(sb
)))
266 mbox_set(mbox
, pos
, mod
, modlen
);
270 static int ec_chop(char *arg
)
275 long newlen
= atoi(arg
);
278 if (mbox_get(mbox
, pos
, &msg
, &msglen
))
280 while (newlen
< msglen
&& msg
[newlen
] != '\n')
283 sbuf_mem(sb
, msg
, newlen
);
284 sbuf_str(sb
, "\nCHOPPED...\n\n");
285 modlen
= sbuf_len(sb
);
287 mbox_set(mbox
, pos
, mod
, modlen
);
291 static int ec_wr(char *arg
)
294 arg
= ex_arg(arg
, box
);
296 mbox_copy(mbox
, box
);
302 static int ex_exec(char *ec
);
304 static int ec_g(char *arg
, int not)
306 while (isspace((unsigned char) *arg
))
308 if (arg
[0] != '/' || ex_keyword(arg
))
311 while (arg
[0] && arg
[0] != '/')
313 if (kwd
[0] && arg
[0] == '/') {
315 if (!ex_match(pos
) == !not)
322 static int ex_exec(char *ec
)
325 char *arg
= ex_cmd(ec
, cmd
);
326 if (!strcmp("rm", cmd
))
328 if (!strcmp("cp", cmd
))
330 if (!strcmp("mv", cmd
))
332 if (!strcmp("hd", cmd
) || !strcmp("set", cmd
))
334 if (!strcmp("ft", cmd
) || !strcmp("filt", cmd
))
336 if (!strcmp("w", cmd
))
338 if (!strcmp("g", cmd
))
340 if (!strcmp("g!", cmd
))
342 if (!strcmp("tj", cmd
))
343 return ec_threadjoin(arg
);
344 if (!strcmp("ch", cmd
) || !strcmp("chop", cmd
))
349 static int ec_stat(char *ec
)
353 int c0
= (unsigned char) ec
[0];
354 int c1
= isalpha((unsigned char) ec
[1]) ? ec
[1] : 0;
357 int i
= atoi(ec
+ 1 + (c1
!= 0));
360 if (mbox_get(mbox
, i
, &msg
, &msglen
))
363 val
= msg_get(msg
, msglen
, "status:");
365 val
+= strlen("status:");
366 while (val
+ 1 < msg
+ msglen
&& isspace((unsigned char) val
[0]))
368 s0
= !isspace(val
[0]) ? (unsigned char) val
[0] : s0
;
369 s1
= !isspace(val
[1]) ? (unsigned char) val
[1] : s1
;
371 if (s0
== c0
&& s1
== c1
)
374 sprintf(newval
, "Status: %c%c\n", c0
, c1
);
376 sprintf(newval
, "Status: %c\n", c0
);
377 if (msg_set(msg
, msglen
, &mod
, &modlen
, "status:", newval
))
379 mbox_set(mbox
, pos
, mod
, modlen
);
391 printf("usage: neatmail ex mbox <cmds\n");
394 mbox
= mbox_open(argv
[0]);
396 fprintf(stderr
, "neatmail: cannot open <%s>\n", argv
[0]);
399 while (fgets(ec
, sizeof(ec
), stdin
)) {
401 if (isupper((unsigned char) ec
[0]) && ec
[1])
405 cmd
= ex_loc(ec
, loc
);
407 if (!ex_region(cur
, &beg
, &end
)) {
408 for (i
= beg
; i
< end
; i
++) {
413 while (*cur
&& *cur
!= ';')