update struct sort at inc command
[mailx.git] / mailx.c
blobe3cd287a41362eb4fb7da0a307e9a0a131420280
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 WIDTH 80
17 #define DIGITS 5
19 static char *hdr_filt[] = {
20 "Subject:", "From:", "To:", "Cc:", "Date:", "User-Agent:",
21 "X-Mailer", "Organization"};
23 static struct mbox *mbox;
24 static struct sort *sort;
25 static int cur;
27 static int read_line(char *dst, int size)
29 static char buf[BUFSIZE];
30 static int cur;
31 static int len;
32 int nw = 0;
33 while (1) {
34 int cur_len = MIN(len - cur, size - nw - 1);
35 char *nl = memchr(buf + cur, '\n', cur_len);
36 int nr = nl ? nl - buf - cur + 1 : cur_len;
37 if (nr) {
38 memcpy(dst + nw, buf + cur, nr);
39 nw += nr;
40 cur += nr;
41 dst[nw] = '\0';
43 if (nl || nw == size - 1)
44 return nw;
45 cur = 0;
46 if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0)
47 return -1;
49 return nw;
52 static char *till_eol(char *r, int len, char *s)
54 char *d = r + len;
55 while (r < d && *s && *s != '\r' && *s != '\n')
56 *r++ = *s++;
57 return r;
60 static char *cut_word(char *dst, char *s)
62 while (isspace(*s))
63 s++;
64 while (!isspace(*s))
65 *dst++ = *s++;
66 *dst = '\0';
67 return s;
70 static int msg_num(char *num)
72 int n = -1;
73 if (!*num || !strcmp(".", num))
74 n = cur;
75 if (isdigit(*num))
76 n = atoi(num);
77 if (!strcmp("$", num))
78 n = mbox->n - 1;
79 if (n < 0 || n >= mbox->n)
80 return -1;
81 cur = n;
82 return n;
85 static void cmd_page(char *args)
87 struct mail *mail;
88 pid_t pid;
89 int fds[2];
90 char head[BUFSIZE];
91 char num[MAXLINE];
92 int hdr_len;
93 args = cut_word(num, args);
94 if (msg_num(num) == -1)
95 return;
96 mail = sort->mails[cur];
97 mail->stat |= STAT_READ;
98 pipe(fds);
99 if (!(pid = fork())) {
100 char *args[] = {PAGER, NULL};
101 close(fds[1]);
102 dup2(fds[0], STDIN_FILENO);
103 execvp(PAGER, args);
104 exit(1);
106 close(fds[0]);
107 hdr_len = mail_head(mail, head, sizeof(head),
108 hdr_filt, ARRAY_SIZE(hdr_filt));
109 write(fds[1], head, hdr_len);
110 write(fds[1], mail->body, mail->body_len);
111 close(fds[1]);
112 waitpid(pid, NULL, 0);
115 static char *cut_cmd(char *dst, char *s)
117 while (isalpha(*s)) {
118 *dst++ = *s++;
120 *dst = '\0';
121 return s;
124 static char *put_int(char *s, int n, int w)
126 int i;
127 for (i = 0; i < w; i++) {
128 s[w - i - 1] = n || !i ? '0' + n % 10 : ' ';
129 n = n / 10;
131 return s + w;
134 static char *put_hdr(struct mail *mail, char *name, int w, char *s)
136 char *hdr = mail_hdr(mail, name);
137 return till_eol(s, w, hdr ? hdr + strlen(name) + 1 : NULL);
140 static void cmd_head(char *args)
142 char num[MAXLINE];
143 int beg, end;
144 int i;
145 args = cut_word(num, args);
146 if (msg_num(num) == -1)
147 return;
148 beg = cur / NHEAD * NHEAD;
149 end = MIN(beg + NHEAD, mbox->n);
150 for (i = beg; i < end; i++) {
151 struct mail *mail = sort->mails[i];
152 char fmt[MAXLINE];
153 char *s = fmt;
154 *s++ = i == cur ? '>' : ' ';
155 if (mail->stat & STAT_READ)
156 *s++ = ' ';
157 else
158 *s++ = mail->stat & STAT_NEW ? 'N' : 'O';
159 s = put_int(s, i, DIGITS);
160 *s++ = ' ';
161 *s++ = ' ';
162 s = put_hdr(mail, "From:", 16, s);
163 *s++ = ' ';
164 *s++ = ' ';
165 s = sort_draw(sort, i, s, WIDTH - (s - fmt));
166 s = put_hdr(mail, "Subject:", WIDTH - (s - fmt), s);
167 *s++ = '\n';
168 write(STDOUT_FILENO, fmt, s - fmt);
172 static void cmd_z(char *args)
174 char num[MAXLINE];
175 int page = -1;
176 cut_word(num, args);
177 if (!*num)
178 page = MIN(cur + NHEAD, mbox->n) / NHEAD;
179 if (*num == '+' || *num == '-') {
180 int d = (*num + 1) ? (*num == '-' ? -1 : 1) : atoi(num);
181 page = cur / NHEAD + d;
183 if (*num == '$')
184 page = mbox->n / NHEAD;
185 if (isdigit(*num))
186 page = atoi(num);
187 if (page >= 0 && page * NHEAD < mbox->n) {
188 cur = page * NHEAD;
189 cmd_head("");
193 static void print(char *s)
195 write(STDOUT_FILENO, s, strlen(s));
198 static void cmd_fold(char *args)
200 char msg[MAXLINE];
201 char *s = put_int(msg, mbox->n, DIGITS);
202 strcpy(s, " messages\n");
203 print(msg);
206 static void cmd_inc(char *args)
208 mbox_inc(mbox);
209 sort_inc(sort);
212 static void prompt(void)
214 write(STDOUT_FILENO, "? ", 2);
217 static void loop(void)
219 char line[MAXLINE];
220 char cmd[MAXLINE];
221 prompt();
222 while (read_line(line, sizeof(line)) > 0) {
223 char *args = cut_cmd(cmd, line);
224 int len = strlen(cmd);
225 if (!len) {
226 if (cur + 1 < mbox->n) {
227 cur++;
228 cmd_page(args);
229 } else {
230 print("EOF\n");
232 prompt();
233 continue;
235 if (!strncmp("page", cmd, len))
236 cmd_page(args);
237 if (!strncmp("header", cmd, len))
238 cmd_head(args);
239 if (!strncmp("folder", cmd, len))
240 cmd_fold(args);
241 if (!strncmp("inc", cmd, len))
242 cmd_inc(args);
243 if (!strncmp("z", cmd, len))
244 cmd_z(args);
245 if (!strncmp("quit", cmd, len)) {
246 mbox_write(mbox);
247 return;
249 if (!strncmp("xit", cmd, len) || !strncmp("exit", cmd, len))
250 return;
251 prompt();
255 int main(int argc, char *argv[])
257 int i = 0;
258 char *filename = NULL;
259 while (++i < argc)
260 if (!strcmp("-f", argv[i]))
261 filename = argv[++i];
262 if (filename) {
263 mbox = mbox_alloc(filename);
264 sort = sort_alloc(mbox);
265 loop();
266 sort_free(sort);
267 mbox_free(mbox);
269 return 0;