12 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
13 #define MIN(a, b) ((a) < (b) ? (a) : (b))
14 #define MAXLINE (1 << 7)
15 #define BUFSIZE (1 << 12)
17 static struct mbox
*mbox
;
18 static struct sort
*sort
;
21 static int read_line(char *dst
, int size
)
23 static char buf
[BUFSIZE
];
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
;
32 memcpy(dst
+ nw
, buf
+ cur
, nr
);
37 if (nl
|| nw
== size
- 1)
40 if ((len
= read(STDIN_FILENO
, buf
, BUFSIZE
)) <= 0)
46 static char *till_eol(char *r
, int len
, char *s
)
49 while (r
< d
&& *s
&& *s
!= '\r' && *s
!= '\n')
54 static char *cut_word(char *dst
, char *s
)
64 static int msg_num(char *num
)
67 if (!*num
|| !strcmp(".", num
))
71 if (!strcmp("$", num
))
73 if (!strcmp(",", num
)) {
75 while (++i
< sort
->n
) {
76 if (!(sort
->mails
[i
]->stat
& STAT_READ
)) {
82 if (n
< 0 || n
>= mbox
->n
)
88 static void cmd_page(char *args
)
96 args
= cut_word(num
, args
);
97 if (msg_num(num
) == -1)
99 mail
= sort
->mails
[cur
];
100 mail
->stat
|= STAT_READ
;
102 if (!(pid
= fork())) {
103 char *args
[] = {PAGER
, NULL
};
105 dup2(fds
[0], STDIN_FILENO
);
110 hdr_len
= mail_head(mail
, head
, sizeof(head
),
111 hdr_filt
, ARRAY_SIZE(hdr_filt
));
112 write(fds
[1], head
, hdr_len
);
113 write(fds
[1], mail
->body
, mail
->body_len
);
115 waitpid(pid
, NULL
, 0);
118 static char *cut_cmd(char *dst
, char *s
)
120 while (isalpha(*s
)) {
127 static char *put_int(char *s
, int n
, int w
)
130 for (i
= 0; i
< w
; i
++) {
131 s
[w
- i
- 1] = n
|| !i
? '0' + n
% 10 : ' ';
137 static char *put_str(char *dst
, char *src
)
139 int len
= strchr(src
, '\0') - src
;
140 memcpy(dst
, src
, len
+ 1);
144 static char *put_hdr(struct mail
*mail
, char *name
, int w
, char *s
)
146 char *hdr
= mail_hdr(mail
, name
);
147 return till_eol(s
, w
, hdr
? hdr
+ strlen(name
) + 1 : NULL
);
150 static void cmd_head(char *args
)
155 args
= cut_word(num
, args
);
156 if (msg_num(num
) == -1)
158 beg
= cur
/ NHEAD
* NHEAD
;
159 end
= MIN(beg
+ NHEAD
, mbox
->n
);
160 for (i
= beg
; i
< end
; i
++) {
161 struct mail
*mail
= sort
->mails
[i
];
164 *s
++ = i
== cur
? '>' : ' ';
165 if (mail
->stat
& STAT_READ
)
168 *s
++ = mail
->stat
& STAT_NEW
? 'N' : 'O';
169 s
= put_int(s
, i
, DIGITS
);
172 s
= put_hdr(mail
, "From:", 16, s
);
175 s
= sort_draw(sort
, i
, s
, WIDTH
- (s
- fmt
));
176 s
= put_hdr(mail
, "Subject:", WIDTH
- (s
- fmt
), s
);
178 write(STDOUT_FILENO
, fmt
, s
- fmt
);
182 static void cmd_z(char *args
)
188 page
= MIN(cur
+ NHEAD
, mbox
->n
) / NHEAD
;
189 if (*num
== '+' || *num
== '-') {
190 int d
= (*num
+ 1) ? (*num
== '-' ? -1 : 1) : atoi(num
);
191 page
= cur
/ NHEAD
+ d
;
194 page
= mbox
->n
/ NHEAD
;
197 if (page
>= 0 && page
* NHEAD
< mbox
->n
) {
203 static void print(char *s
)
205 write(STDOUT_FILENO
, s
, strlen(s
));
208 static void open_mbox(char *filename
)
210 mbox
= mbox_alloc(filename
);
211 sort
= sort_alloc(mbox
);
215 static void close_mbox(void)
221 static int is_mbox(char *filename
)
225 return S_ISREG(st
.st_mode
);
228 static void sum_mbox(void)
231 char *s
= put_int(msg
, mbox
->n
, DIGITS
);
235 s
= put_str(s
, " messages ");
236 for (i
= 0; i
< mbox
->n
; i
++)
237 if (mbox
->mails
[i
].stat
& STAT_NEW
)
239 else if (!(mbox
->mails
[i
].stat
& STAT_READ
))
242 s
= put_int(s
, new, DIGITS
);
243 s
= put_str(s
, " new ");
246 s
= put_int(s
, unread
, DIGITS
);
247 s
= put_str(s
, " unread ");
249 s
= put_str(s
, "\n");
253 static int has_mail(char *path
)
256 if (stat(path
, &st
) == -1)
258 return st
.st_mtime
> st
.st_atime
;
261 static int mbox_path(char *path
, char *addr
)
266 s
= put_str(s
, FOLDER
);
267 s
= put_str(s
, addr
+ 1);
270 for (i
= 0; i
< ARRAY_SIZE(boxes
); i
++) {
271 if (has_mail(boxes
[i
])) {
272 s
= put_str(s
, boxes
[i
]);
277 if (!strcmp(".", addr
) && mbox
)
278 s
= put_str(s
, mbox
->path
);
279 if (s
== path
&& *addr
)
280 s
= put_str(s
, addr
);
284 static void cmd_fold(char *args
)
286 char filename
[MAXLINE
];
287 args
= cut_word(filename
, args
);
289 char path
[MAXPATHLEN
];
290 if (mbox_path(path
, filename
) && is_mbox(path
)) {
299 static void cmd_inc(char *args
)
302 int new = mbox_inc(mbox
);
307 s
= put_int(msg
, new, DIGITS
);
308 s
= put_str(s
, " new\n");
311 for (i
= 0; i
< ARRAY_SIZE(boxes
); i
++) {
312 if (has_mail(boxes
[i
])) {
313 char *box
= strrchr(boxes
[i
], '/');
315 box
= box
? box
+ 1 : boxes
[i
];
316 s
= put_str(s
, "mbox: ");
318 s
= put_str(s
, "\n");
324 static void prompt(void)
326 write(STDOUT_FILENO
, "? ", 2);
329 static void loop(void)
334 while (read_line(line
, sizeof(line
)) > 0) {
335 char *args
= cut_cmd(cmd
, line
);
336 int len
= strlen(cmd
);
338 if (cur
+ 1 < mbox
->n
) {
347 if (!strncmp("page", cmd
, len
))
349 if (!strncmp("header", cmd
, len
))
351 if (!strncmp("file", cmd
, len
) || !strncmp("folder", cmd
, len
))
353 if (!strncmp("inc", cmd
, len
))
355 if (!strncmp("z", cmd
, len
))
357 if (!strncmp("quit", cmd
, len
)) {
361 if (!strncmp("xit", cmd
, len
) || !strncmp("exit", cmd
, len
))
367 int main(int argc
, char *argv
[])
370 char *filename
= NULL
;
372 if (!strcmp("-f", argv
[i
]))
373 filename
= argv
[++i
];
375 char path
[MAXPATHLEN
];
376 if (mbox_path(path
, filename
) && is_mbox(path
)) {