mbox: don't write the mbox if no mem for new msgs
[mailx.git] / mbox.c
blob7ec8c53c3ee9c753e129d00a04f2570abfe5ac6e
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 <unistd.h>
8 #include <utime.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include "mbox.h"
12 #include "util.h"
14 #define INCSIZE (1 << 21)
16 static void set_atime(char *filename)
18 struct stat st;
19 struct utimbuf times;
20 stat(filename, &st);
21 times.actime = time(NULL);
22 times.modtime = st.st_mtime;
23 utime(filename, &times);
26 static char *mail_start(char *r)
28 char *s = r;
29 while (s) {
30 if (!strncmp("From ", s, 5) && (s == r || *(s - 1) == '\n'))
31 break;
32 s = strchr(s + 1, 'F');
34 return s;
37 static char *mail_hdrs(struct mail *mail, char *s)
39 static char stat[] = "Status:";
40 while (s && *s && *s != '\r' && *s != '\n') {
41 if (isalpha(*s) && mail->nhdrs < MAXHDRS)
42 mail->hdrs[mail->nhdrs++] = s;
43 if (!strncasecmp(stat, s, sizeof(stat) - 1))
44 mail->stat_hdr = s;
45 s = strchr(s + 1, '\n');
46 s = s ? s + 1 : s;
48 mail->hdrs[mail->nhdrs] = s;
49 return s;
52 char *mail_hdr(struct mail *mail, char *hdr)
54 int i;
55 int len = strlen(hdr);
56 for (i = 0; i < mail->nhdrs; i++)
57 if (!strncasecmp(mail->hdrs[i], hdr, len))
58 return mail->hdrs[i];
59 return NULL;
62 int hdr_len(char *hdr)
64 char *s = hdr;
65 while (*s) {
66 char *r = strchr(s, '\n');
67 if (!r)
68 return strchr(s, '\0') - hdr;
69 s = r;
70 if (!isspace(*(s + 1)))
71 return s - hdr;
72 s++;
74 return 0;
77 static void mail_stat(struct mail *mail)
79 if (mail->stat_hdr) {
80 char *s = mail->stat_hdr + strlen("Status:");
81 while (*s && *s != '\r' && *s != '\n') {
82 switch (*s++) {
83 case 'O':
84 mail->stat |= STAT_OLD;
85 break;
86 case 'N':
87 mail->stat |= STAT_NEW;
88 break;
89 case 'R':
90 mail->stat |= STAT_READ;
91 break;
94 mail->orig_stat = mail->stat;
95 } else {
96 mail->stat = STAT_NEW;
100 static char *mail_read(struct mail *mail, char *s)
102 char *end;
103 int last = 0;
104 mail->head = s;
105 mail->body = mail_hdrs(mail, s);
106 if (!(end = mail_start(mail->body))) {
107 last = 1;
108 end = strchr(mail->body, '\0');
110 mail->len = end - mail->head;
111 mail->body_len = end - mail->body;
112 mail_stat(mail);
113 return last ? NULL : end;
116 static void read_mails(struct mbox *mbox, char *s)
118 while (s)
119 s = mail_read(&mbox->mails[mbox->n++], s);
122 int mbox_inc(struct mbox *mbox)
124 int fd = open(mbox->path, O_RDONLY | O_LARGEFILE);
125 int old_n = mbox->n;
126 int old_len = mbox->len;
127 int len = file_size(fd);
128 if (fd == -1)
129 return 0;
130 if (!mbox->mbox) {
131 mbox->size = len + INCSIZE + 1;
132 mbox->mbox = malloc(mbox->size);
134 if (len > mbox->size - 1)
135 return -1;
136 if (mbox->len)
137 lseek(fd, mbox->len, SEEK_SET);
138 mbox->len += xread(fd, mbox->mbox + mbox->len, len);
139 mbox->mbox[mbox->len] = '\0';
140 close(fd);
141 set_atime(mbox->path);
142 if (old_len < mbox->len)
143 read_mails(mbox, mbox->mbox + old_len);
144 return mbox->n - old_n;
147 struct mbox *mbox_alloc(char *filename)
149 struct mbox *mbox;
150 mbox = malloc(sizeof(*mbox));
151 memset(mbox, 0, sizeof(*mbox));
152 strcpy(mbox->path, filename);
153 mbox_inc(mbox);
154 return mbox;
157 void mbox_free(struct mbox *mbox)
159 free(mbox->mbox);
160 free(mbox);
163 int mail_head(struct mail *mail, char *buf, int buf_len,
164 char **hdrs, int n)
166 int i, j;
167 char *s = buf;
168 char *dead = s + buf_len;
169 for (i = 0; i < n; i++) {
170 char *pat = hdrs[i];
171 int pat_len = strlen(hdrs[i]);
172 for (j = 0; j < mail->nhdrs; j++) {
173 char *hdr = mail->hdrs[j];
174 if (!strncasecmp(hdr, pat, pat_len)) {
175 int hdr_len = mail->hdrs[j + 1] - hdr;
176 if (s + hdr_len > dead)
177 hdr_len = dead - s;
178 memcpy(s, hdr, hdr_len);
179 s += hdr_len;
180 break;
184 *s = '\0';
185 return s - buf;
188 static int mail_changed(struct mail *mail)
190 return mail->orig_stat != mail->stat;
193 void mail_write(struct mail *mail, int fd)
195 char stat[32] = "Status: ";
196 char *s = strchr(stat, '\0');
197 if (mail->stat & STAT_READ)
198 *s++ = 'R';
199 *s++ = 'O';
200 *s++ = '\n';
201 if (!mail->stat_hdr) {
202 xwrite(fd, mail->head, mail->body - mail->head);
203 write(fd, stat, s - stat);
204 write(fd, mail->body, mail->body_len);
205 } else {
206 char *hdr_end = strchr(mail->stat_hdr, '\n');
207 xwrite(fd, mail->head, mail->stat_hdr - mail->head);
208 write(fd, stat, s - stat);
209 if (hdr_end)
210 write(fd, hdr_end + 1,
211 mail->head + mail->len - hdr_end - 1);
215 static int mbox_changed(struct mbox *mbox)
217 int i;
218 for (i = 0; i < mbox->n; i++)
219 if (mail_changed(&mbox->mails[i]))
220 return 1;
221 return 0;
224 int mbox_write(struct mbox *mbox)
226 int fd;
227 int i = 0;
228 if (mbox_inc(mbox) == -1)
229 return -1;
230 if (!mbox_changed(mbox))
231 return 0;
232 fd = open(mbox->path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
233 while (i < mbox->n) {
234 char *beg = mbox->mails[i].head;
235 char *end = mbox->mbox + mbox->len;
236 while (i < mbox->n && !mail_changed(&mbox->mails[i]))
237 i++;
238 if (i < mbox->n)
239 end = mbox->mails[i].head;
240 xwrite(fd, beg, end - beg);
241 if (i < mbox->n)
242 mail_write(&mbox->mails[i++], fd);
244 close(fd);
245 return 0;