mbox: make mail_read() non-static
[mailx.git] / mbox.c
blob435a5a15ed679de84718e549adfc651d028503ef
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 char *t;
30 while (*s) {
31 if (!strncmp("From ", s, 5) && (s == r || *(s - 1) == '\n'))
32 break;
33 if ((t = strchr(s + 1, 'F')))
34 s = t;
35 else
36 s = strchr(s, '\0');
38 return s;
41 static char *mail_hdrs(struct mail *mail, char *s)
43 static char stat[] = "Status:";
44 char *r;
45 while (s && *s && *s != '\r' && *s != '\n') {
46 if (isalpha(*s) && mail->nhdrs < MAXHDRS)
47 mail->hdrs[mail->nhdrs++] = s;
48 if (!strncasecmp(stat, s, sizeof(stat) - 1))
49 mail->stat_hdr = s;
50 if ((r = strchr(s + 1, '\n')))
51 s = r + 1;
52 else
53 s = strchr(s + 1, '\0');
55 mail->hdrs[mail->nhdrs] = s;
56 return s;
59 char *mail_hdr(struct mail *mail, char *hdr)
61 int i;
62 int len = strlen(hdr);
63 for (i = 1; i < mail->nhdrs; i++)
64 if (!strncasecmp(mail->hdrs[i], hdr, len))
65 return mail->hdrs[i];
66 return NULL;
69 int hdr_len(char *hdr)
71 char *s = hdr;
72 while (*s) {
73 char *r = strchr(s, '\n');
74 if (!r)
75 return strchr(s, '\0') - hdr;
76 s = r;
77 if (!isspace(*(s + 1)))
78 return s - hdr;
79 s++;
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 | O_LARGEFILE);
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_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);
251 close(fd);
252 return 0;