mbox: double the value of INCSIZE
[mailx.git] / mbox.c
blobc7f4d8480864f74003bfa2a3f1ad73e5bfdc4532
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <strings.h>
7 #include <time.h>
8 #include <unistd.h>
9 #include <utime.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include "mbox.h"
13 #include "util.h"
15 #define INCSIZE (1 << 22)
17 static void set_atime(char *filename)
19 struct stat st;
20 struct utimbuf times;
21 stat(filename, &st);
22 times.actime = time(NULL);
23 times.modtime = st.st_mtime;
24 utime(filename, &times);
27 static char *mail_start(char *r)
29 char *s = r;
30 char *t;
31 while (*s) {
32 if (!strncmp("From ", s, 5) && (s == r || *(s - 1) == '\n'))
33 break;
34 if ((t = strchr(s + 1, 'F')))
35 s = t;
36 else
37 s = strchr(s, '\0');
39 return s;
42 static char *mail_hdrs(struct mail *mail, char *s)
44 static char stat[] = "Status:";
45 char *r;
46 while (s && *s && *s != '\r' && *s != '\n') {
47 if (isalpha(*s) && mail->nhdrs < MAXHDRS)
48 mail->hdrs[mail->nhdrs++] = s;
49 if (!strncmp(stat, s, sizeof(stat) - 1))
50 mail->stat_hdr = s;
51 if ((r = strchr(s + 1, '\n')))
52 s = r + 1;
53 else
54 s = strchr(s + 1, '\0');
56 mail->hdrs[mail->nhdrs] = s;
57 return s;
60 char *mail_hdr(struct mail *mail, char *hdr)
62 int i;
63 int len = strlen(hdr);
64 for (i = 1; i < mail->nhdrs; i++)
65 if (!strncasecmp(mail->hdrs[i], hdr, len))
66 return mail->hdrs[i];
67 return NULL;
70 int hdr_len(char *hdr)
72 char *s = hdr;
73 while (*s) {
74 char *r = strchr(s, '\n');
75 if (!r)
76 return strchr(s, '\0') - hdr;
77 s = r + 1;
78 if (!isspace(*s))
79 return s - hdr;
81 return 0;
84 static void mail_stat(struct mail *mail)
86 if (mail->stat_hdr) {
87 char *s = mail->stat_hdr + strlen("Status:");
88 while (*s && *s != '\r' && *s != '\n') {
89 switch (*s++) {
90 case 'O':
91 mail->stat |= STAT_OLD;
92 break;
93 case 'N':
94 mail->stat |= STAT_NEW;
95 break;
96 case 'R':
97 mail->stat |= STAT_READ;
98 break;
101 mail->orig_stat = mail->stat;
102 } else {
103 mail->stat = STAT_NEW;
107 char *mail_read(struct mail *mail, char *s)
109 char *end;
110 mail->head = s;
111 mail->body = mail_hdrs(mail, s);
112 end = mail_start(mail->body);
113 mail->len = end - mail->head;
114 mail->body_len = end - mail->body;
115 mail_stat(mail);
116 return end;
119 static void read_mails(struct mbox *mbox, char *s)
121 while (s && *s)
122 s = mail_read(&mbox->mails[mbox->n++], s);
125 int mbox_inc(struct mbox *mbox)
127 int fd = open(mbox->path, O_RDONLY);
128 int old_n = mbox->n;
129 int old_len = mbox->len;
130 int len = file_size(fd);
131 if (fd == -1)
132 return 0;
133 if (!mbox->mbox) {
134 mbox->size = len + INCSIZE + 1;
135 mbox->mbox = malloc(mbox->size);
137 if (len > mbox->size - 1)
138 return -1;
139 if (mbox->len)
140 lseek(fd, mbox->len, SEEK_SET);
141 mbox->len += xread(fd, mbox->mbox + mbox->len, len);
142 mbox->mbox[mbox->len] = '\0';
143 close(fd);
144 set_atime(mbox->path);
145 if (old_len < mbox->len)
146 read_mails(mbox, mbox->mbox + old_len);
147 return mbox->n - old_n;
150 struct mbox *mbox_alloc(char *filename)
152 struct mbox *mbox;
153 mbox = malloc(sizeof(*mbox));
154 memset(mbox, 0, sizeof(*mbox));
155 strcpy(mbox->path, filename);
156 mbox_inc(mbox);
157 return mbox;
160 void mbox_free(struct mbox *mbox)
162 free(mbox->mbox);
163 free(mbox);
166 int mail_head(struct mail *mail, char *buf, int buf_len,
167 char **hdrs, int n)
169 int i, j;
170 char *s = buf;
171 char *dead = s + buf_len;
172 for (i = 0; i < n; i++) {
173 char *pat = hdrs[i];
174 int pat_len = strlen(hdrs[i]);
175 for (j = 0; j < mail->nhdrs; j++) {
176 char *hdr = mail->hdrs[j];
177 if (!strncasecmp(hdr, pat, pat_len)) {
178 int hdr_len = mail->hdrs[j + 1] - hdr;
179 if (s + hdr_len > dead)
180 hdr_len = dead - s;
181 memcpy(s, hdr, hdr_len);
182 s += hdr_len;
183 break;
187 *s = '\0';
188 return s - buf;
191 static int mail_changed(struct mail *mail)
193 return mail->orig_stat != mail->stat;
196 void mail_write(struct mail *mail, int fd)
198 char stat[32] = "Status: ";
199 char *s = strchr(stat, '\0');
200 if (mail->stat & STAT_READ)
201 *s++ = 'R';
202 *s++ = 'O';
203 *s++ = '\n';
204 if (!mail->stat_hdr) {
205 xwrite(fd, mail->head, mail->body - mail->head);
206 xwrite(fd, stat, s - stat);
207 xwrite(fd, mail->body, mail->body_len);
208 return;
210 if (!mail_changed(mail)) {
211 xwrite(fd, mail->head, mail->len);
212 } else {
213 char *hdr_end = strchr(mail->stat_hdr, '\n');
214 xwrite(fd, mail->head, mail->stat_hdr - mail->head);
215 xwrite(fd, stat, s - stat);
216 if (hdr_end)
217 xwrite(fd, hdr_end + 1,
218 mail->head + mail->len - hdr_end - 1);
222 static int mbox_changed(struct mbox *mbox)
224 int i;
225 for (i = 0; i < mbox->n; i++)
226 if (mail_changed(&mbox->mails[i]))
227 return 1;
228 return 0;
231 int mbox_write(struct mbox *mbox)
233 int fd;
234 int i = 0;
235 if (mbox_inc(mbox) == -1)
236 return -1;
237 if (!mbox_changed(mbox))
238 return 0;
239 fd = open(mbox->path, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
240 while (i < mbox->n) {
241 char *beg = mbox->mails[i].head;
242 char *end = mbox->mbox + mbox->len;
243 while (i < mbox->n && !mail_changed(&mbox->mails[i]))
244 i++;
245 if (i < mbox->n)
246 end = mbox->mails[i].head;
247 xwrite(fd, beg, end - beg);
248 if (i < mbox->n && !(mbox->mails[i].stat & STAT_DEL))
249 mail_write(&mbox->mails[i], fd);
250 i++;
252 close(fd);
253 return 0;