move id and rply header from mail to thread
[mailx.git] / mailx.c
blob7b026a9360f32160e2203a6e93abf19ddd5a3b51
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"
8 #include "sort.h"
10 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
11 #define MIN(a, b) ((a) < (b) ? (a) : (b))
12 #define MAXLINE (1 << 7)
13 #define BUFSIZE (1 << 12)
14 #define PAGER "pgmail"
15 #define NHEAD (1 << 4)
16 #define DIGITS 5
18 static char *hdr_filt[] = {
19 "Subject:", "From:", "To:", "Cc:", "Date:", "User-Agent:",
20 "X-Mailer", "Organization"};
22 static struct mbox *mbox;
23 static struct sort *sort;
24 static int cur;
26 static int read_line(char *dst, int size)
28 static char buf[BUFSIZE];
29 static int cur;
30 static int len;
31 int nw = 0;
32 while (1) {
33 int cur_len = MIN(len - cur, size - nw - 1);
34 char *nl = memchr(buf + cur, '\n', cur_len);
35 int nr = nl ? nl - buf - cur + 1 : cur_len;
36 if (nr) {
37 memcpy(dst + nw, buf + cur, nr);
38 nw += nr;
39 cur += nr;
40 dst[nw] = '\0';
42 if (nl || nw == size - 1)
43 return nw;
44 cur = 0;
45 if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0)
46 return -1;
48 return nw;
51 static char *till_eol(char *r, int len, char *s)
53 char *d = r + len;
54 while (r < d && *s && *s != '\r' && *s != '\n')
55 *r++ = *s++;
56 return r;
59 static char *cut_word(char *dst, char *s)
61 while (isspace(*s))
62 s++;
63 while (!isspace(*s))
64 *dst++ = *s++;
65 *dst = '\0';
66 return s;
69 static int msg_num(char *num)
71 int n = -1;
72 if (!*num || !strcmp(".", num))
73 n = cur;
74 if (isdigit(*num))
75 n = atoi(num);
76 if (!strcmp("$", num))
77 n = mbox->n - 1;
78 if (n < 0 || n >= mbox->n)
79 return -1;
80 cur = n;
81 return n;
84 static void cmd_page(char *args)
86 struct mail *mail;
87 pid_t pid;
88 int fds[2];
89 char head[BUFSIZE];
90 char num[MAXLINE];
91 int hdr_len;
92 args = cut_word(num, args);
93 if (msg_num(num) == -1)
94 return;
95 mail = sort->mails[cur];
96 mail->stat |= STAT_READ;
97 pipe(fds);
98 if (!(pid = fork())) {
99 char *args[] = {PAGER, NULL};
100 close(fds[1]);
101 dup2(fds[0], STDIN_FILENO);
102 execvp(PAGER, args);
103 exit(1);
105 close(fds[0]);
106 hdr_len = mail_head(mail, head, sizeof(head),
107 hdr_filt, ARRAY_SIZE(hdr_filt));
108 write(fds[1], head, hdr_len);
109 write(fds[1], mail->body, mail->body_len);
110 close(fds[1]);
111 waitpid(pid, NULL, 0);
114 static char *cut_cmd(char *dst, char *s)
116 while (isalpha(*s)) {
117 *dst++ = *s++;
119 *dst = '\0';
120 return s;
123 static char *put_int(char *s, int n, int w)
125 int i;
126 for (i = 0; i < w; i++) {
127 s[w - i - 1] = n || !i ? '0' + n % 10 : ' ';
128 n = n / 10;
130 return s + w;
133 static void cmd_head(char *args)
135 char num[MAXLINE];
136 int beg, end;
137 int i;
138 args = cut_word(num, args);
139 if (msg_num(num) == -1)
140 return;
141 beg = cur / NHEAD * NHEAD;
142 end = MIN(beg + NHEAD, mbox->n);
143 for (i = beg; i < end; i++) {
144 struct mail *mail = sort->mails[i];
145 char fmt[MAXLINE];
146 char *s = fmt;
147 *s++ = i == cur ? '>' : ' ';
148 if (mail->stat & STAT_READ)
149 *s++ = ' ';
150 else
151 *s++ = mail->stat & STAT_NEW ? 'N' : 'O';
152 s = put_int(s, i, DIGITS);
153 *s++ = ' ';
154 *s++ = ' ';
155 if (sort) {
156 s = sort_draw(sort, i, s, 32);
158 if (mail->subj_hdr)
159 s = till_eol(s, 40, mail->subj_hdr + 9);
160 *s++ = '\n';
161 write(STDOUT_FILENO, fmt, s - fmt);
165 static void print(char *s)
167 write(STDOUT_FILENO, s, strlen(s));
170 static void cmd_fold(char *args)
172 char msg[MAXLINE];
173 char *s = put_int(msg, mbox->n, DIGITS);
174 strcpy(s, " messages\n");
175 print(msg);
178 static void cmd_inc(char *args)
180 mbox_inc(mbox);
183 static void prompt(void)
185 write(STDOUT_FILENO, "? ", 2);
188 static void loop(void)
190 char line[MAXLINE];
191 char cmd[MAXLINE];
192 prompt();
193 while (read_line(line, sizeof(line)) > 0) {
194 char *args = cut_cmd(cmd, line);
195 int len = strlen(cmd);
196 if (!len) {
197 if (cur + 1 < mbox->n) {
198 cur++;
199 cmd_page(args);
200 } else {
201 print("EOF\n");
203 prompt();
204 continue;
206 if (!strncmp("page", cmd, len))
207 cmd_page(args);
208 if (!strncmp("header", cmd, len))
209 cmd_head(args);
210 if (!strncmp("folder", cmd, len))
211 cmd_fold(args);
212 if (!strncmp("inc", cmd, len))
213 cmd_inc(args);
214 if (!strncmp("quit", cmd, len)) {
215 mbox_write(mbox);
216 return;
218 if (!strncmp("xit", cmd, len) || !strncmp("exit", cmd, len))
219 return;
220 prompt();
224 int main(int argc, char *argv[])
226 int i = 0;
227 char *filename = NULL;
228 while (++i < argc)
229 if (!strcmp("-f", argv[i]))
230 filename = argv[++i];
231 if (filename) {
232 mbox = mbox_alloc(filename);
233 sort = sort_alloc(mbox);
234 loop();
235 sort_free(sort);
236 mbox_free(mbox);
238 return 0;