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])
64 while (*s
&& !isspace((unsigned char) *s
)) {
65 if (*s
== '\\' && s
[1])
74 static int ex_eol(char *s
)
76 while (isspace((unsigned char) *s
))
81 static int ex_keyword(char *pat
)
90 if (*e
== '\\' && e
[1])
92 sbuf_chr(sb
, (unsigned char) *e
);
94 if (sbuf_len(sb
) && strcmp(kwd
, sbuf_buf(sb
))) {
97 snprintf(kwd
, sizeof(kwd
), "%s", sbuf_buf(sb
));
98 if (regcomp(&kwd_re
, kwd
, REG_EXTENDED
| REG_ICASE
))
100 if (kwd
[0] == '^' && isalpha((unsigned char) (kwd
[1])) &&
102 int len
= strchr(kwd
, ':') - kwd
;
103 memcpy(kwd_hdr
, kwd
+ 1, len
);
106 strcpy(kwd_hdr
, "subject:");
113 static int ex_match(int i
)
120 if (mbox_get(mbox
, i
, &msg
, &msglen
))
122 hdr
= msg_get(msg
, msglen
, kwd_hdr
);
125 len
= hdrlen(hdr
, msg
+ msglen
- hdr
);
126 buf
= malloc(len
+ 1);
127 memcpy(buf
, hdr
, len
);
129 ret
= regexec(&kwd_re
, buf
, 0, NULL
, 0);
134 static int ex_search(char *pat
)
136 int dir
= *pat
== '/' ? +1 : -1;
140 while (i
>= 0 && i
< mbox_len(mbox
)) {
148 static int ex_lineno(char *num
)
151 if (!num
[0] || num
[0] == '.')
156 n
= mbox_len(mbox
) - 1;
158 n
= pos
- (num
[1] ? ex_lineno(num
+ 1) : 1);
160 n
= pos
+ (num
[1] ? ex_lineno(num
+ 1) : 1);
161 if (num
[0] == '/' && num
[1])
163 if (num
[0] == '?' && num
[1])
168 static int ex_region(char *loc
, int *beg
, int *end
)
172 *end
= mbox_len(mbox
);
175 if (!*loc
|| loc
[0] == ';') {
177 *end
= pos
== mbox_len(mbox
) ? pos
: pos
+ 1;
180 *beg
= ex_lineno(loc
);
181 while (*loc
&& *loc
!= ',' && *loc
!= ';')
184 *end
= ex_lineno(++loc
) + 1;
186 *end
= *beg
== mbox_len(mbox
) ? *beg
: *beg
+ 1;
187 if (*beg
< 0 || *beg
>= mbox_len(mbox
))
189 if (*end
< *beg
|| *end
> mbox_len(mbox
))
194 static int ec_print(char *arg
)
200 static int ec_rm(char *arg
)
202 return mbox_set(mbox
, pos
, "", 0);
205 static int ec_cp(char *arg
)
211 arg
= ex_arg(arg
, box
);
212 if (mbox_get(mbox
, pos
, &msg
, &msz
))
214 if ((fd
= open(box
, O_WRONLY
| O_APPEND
| O_CREAT
, S_IRUSR
| S_IWUSR
)) < 0)
216 xwrite(fd
, msg
, msz
);
221 static int ec_mv(char *arg
)
228 static int ec_hd(char *arg
)
230 char hdr
[EXLEN
], val
[EXLEN
];
234 arg
= ex_arg(arg
, hdr
);
235 if (mbox_get(mbox
, pos
, &msg
, &msglen
))
239 arg
= ex_arg(arg
, val
);
240 snprintf(hln
, sizeof(hln
), "%s %s\n", hdr
, val
);
242 if (msg_set(msg
, msglen
, &mod
, &modlen
, hdr
, hln
))
244 mbox_set(mbox
, pos
, mod
, modlen
);
249 static int ec_ft(char *arg
)
254 arg
= ex_arg(arg
, cmd
);
255 if (mbox_get(mbox
, pos
, &msg
, &msglen
))
257 if (xpipe(cmd
, msg
, msglen
, &mod
, &modlen
))
259 mbox_set(mbox
, pos
, mod
, modlen
);
264 static int ec_threadjoin(char *arg
)
266 char *th
, *msg
, *mod
;
267 long thlen
, msglen
, modlen
;
270 if (mbox_get(mbox
, atoi(arg
), &th
, &thlen
))
272 if (mbox_get(mbox
, pos
, &msg
, &msglen
))
274 id
= msg_get(th
, thlen
, "message-id:");
277 id_end
= id
+ hdrlen(id
, th
+ thlen
- id
);
278 id
= strchr(id
, ':') + 1;
280 sbuf_str(sb
, "In-Reply-To:");
281 sbuf_mem(sb
, id
, id_end
- id
);
282 if (msg_set(msg
, msglen
, &mod
, &modlen
, "in-reply-to:", sbuf_done(sb
)))
284 mbox_set(mbox
, pos
, mod
, modlen
);
289 static int ec_chop(char *arg
)
294 long newlen
= arg
? atoi(arg
) * 1024 : 0;
296 if (mbox_get(mbox
, pos
, &msg
, &msglen
))
298 while (beg
+ 2 < msglen
&& (msg
[beg
] != '\n' || msg
[beg
+ 1] != '\n'))
300 end
= beg
+ 1 + newlen
;
301 while (end
< msglen
&& msg
[end
] != '\n')
306 sbuf_mem(sb
, msg
, end
);
307 sbuf_str(sb
, "\nCHOPPED...\n\n");
308 modlen
= sbuf_len(sb
);
310 mbox_set(mbox
, pos
, mod
, modlen
);
315 static int ec_wr(char *arg
)
318 arg
= ex_arg(arg
, box
);
320 mbox_copy(mbox
, box
);
326 static int ex_exec(char *ec
);
328 static int ec_g(char *arg
, int not)
330 while (isspace((unsigned char) *arg
))
332 if (arg
[0] != '/' || ex_keyword(arg
))
335 while (arg
[0] && arg
[0] != '/')
337 if (kwd
[0] && arg
[0] == '/') {
339 if (!ex_match(pos
) == !not)
346 static int ex_exec(char *ec
)
349 char *arg
= ex_cmd(ec
, cmd
);
350 if (!strcmp("rm", cmd
))
352 if (!strcmp("cp", cmd
))
354 if (!strcmp("mv", cmd
))
356 if (!strcmp("hd", cmd
) || !strcmp("set", cmd
))
358 if (!strcmp("ft", cmd
) || !strcmp("filt", cmd
))
360 if (!strcmp("w", cmd
))
362 if (!strcmp("g", cmd
))
364 if (!strcmp("g!", cmd
))
366 if (!strcmp("tj", cmd
))
367 return ec_threadjoin(arg
);
368 if (!strcmp("ch", cmd
) || !strcmp("chop", cmd
))
370 if (!strcmp("p", cmd
))
371 return ec_print(arg
);
375 static int ec_stat(char *ec
)
379 int c0
= ec
[0] >= 'A' && ec
[0] <= 'Z' ? ec
[0] : 0;
380 int c1
= ec
[1] >= 'A' && ec
[1] <= 'Z' ? ec
[1] : 0;
383 int i
= 1 + (c1
!= 0);
387 while (ec
[i
] >= '0' && ec
[i
] <= '9')
388 n
= n
* 10 + ec
[i
++] - '0';
389 if (ec
[i
] == '@') /* message not in the main mbox */
391 if (mbox_get(mbox
, n
, &msg
, &msglen
))
394 val
= msg_get(msg
, msglen
, "status:");
396 val
+= strlen("status:");
397 while (val
+ 1 < msg
+ msglen
&& isspace((unsigned char) val
[0]))
399 s0
= !isspace(val
[0]) ? (unsigned char) val
[0] : s0
;
400 s1
= !isspace(val
[1]) ? (unsigned char) val
[1] : s1
;
402 if (s0
== c0
&& s1
== c1
)
405 sprintf(newval
, "Status: %c%c\n", c0
, c1
);
407 sprintf(newval
, "Status: %c\n", c0
);
408 if (msg_set(msg
, msglen
, &mod
, &modlen
, "status:", newval
))
410 mbox_set(mbox
, pos
, mod
, modlen
);
421 char *path
[16] = {NULL
};
424 printf("usage: neatmail ex [mbox] <cmds\n");
427 for (i
= 0; argv
[i
] && argv
[i
][0] == '-'; i
++) {
428 if (argv
[i
][1] == 'b')
429 path
[path_n
++] = argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
];
432 path
[path_n
++] = argv
[i
];
433 mbox
= mbox_open(path
);
435 fprintf(stderr
, "neatmail: cannot open <%s>\n", path
[0]);
438 while (fgets(ec
, sizeof(ec
), stdin
)) {
440 if (isupper((unsigned char) ec
[0]) && ec
[1])
444 cmd
= ex_loc(ec
, loc
);
446 if (!ex_region(cur
, &beg
, &end
)) {
447 for (i
= beg
; i
< end
; i
++) {
452 while (*cur
&& *cur
!= ';')