add inc command to read new mails
[mailx.git] / mailx.c
blob8d04836e489b454f125e4eee8e26b80a561d3247
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)
15 #define DIGITS 5
17 static char *hdr_filt[] = {
18 "Subject:", "From:", "To:", "Cc:", "Date:", "User-Agent:",
19 "X-Mailer", "Organization"};
21 static char buf[BUFSIZE];
22 static int cur;
23 static int len;
25 static int read_line(char *dst, int size)
27 int nw = 0;
28 while (1) {
29 int cur_len = MIN(len - cur, size - nw - 1);
30 char *nl = memchr(buf + cur, '\n', cur_len);
31 int nr = nl ? nl - buf - cur + 1 : cur_len;
32 if (nr) {
33 memcpy(dst + nw, buf + cur, nr);
34 nw += nr;
35 cur += nr;
36 dst[nw] = '\0';
38 if (nl || nw == size - 1)
39 return nw;
40 cur = 0;
41 if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0)
42 return -1;
44 return nw;
47 static void till_eol(char *s)
49 char *r = s;
50 while (*s && *s != '\r' && *s != '\n')
51 s++;
52 write(1, r, s - r);
53 write(1, "\n", 1);
56 static char *cut_word(char *dst, char *s)
58 while (isspace(*s))
59 s++;
60 while (!isspace(*s))
61 *dst++ = *s++;
62 *dst = '\0';
63 return s;
66 static int msg_num(struct mbox *mbox, char *num)
68 int n = -1;
69 if (!*num || !strcmp(".", num))
70 n = mbox->c;
71 if (isdigit(*num))
72 n = atoi(num);
73 if (!strcmp("$", num))
74 n = mbox->n - 1;
75 if (n < 0 || n >= mbox->n)
76 return -1;
77 mbox->c = n;
78 return n;
81 static void cmd_page(struct mbox *mbox, char *args)
83 struct mail *mail;
84 pid_t pid;
85 int fds[2];
86 char head[BUFSIZE];
87 char num[MAXLINE];
88 int hdr_len;
89 args = cut_word(num, args);
90 if (msg_num(mbox, num) == -1)
91 return;
92 mail = &mbox->mails[mbox->c];
93 pipe(fds);
94 if (!(pid = fork())) {
95 char *args[] = {PAGER, NULL};
96 close(fds[1]);
97 dup2(fds[0], STDIN_FILENO);
98 execvp(PAGER, args);
99 exit(1);
101 close(fds[0]);
102 hdr_len = mail_head(mail, head, sizeof(head),
103 hdr_filt, ARRAY_SIZE(hdr_filt));
104 write(fds[1], head, hdr_len);
105 write(fds[1], mail->body, mail->body_len);
106 close(fds[1]);
107 waitpid(pid, NULL, 0);
110 static char *cut_cmd(char *dst, char *s)
112 while (isalpha(*s)) {
113 *dst++ = *s++;
115 *dst = '\0';
116 return s;
119 static char *put_int(char *s, int n, int w)
121 int i;
122 for (i = 0; i < w; i++) {
123 s[w - i - 1] = n || !i ? '0' + n % 10 : ' ';
124 n = n / 10;
126 return s + w;
129 static void cmd_head(struct mbox *mbox, char *args)
131 char num[MAXLINE];
132 int beg, end;
133 int i;
134 args = cut_word(num, args);
135 if (msg_num(mbox, num) == -1)
136 return;
137 beg = mbox->c / NHEAD * NHEAD;
138 end = MIN(beg + NHEAD, mbox->n);
139 for (i = beg; i < end; i++) {
140 char fmt[16] = {0};
141 char *s = fmt;
142 *s++ = i == mbox->c ? '>' : ' ';
143 s = put_int(s, i, DIGITS);
144 *s++ = ' ';
145 *s++ = ' ';
146 write(STDOUT_FILENO, fmt, strlen(fmt));
147 if (mbox->mails[i].subject)
148 till_eol(mbox->mails[i].subject + 9);
152 static void print(char *s)
154 write(STDOUT_FILENO, s, strlen(s));
157 static void cmd_fold(struct mbox *mbox, char *args)
159 char msg[MAXLINE];
160 char *s = put_int(msg, mbox->n, DIGITS);
161 strcpy(s, " messages\n");
162 print(msg);
165 static void cmd_inc(struct mbox *mbox, char *args)
167 mbox_inc(mbox);
170 static void prompt(void)
172 write(STDOUT_FILENO, "? ", 2);
175 static void loop(struct mbox *mbox)
177 char line[MAXLINE];
178 char cmd[MAXLINE];
179 prompt();
180 while (read_line(line, sizeof(line)) > 0) {
181 char *args = cut_cmd(cmd, line);
182 int len = strlen(cmd);
183 if (!len) {
184 if (mbox->c + 1 < mbox->n) {
185 mbox->c++;
186 cmd_page(mbox, args);
187 } else {
188 print("EOF\n");
190 prompt();
191 continue;
193 if (!strncmp("page", cmd, len))
194 cmd_page(mbox, args);
195 if (!strncmp("header", cmd, len))
196 cmd_head(mbox, args);
197 if (!strncmp("folder", cmd, len))
198 cmd_fold(mbox, args);
199 if (!strncmp("inc", cmd, len))
200 cmd_inc(mbox, args);
201 if (!strncmp("quit", cmd, len))
202 return;
203 if (!strncmp("x", cmd, len) || !strncmp("exit", cmd, len))
204 return;
205 prompt();
209 int main(int argc, char *argv[])
211 int i = 0;
212 struct mbox *mbox;
213 char *filename = NULL;
214 while (++i < argc)
215 if (!strcmp("-f", argv[i]))
216 filename = argv[++i];
217 if (filename) {
218 mbox = mbox_alloc(filename);
219 loop(mbox);
220 mbox_free(mbox);
222 return 0;