send: read reply-to header
[mailx.git] / mbox.c
blob2475fce52fe619efc946427100fdf6f1c6c4c085
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.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 "str.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, char *e)
29 char *s = r;
30 char *t;
31 while (s < e) {
32 if (!strncmp("From ", s, 5) && (s == r || *(s - 1) == '\n'))
33 break;
34 t = memchr(s + 1, 'F', e - s - 1);
35 s = t ? t : e;
37 return s;
40 static char *mail_hdrs(struct mail *mail, char *s)
42 static char stat[] = "Status:";
43 char *r;
44 while (s && *s && *s != '\r' && *s != '\n') {
45 if (isalpha(*s) && mail->nhdrs < MAXHDRS)
46 mail->hdrs[mail->nhdrs++] = s;
47 if (!strncmp(stat, s, sizeof(stat) - 1))
48 mail->stat_hdr = s;
49 if ((r = strchr(s + 1, '\n')))
50 s = r + 1;
51 else
52 s = strchr(s + 1, '\0');
54 mail->hdrs[mail->nhdrs] = s;
55 return s;
58 char *mail_hdr(struct mail *mail, char *hdr)
60 int i;
61 for (i = 1; i < mail->nhdrs; i++)
62 if (startswith(mail->hdrs[i], hdr))
63 return mail->hdrs[i];
64 return NULL;
67 int hdr_len(char *hdr)
69 char *s = hdr;
70 while (*s) {
71 char *r = strchr(s, '\n');
72 if (!r)
73 return strchr(s, '\0') - hdr;
74 s = r + 1;
75 if (!isspace(*s))
76 return s - hdr;
78 return 0;
81 static void mail_stat(struct mail *mail)
83 if (mail->stat_hdr) {
84 char *s = mail->stat_hdr + strlen("Status:");
85 while (*s && *s != '\r' && *s != '\n') {
86 switch (*s++) {
87 case 'O':
88 mail->stat |= STAT_OLD;
89 break;
90 case 'N':
91 mail->stat |= STAT_NEW;
92 break;
93 case 'R':
94 mail->stat |= STAT_READ;
95 break;
98 mail->orig_stat = mail->stat;
99 } else {
100 mail->stat = STAT_NEW;
104 char *mail_read(struct mail *mail, char *s, char *e)
106 char *end;
107 mail->head = s;
108 mail->body = mail_hdrs(mail, s);
109 end = mail_start(mail->body, e);
110 mail->len = end - mail->head;
111 mail->body_len = end - mail->body;
112 mail_stat(mail);
113 return end;
116 static int read_mails(struct mbox *mbox, char *s, char *e)
118 while (s && *s && mbox->n < MAXMAILS)
119 s = mail_read(&mbox->mails[mbox->n++], s, e);
120 return mbox->n == MAXMAILS;
123 int mbox_inc(struct mbox *mbox)
125 int fd = open(mbox->path, O_RDONLY);
126 int old_n = mbox->n;
127 int old_len = mbox->len;
128 int len = file_size(fd);
129 if (fd == -1)
130 return 0;
131 if (!mbox->mbox) {
132 mbox->size = len + INCSIZE + 1;
133 mbox->mbox = malloc(mbox->size);
135 if (len > mbox->size - 1)
136 return -1;
137 if (mbox->len)
138 lseek(fd, mbox->len, SEEK_SET);
139 mbox->len += xread(fd, mbox->mbox + mbox->len, len);
140 mbox->mbox[mbox->len] = '\0';
141 close(fd);
142 set_atime(mbox->path);
143 if (old_len < mbox->len)
144 if (read_mails(mbox, mbox->mbox + old_len,
145 mbox->mbox + mbox->len))
146 return -1;
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 if (mbox_inc(mbox) < 0) {
157 mbox_free(mbox);
158 return NULL;
160 return mbox;
163 void mbox_free(struct mbox *mbox)
165 free(mbox->mbox);
166 free(mbox);
169 int mail_head(struct mail *mail, char *buf, int buf_len,
170 char **hdrs, int n)
172 int i, j;
173 char *s = buf;
174 char *dead = s + buf_len;
175 for (i = 0; i < n; i++) {
176 char *pat = hdrs[i];
177 for (j = 0; j < mail->nhdrs; j++) {
178 char *hdr = mail->hdrs[j];
179 if (startswith(hdr, pat)) {
180 int hdr_len = mail->hdrs[j + 1] - hdr;
181 if (s + hdr_len > dead)
182 hdr_len = dead - s;
183 memcpy(s, hdr, hdr_len);
184 s += hdr_len;
185 break;
189 *s = '\0';
190 return s - buf;
193 static int mail_changed(struct mail *mail)
195 return mail->orig_stat != mail->stat;
198 void mail_write(struct mail *mail, int fd)
200 char stat[32] = "Status: ";
201 char *s = strchr(stat, '\0');
202 if (mail->stat & STAT_READ)
203 *s++ = 'R';
204 if (mail->stat & (STAT_OLD | STAT_READ))
205 *s++ = 'O';
206 if (mail->stat & STAT_NEW)
207 *s++ = 'N';
208 *s++ = '\n';
209 if (!mail_changed(mail)) {
210 xwrite(fd, mail->head, mail->len);
211 } else {
212 char *hdr_beg = mail->body;
213 char *hdr_end = mail->body;
214 if (mail->stat_hdr) {
215 char *nl = strchr(mail->stat_hdr, '\n');
216 hdr_beg = mail->stat_hdr;
217 hdr_end = nl ? nl + 1 : mail->body;
219 xwrite(fd, mail->head, hdr_beg - mail->head);
220 xwrite(fd, stat, s - stat);
221 if (hdr_end)
222 xwrite(fd, hdr_end, mail->head + mail->len - hdr_end);
226 static int mbox_changed(struct mbox *mbox)
228 int i;
229 for (i = 0; i < mbox->n; i++)
230 if (mail_changed(&mbox->mails[i]))
231 return 1;
232 return 0;
235 int mbox_write(struct mbox *mbox)
237 int fd;
238 int i = 0;
239 if (mbox_inc(mbox) < 0)
240 return -1;
241 if (!mbox_changed(mbox))
242 return 0;
243 fd = open(mbox->path, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
244 while (i < mbox->n) {
245 char *beg = mbox->mails[i].head;
246 char *end = mbox->mbox + mbox->len;
247 while (i < mbox->n && !mail_changed(&mbox->mails[i]))
248 i++;
249 if (i < mbox->n)
250 end = mbox->mails[i].head;
251 xwrite(fd, beg, end - beg);
252 if (i < mbox->n && !(mbox->mails[i].stat & STAT_DEL))
253 mail_write(&mbox->mails[i], fd);
254 i++;
256 close(fd);
257 return 0;