filter headers before paging
[mailx.git] / mailx.c
blob67232f505b71816cd61ff0a02bb22243d9c4eaf3
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 ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
10 #define MIN(a, b) ((a) < (b) ? (a) : (b))
11 #define MAXLINE (1 << 7)
12 #define BUFSIZE (1 << 12)
13 #define PAGER "pgmail"
14 #define NHEAD (1 << 4)
16 static char *hdr_filt[] = {
17 "Subject:", "From:", "To:", "Cc:", "Date:", "User-Agent:",
18 "X-Mailer", "Organization"};
20 static char buf[BUFSIZE];
21 static int cur;
22 static int len;
24 static int read_line(char *dst, int size)
26 int nw = 0;
27 while (1) {
28 int cur_len = MIN(len - cur, size - nw - 1);
29 char *nl = memchr(buf + cur, '\n', cur_len);
30 int nr = nl ? nl - buf - cur + 1 : cur_len;
31 if (nr) {
32 memcpy(dst + nw, buf + cur, nr);
33 nw += nr;
34 cur += nr;
35 dst[nw] = '\0';
37 if (nl || nw == size - 1)
38 return nw;
39 cur = 0;
40 if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0)
41 return -1;
43 return nw;
46 static void till_eol(char *s)
48 char *r = s;
49 while (*s && *s != '\r' && *s != '\n')
50 s++;
51 write(1, r, s - r);
52 write(1, "\n", 1);
55 static char *cut_int(char *dst, char *s)
57 while (isspace(*s))
58 s++;
59 while (isdigit(*s))
60 *dst++ = *s++;
61 *dst = '\0';
62 return s;
65 static void cmd_page(struct mbox *mbox, char *args)
67 struct mail *mail;
68 pid_t pid;
69 int fds[2];
70 char head[BUFSIZE];
71 char num[MAXLINE];
72 int hdr_len;
73 int n = mbox->c;
74 args = cut_int(num, args);
75 if (isdigit(*num))
76 n = atoi(num);
77 if (n < 0 && n >= mbox->n)
78 return;
79 mail = &mbox->mails[n];
80 mbox->c = n;
81 pipe(fds);
82 if (!(pid = fork())) {
83 char *args[] = {PAGER, NULL};
84 close(fds[1]);
85 dup2(fds[0], STDIN_FILENO);
86 execvp(PAGER, args);
87 exit(1);
89 close(fds[0]);
90 hdr_len = mail_head(mail, head, sizeof(head),
91 hdr_filt, ARRAY_SIZE(hdr_filt));
92 write(fds[1], head, hdr_len);
93 write(fds[1], mail->body, mail->body_len);
94 close(fds[1]);
95 waitpid(pid, NULL, 0);
98 static char *cut_cmd(char *dst, char *s)
100 while (isalpha(*s)) {
101 *dst++ = *s++;
103 *dst = '\0';
104 return s;
107 static char *put_int(char *s, int n, int w)
109 int i;
110 for (i = 0; i < w; i++) {
111 s[w - i - 1] = n || !i ? '0' + n % 10 : ' ';
112 n = n / 10;
114 return s + w;
117 static void cmd_head(struct mbox *mbox, char *args)
119 int i;
120 int beg = mbox->c / NHEAD * NHEAD;
121 int end = MIN(beg + NHEAD, mbox->n);
122 if (!mbox->n)
123 return;
124 for (i = beg; i < end; i++) {
125 char fmt[16] = {0};
126 char *s = fmt;
127 *s++ = i == mbox->c ? '>' : ' ';
128 s = put_int(s, i, 5);
129 *s++ = ' ';
130 *s++ = ' ';
131 write(STDOUT_FILENO, fmt, strlen(fmt));
132 if (mbox->mails[i].subject)
133 till_eol(mbox->mails[i].subject + 9);
137 static void prompt(void)
139 write(STDOUT_FILENO, "? ", 2);
142 static void print(char *s)
144 write(STDOUT_FILENO, s, strlen(s));
147 static void loop(struct mbox *mbox)
149 char line[MAXLINE];
150 char cmd[MAXLINE];
151 prompt();
152 while (read_line(line, sizeof(line)) > 0) {
153 char *args = cut_cmd(cmd, line);
154 int len = strlen(cmd);
155 if (!len) {
156 if (mbox->c < mbox->n + 1) {
157 mbox->c++;
158 cmd_page(mbox, args);
159 } else {
160 print("EOF\n");
162 prompt();
163 continue;
165 if (!strncmp("page", cmd, len))
166 cmd_page(mbox, args);
167 if (!strncmp("header", cmd, len))
168 cmd_head(mbox, args);
169 if (!strncmp("quit", cmd, len))
170 return;
171 if (!strncmp("x", cmd, len) || !strncmp("exit", cmd, len))
172 return;
173 prompt();
177 int main(int argc, char *argv[])
179 int i = 0;
180 struct mbox *mbox;
181 char *filename = NULL;
182 while (++i < argc)
183 if (!strcmp("-f", argv[i]))
184 filename = argv[++i];
185 if (filename) {
186 mbox = mbox_alloc(filename);
187 loop(mbox);
188 mbox_free(mbox);
190 return 0;