mailx: better cmd parsing
[mailx.git] / mailx.c
blob025320dde712b386d4e440610efb28d5c3b5f1b0
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7 #include "mbox.h"
9 #define MIN(a, b) ((a) < (b) ? (a) : (b))
10 #define BUFSIZE (1 << 12)
11 #define PAGER "pgmail"
13 static char buf[BUFSIZE];
14 static int cur;
15 static int len;
17 static int read_line(char *dst, int size)
19 int nw = 0;
20 while (1) {
21 int cur_len = MIN(len - cur, size - nw - 1);
22 char *nl = memchr(buf + cur, '\n', cur_len);
23 int nr = nl ? nl - buf - cur + 1 : cur_len;
24 if (nr) {
25 memcpy(dst + nw, buf + cur, nr);
26 nw += nr;
27 cur += nr;
28 dst[nw] = '\0';
30 if (nl || nw == size - 1)
31 return nw;
32 cur = 0;
33 if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0)
34 return -1;
36 return nw;
39 static void till_eol(char *s)
41 char *r = s;
42 while (*s && *s != '\r' && *s != '\n')
43 s++;
44 write(1, r, s - r);
45 write(1, "\n", 1);
48 static void cmd_page(struct mbox *mbox, char *args)
50 struct mail *mail;
51 pid_t pid;
52 int fds[2];
53 mail = &mbox->mails[0];
54 pipe(fds);
55 if (!(pid = fork())) {
56 char *args[] = {PAGER, NULL};
57 close(fds[1]);
58 dup2(fds[0], STDIN_FILENO);
59 execvp(PAGER, args);
60 exit(1);
62 close(fds[0]);
63 write(fds[1], mail->head, mail->len);
64 close(fds[1]);
65 waitpid(pid, NULL, 0);
68 static char *cut_cmd(char *dst, char *s)
70 while (isalpha(*s)) {
71 *dst++ = *s++;
73 *dst = '\0';
74 return s;
77 static void cmd_head(struct mbox *mbox, char *args)
79 int i;
80 int n = MIN(mbox->n, 10);
81 for (i = 0; i < n; i++)
82 if (mbox->mails[i].subject)
83 till_eol(mbox->mails[i].subject);
86 static void loop(struct mbox *mbox)
88 char line[128];
89 char cmd[128];
90 while (read_line(line, sizeof(line)) > 0) {
91 char *args = cut_cmd(cmd, line);
92 int len = strlen(cmd);
93 if (!strncmp("header", cmd, len))
94 cmd_head(mbox, args);
95 if (!strncmp("page", cmd, len))
96 cmd_page(mbox, args);
97 if (!strncmp("quit", cmd, len))
98 return;
99 if (!strncmp("x", cmd, len) || !strncmp("exit", cmd, len))
100 return;
104 int main(int argc, char *argv[])
106 int i = 0;
107 struct mbox *mbox;
108 char *filename = NULL;
109 while (++i < argc)
110 if (!strcmp("-f", argv[i]))
111 filename = argv[++i];
112 if (filename) {
113 mbox = mbox_alloc(filename);
114 loop(mbox);
115 mbox_free(mbox);
117 return 0;