fix some errors with glibc
[mailx.git] / mbox.c
blobd485b822e32c83d4c934406b0572ead2e91507b6
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 << 21)
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;
78 if (!isspace(*(s + 1)))
79 return s - hdr;
80 s++;
82 return 0;
85 static void mail_stat(struct mail *mail)
87 if (mail->stat_hdr) {
88 char *s = mail->stat_hdr + strlen("Status:");
89 while (*s && *s != '\r' && *s != '\n') {
90 switch (*s++) {
91 case 'O':
92 mail->stat |= STAT_OLD;
93 break;
94 case 'N':
95 mail->stat |= STAT_NEW;
96 break;
97 case 'R':
98 mail->stat |= STAT_READ;
99 break;
102 mail->orig_stat = mail->stat;
103 } else {
104 mail->stat = STAT_NEW;
108 char *mail_read(struct mail *mail, char *s)
110 char *end;
111 mail->head = s;
112 mail->body = mail_hdrs(mail, s);
113 end = mail_start(mail->body);
114 mail->len = end - mail->head;
115 mail->body_len = end - mail->body;
116 mail_stat(mail);
117 return end;
120 static void read_mails(struct mbox *mbox, char *s)
122 while (s && *s)
123 s = mail_read(&mbox->mails[mbox->n++], s);
126 int mbox_inc(struct mbox *mbox)
128 int fd = open(mbox->path, O_RDONLY);
129 int old_n = mbox->n;
130 int old_len = mbox->len;
131 int len = file_size(fd);
132 if (fd == -1)
133 return 0;
134 if (!mbox->mbox) {
135 mbox->size = len + INCSIZE + 1;
136 mbox->mbox = malloc(mbox->size);
138 if (len > mbox->size - 1)
139 return -1;
140 if (mbox->len)
141 lseek(fd, mbox->len, SEEK_SET);
142 mbox->len += xread(fd, mbox->mbox + mbox->len, len);
143 mbox->mbox[mbox->len] = '\0';
144 close(fd);
145 set_atime(mbox->path);
146 if (old_len < mbox->len)
147 read_mails(mbox, mbox->mbox + old_len);
148 return mbox->n - old_n;
151 struct mbox *mbox_alloc(char *filename)
153 struct mbox *mbox;
154 mbox = malloc(sizeof(*mbox));
155 memset(mbox, 0, sizeof(*mbox));
156 strcpy(mbox->path, filename);
157 mbox_inc(mbox);
158 return mbox;
161 void mbox_free(struct mbox *mbox)
163 free(mbox->mbox);
164 free(mbox);
167 int mail_head(struct mail *mail, char *buf, int buf_len,
168 char **hdrs, int n)
170 int i, j;
171 char *s = buf;
172 char *dead = s + buf_len;
173 for (i = 0; i < n; i++) {
174 char *pat = hdrs[i];
175 int pat_len = strlen(hdrs[i]);
176 for (j = 0; j < mail->nhdrs; j++) {
177 char *hdr = mail->hdrs[j];
178 if (!strncasecmp(hdr, pat, pat_len)) {
179 int hdr_len = mail->hdrs[j + 1] - hdr;
180 if (s + hdr_len > dead)
181 hdr_len = dead - s;
182 memcpy(s, hdr, hdr_len);
183 s += hdr_len;
184 break;
188 *s = '\0';
189 return s - buf;
192 static int mail_changed(struct mail *mail)
194 return mail->orig_stat != mail->stat;
197 void mail_write(struct mail *mail, int fd)
199 char stat[32] = "Status: ";
200 char *s = strchr(stat, '\0');
201 if (mail->stat & STAT_READ)
202 *s++ = 'R';
203 *s++ = 'O';
204 *s++ = '\n';
205 if (!mail->stat_hdr) {
206 xwrite(fd, mail->head, mail->body - mail->head);
207 xwrite(fd, stat, s - stat);
208 xwrite(fd, mail->body, mail->body_len);
209 return;
211 if (!mail_changed(mail)) {
212 xwrite(fd, mail->head, mail->len);
213 } else {
214 char *hdr_end = strchr(mail->stat_hdr, '\n');
215 xwrite(fd, mail->head, mail->stat_hdr - mail->head);
216 xwrite(fd, stat, s - stat);
217 if (hdr_end)
218 xwrite(fd, hdr_end + 1,
219 mail->head + mail->len - hdr_end - 1);
223 static int mbox_changed(struct mbox *mbox)
225 int i;
226 for (i = 0; i < mbox->n; i++)
227 if (mail_changed(&mbox->mails[i]))
228 return 1;
229 return 0;
232 int mbox_write(struct mbox *mbox)
234 int fd;
235 int i = 0;
236 if (mbox_inc(mbox) == -1)
237 return -1;
238 if (!mbox_changed(mbox))
239 return 0;
240 fd = open(mbox->path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
241 while (i < mbox->n) {
242 char *beg = mbox->mails[i].head;
243 char *end = mbox->mbox + mbox->len;
244 while (i < mbox->n && !mail_changed(&mbox->mails[i]))
245 i++;
246 if (i < mbox->n)
247 end = mbox->mails[i].head;
248 xwrite(fd, beg, end - beg);
249 if (i < mbox->n || !(mbox->mails[i].stat & STAT_DEL))
250 mail_write(&mbox->mails[i++], fd);
252 close(fd);
253 return 0;