15 #define INCSIZE (1 << 22)
17 static void set_atime(char *filename
)
22 times
.actime
= time(NULL
);
23 times
.modtime
= st
.st_mtime
;
24 utime(filename
, ×
);
27 static char *mail_start(char *r
, char *e
)
32 if (!strncmp("From ", s
, 5) && (s
== r
|| *(s
- 1) == '\n'))
34 t
= memchr(s
+ 1, 'F', e
- s
- 1);
40 static char *mail_hdrs(struct mail
*mail
, char *s
)
42 static char stat
[] = "Status:";
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))
49 if ((r
= strchr(s
+ 1, '\n')))
52 s
= strchr(s
+ 1, '\0');
54 mail
->hdrs
[mail
->nhdrs
] = s
;
58 char *mail_hdr(struct mail
*mail
, char *hdr
)
61 for (i
= 1; i
< mail
->nhdrs
; i
++)
62 if (startswith(mail
->hdrs
[i
], hdr
))
67 int hdr_len(char *hdr
)
71 char *r
= strchr(s
, '\n');
73 return strchr(s
, '\0') - hdr
;
81 static void mail_stat(struct mail
*mail
)
84 char *s
= mail
->stat_hdr
+ strlen("Status:");
85 while (*s
&& *s
!= '\r' && *s
!= '\n') {
88 mail
->stat
|= STAT_OLD
;
91 mail
->stat
|= STAT_NEW
;
94 mail
->stat
|= STAT_READ
;
98 mail
->orig_stat
= mail
->stat
;
100 mail
->stat
= STAT_NEW
;
104 char *mail_read(struct mail
*mail
, char *s
, char *e
)
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
;
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
);
127 int old_len
= mbox
->len
;
128 int len
= file_size(fd
);
132 mbox
->size
= len
+ INCSIZE
+ 1;
133 mbox
->mbox
= malloc(mbox
->size
);
135 if (!mbox
->mbox
|| len
> mbox
->size
- 1)
138 lseek(fd
, mbox
->len
, SEEK_SET
);
139 mbox
->len
+= xread(fd
, mbox
->mbox
+ mbox
->len
, len
);
140 mbox
->mbox
[mbox
->len
] = '\0';
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
))
147 return mbox
->n
- old_n
;
150 struct mbox
*mbox_alloc(char *filename
)
153 mbox
= malloc(sizeof(*mbox
));
156 memset(mbox
, 0, sizeof(*mbox
));
157 strcpy(mbox
->path
, filename
);
158 if (mbox_inc(mbox
) < 0) {
165 void mbox_free(struct mbox
*mbox
)
171 int mail_head(struct mail
*mail
, char *buf
, int buf_len
,
176 char *dead
= s
+ buf_len
;
177 for (i
= 0; i
< n
; i
++) {
179 for (j
= 0; j
< mail
->nhdrs
; j
++) {
180 char *hdr
= mail
->hdrs
[j
];
181 if (startswith(hdr
, pat
)) {
182 int hdr_len
= mail
->hdrs
[j
+ 1] - hdr
;
183 if (s
+ hdr_len
> dead
)
185 memcpy(s
, hdr
, hdr_len
);
195 static int mail_changed(struct mail
*mail
)
197 return mail
->orig_stat
!= mail
->stat
;
200 void mail_write(struct mail
*mail
, int fd
)
202 char stat
[32] = "Status: ";
203 char *s
= strchr(stat
, '\0');
204 if (mail
->stat
& STAT_READ
)
206 if (mail
->stat
& (STAT_OLD
| STAT_READ
))
208 if (mail
->stat
& STAT_NEW
)
211 if (!mail_changed(mail
)) {
212 xwrite(fd
, mail
->head
, mail
->len
);
214 char *hdr_beg
= mail
->body
;
215 char *hdr_end
= mail
->body
;
216 if (mail
->stat_hdr
) {
217 char *nl
= strchr(mail
->stat_hdr
, '\n');
218 hdr_beg
= mail
->stat_hdr
;
219 hdr_end
= nl
? nl
+ 1 : mail
->body
;
221 xwrite(fd
, mail
->head
, hdr_beg
- mail
->head
);
222 xwrite(fd
, stat
, s
- stat
);
224 xwrite(fd
, hdr_end
, mail
->head
+ mail
->len
- hdr_end
);
228 static int mbox_changed(struct mbox
*mbox
)
231 for (i
= 0; i
< mbox
->n
; i
++)
232 if (mail_changed(&mbox
->mails
[i
]))
237 int mbox_write(struct mbox
*mbox
)
241 if (mbox_inc(mbox
) < 0)
243 if (!mbox_changed(mbox
))
245 fd
= open(mbox
->path
, O_WRONLY
| O_TRUNC
| O_CREAT
, S_IRUSR
| S_IWUSR
);
246 while (i
< mbox
->n
) {
247 char *beg
= mbox
->mails
[i
].head
;
248 char *end
= mbox
->mbox
+ mbox
->len
;
249 while (i
< mbox
->n
&& !mail_changed(&mbox
->mails
[i
]))
252 end
= mbox
->mails
[i
].head
;
253 xwrite(fd
, beg
, end
- beg
);
254 if (i
< mbox
->n
&& !(mbox
->mails
[i
].stat
& STAT_DEL
))
255 mail_write(&mbox
->mails
[i
], fd
);