mime: cast to unsigned char for array accesses
[mailx.git] / mbox.c
blob331fa3026287bb7484438145efb56c8911cfbdeb
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 "util.h"
14 #define INCSIZE (1 << 22)
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 t = strchr(s + 1, 'F');
34 s = t ? t : strchr(s, '\0');
36 return s;
39 static char *mail_hdrs(struct mail *mail, char *s)
41 static char stat[] = "Status:";
42 char *r;
43 while (s && *s && *s != '\r' && *s != '\n') {
44 if (isalpha(*s) && mail->nhdrs < MAXHDRS)
45 mail->hdrs[mail->nhdrs++] = s;
46 if (!strncmp(stat, s, sizeof(stat) - 1))
47 mail->stat_hdr = s;
48 if ((r = strchr(s + 1, '\n')))
49 s = r + 1;
50 else
51 s = strchr(s + 1, '\0');
53 mail->hdrs[mail->nhdrs] = s;
54 return s;
57 static int startswith(char *s, char *r)
59 while (*r) {
60 int c1 = *s++;
61 int c2 = *r++;
62 if (tolower(c1) != tolower(c2))
63 return 0;
65 return 1;
68 char *mail_hdr(struct mail *mail, char *hdr)
70 int i;
71 for (i = 1; i < mail->nhdrs; i++)
72 if (startswith(mail->hdrs[i], hdr))
73 return mail->hdrs[i];
74 return NULL;
77 int hdr_len(char *hdr)
79 char *s = hdr;
80 while (*s) {
81 char *r = strchr(s, '\n');
82 if (!r)
83 return strchr(s, '\0') - hdr;
84 s = r + 1;
85 if (!isspace(*s))
86 return s - hdr;
88 return 0;
91 static void mail_stat(struct mail *mail)
93 if (mail->stat_hdr) {
94 char *s = mail->stat_hdr + strlen("Status:");
95 while (*s && *s != '\r' && *s != '\n') {
96 switch (*s++) {
97 case 'O':
98 mail->stat |= STAT_OLD;
99 break;
100 case 'N':
101 mail->stat |= STAT_NEW;
102 break;
103 case 'R':
104 mail->stat |= STAT_READ;
105 break;
108 mail->orig_stat = mail->stat;
109 } else {
110 mail->stat = STAT_NEW;
114 char *mail_read(struct mail *mail, char *s)
116 char *end;
117 mail->head = s;
118 mail->body = mail_hdrs(mail, s);
119 end = mail_start(mail->body);
120 mail->len = end - mail->head;
121 mail->body_len = end - mail->body;
122 mail_stat(mail);
123 return end;
126 static void read_mails(struct mbox *mbox, char *s)
128 while (s && *s)
129 s = mail_read(&mbox->mails[mbox->n++], s);
132 int mbox_inc(struct mbox *mbox)
134 int fd = open(mbox->path, O_RDONLY);
135 int old_n = mbox->n;
136 int old_len = mbox->len;
137 int len = file_size(fd);
138 if (fd == -1)
139 return 0;
140 if (!mbox->mbox) {
141 mbox->size = len + INCSIZE + 1;
142 mbox->mbox = malloc(mbox->size);
144 if (len > mbox->size - 1)
145 return -1;
146 if (mbox->len)
147 lseek(fd, mbox->len, SEEK_SET);
148 mbox->len += xread(fd, mbox->mbox + mbox->len, len);
149 mbox->mbox[mbox->len] = '\0';
150 close(fd);
151 set_atime(mbox->path);
152 if (old_len < mbox->len)
153 read_mails(mbox, mbox->mbox + old_len);
154 return mbox->n - old_n;
157 struct mbox *mbox_alloc(char *filename)
159 struct mbox *mbox;
160 mbox = malloc(sizeof(*mbox));
161 memset(mbox, 0, sizeof(*mbox));
162 strcpy(mbox->path, filename);
163 mbox_inc(mbox);
164 return mbox;
167 void mbox_free(struct mbox *mbox)
169 free(mbox->mbox);
170 free(mbox);
173 int mail_head(struct mail *mail, char *buf, int buf_len,
174 char **hdrs, int n)
176 int i, j;
177 char *s = buf;
178 char *dead = s + buf_len;
179 for (i = 0; i < n; i++) {
180 char *pat = hdrs[i];
181 for (j = 0; j < mail->nhdrs; j++) {
182 char *hdr = mail->hdrs[j];
183 if (startswith(hdr, pat)) {
184 int hdr_len = mail->hdrs[j + 1] - hdr;
185 if (s + hdr_len > dead)
186 hdr_len = dead - s;
187 memcpy(s, hdr, hdr_len);
188 s += hdr_len;
189 break;
193 *s = '\0';
194 return s - buf;
197 static int mail_changed(struct mail *mail)
199 return mail->orig_stat != mail->stat;
202 void mail_write(struct mail *mail, int fd)
204 char stat[32] = "Status: ";
205 char *s = strchr(stat, '\0');
206 if (mail->stat & STAT_READ)
207 *s++ = 'R';
208 if (mail->stat & STAT_OLD)
209 *s++ = 'O';
210 if (mail->stat & STAT_NEW)
211 *s++ = 'N';
212 *s++ = '\n';
213 if (!mail_changed(mail)) {
214 xwrite(fd, mail->head, mail->len);
215 } else {
216 char *hdr_beg = mail->body;
217 char *hdr_end = mail->body;
218 if (mail->stat_hdr) {
219 char *nl = strchr(mail->stat_hdr, '\n');
220 hdr_beg = mail->stat_hdr;
221 hdr_end = nl ? nl + 1 : mail->body;
223 xwrite(fd, mail->head, hdr_beg - mail->head);
224 xwrite(fd, stat, s - stat);
225 if (hdr_end)
226 xwrite(fd, hdr_end, mail->head + mail->len - hdr_end);
230 static int mbox_changed(struct mbox *mbox)
232 int i;
233 for (i = 0; i < mbox->n; i++)
234 if (mail_changed(&mbox->mails[i]))
235 return 1;
236 return 0;
239 int mbox_write(struct mbox *mbox)
241 int fd;
242 int i = 0;
243 if (mbox_inc(mbox) == -1)
244 return -1;
245 if (!mbox_changed(mbox))
246 return 0;
247 fd = open(mbox->path, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
248 while (i < mbox->n) {
249 char *beg = mbox->mails[i].head;
250 char *end = mbox->mbox + mbox->len;
251 while (i < mbox->n && !mail_changed(&mbox->mails[i]))
252 i++;
253 if (i < mbox->n)
254 end = mbox->mails[i].head;
255 xwrite(fd, beg, end - beg);
256 if (i < mbox->n && !(mbox->mails[i].stat & STAT_DEL))
257 mail_write(&mbox->mails[i], fd);
258 i++;
260 close(fd);
261 return 0;