put message number in header cmd
[mailx.git] / mailx.c
bloba518da8be28da48f9a19c4925b297d8774774f55
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 MAXLINE (1 << 7)
11 #define BUFSIZE (1 << 12)
12 #define PAGER "pgmail"
13 #define NHEAD (1 << 4)
15 static char buf[BUFSIZE];
16 static int cur;
17 static int len;
19 static int read_line(char *dst, int size)
21 int nw = 0;
22 while (1) {
23 int cur_len = MIN(len - cur, size - nw - 1);
24 char *nl = memchr(buf + cur, '\n', cur_len);
25 int nr = nl ? nl - buf - cur + 1 : cur_len;
26 if (nr) {
27 memcpy(dst + nw, buf + cur, nr);
28 nw += nr;
29 cur += nr;
30 dst[nw] = '\0';
32 if (nl || nw == size - 1)
33 return nw;
34 cur = 0;
35 if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0)
36 return -1;
38 return nw;
41 static void till_eol(char *s)
43 char *r = s;
44 while (*s && *s != '\r' && *s != '\n')
45 s++;
46 write(1, r, s - r);
47 write(1, "\n", 1);
50 static char *cut_int(char *dst, char *s)
52 while (isspace(*s))
53 s++;
54 while (isdigit(*s))
55 *dst++ = *s++;
56 *dst = '\0';
57 return s;
60 static void cmd_page(struct mbox *mbox, char *args)
62 struct mail *mail;
63 pid_t pid;
64 int fds[2];
65 char num[MAXLINE];
66 int n = mbox->c;
67 args = cut_int(num, args);
68 if (isdigit(*num))
69 n = atoi(num);
70 if (n < 0 && n >= mbox->n)
71 return;
72 mail = &mbox->mails[n];
73 mbox->c = n;
74 pipe(fds);
75 if (!(pid = fork())) {
76 char *args[] = {PAGER, NULL};
77 close(fds[1]);
78 dup2(fds[0], STDIN_FILENO);
79 execvp(PAGER, args);
80 exit(1);
82 close(fds[0]);
83 write(fds[1], mail->head, mail->len);
84 close(fds[1]);
85 waitpid(pid, NULL, 0);
88 static char *cut_cmd(char *dst, char *s)
90 while (isalpha(*s)) {
91 *dst++ = *s++;
93 *dst = '\0';
94 return s;
97 static char *put_int(char *s, int n, int w)
99 int i;
100 for (i = 0; i < w; i++) {
101 s[w - i - 1] = n || !i ? '0' + n % 10 : ' ';
102 n = n / 10;
104 return s + w;
107 static void cmd_head(struct mbox *mbox, char *args)
109 int i;
110 int beg = mbox->c / NHEAD * NHEAD;
111 int end = MIN(beg + NHEAD, mbox->n);
112 if (!mbox->n)
113 return;
114 for (i = beg; i < end; i++) {
115 char fmt[16] = {0};
116 char *s = fmt;
117 *s++ = i == mbox->c ? '>' : ' ';
118 s = put_int(s, i, 5);
119 *s++ = ' ';
120 *s++ = ' ';
121 write(STDOUT_FILENO, fmt, strlen(fmt));
122 if (mbox->mails[i].subject)
123 till_eol(mbox->mails[i].subject + 9);
127 static void loop(struct mbox *mbox)
129 char line[MAXLINE];
130 char cmd[MAXLINE];
131 while (read_line(line, sizeof(line)) > 0) {
132 char *args = cut_cmd(cmd, line);
133 int len = strlen(cmd);
134 if (!strncmp("header", cmd, len))
135 cmd_head(mbox, args);
136 if (!strncmp("page", cmd, len))
137 cmd_page(mbox, args);
138 if (!strncmp("quit", cmd, len))
139 return;
140 if (!strncmp("x", cmd, len) || !strncmp("exit", cmd, len))
141 return;
145 int main(int argc, char *argv[])
147 int i = 0;
148 struct mbox *mbox;
149 char *filename = NULL;
150 while (++i < argc)
151 if (!strcmp("-f", argv[i]))
152 filename = argv[++i];
153 if (filename) {
154 mbox = mbox_alloc(filename);
155 loop(mbox);
156 mbox_free(mbox);
158 return 0;