mime: fix uninitialised mime->depth
[neatmail.git] / mbox.c
blobe38f4a369e1fab1a708836674bba43d38835db74
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <time.h>
10 #include <unistd.h>
11 #include <utime.h>
12 #include "mail.h"
14 struct mbox {
15 char *path;
16 char **msg; /* messages */
17 long *msglen; /* message lengths */
18 char **mod; /* modified messages */
19 long *modlen; /* modified message lengths */
20 char *buf; /* mbox buffer */
21 long len; /* buf len */
22 int n; /* number of messages */
25 static void set_atime(char *filename)
27 struct stat st;
28 struct utimbuf times;
29 stat(filename, &st);
30 times.actime = time(NULL);
31 times.modtime = st.st_mtime;
32 utime(filename, &times);
35 static char *mbox_from_(char *s, char *e)
37 char *r;
38 while (s && s + 6 < e) {
39 if (s[0] == 'F' && s[1] == 'r' && s[2] == 'o' &&
40 s[3] == 'm' && s[4] == ' ')
41 return s;
42 r = memchr(s, '\n', e - s);
43 s = r && r + 7 < e ? r + 1 : NULL;
45 return NULL;
48 static int mbox_count(char *s, char *e)
50 int n = 0;
51 while ((s = mbox_from_(s, e)))
52 n++, s++;
53 return n;
56 int mbox_get(struct mbox *mbox, int i, char **msg, long *msglen)
58 if (i < 0 || i >= mbox->n)
59 return 1;
60 if (mbox->mod[i]) {
61 *msg = mbox->mod[i];
62 *msglen = mbox->modlen[i];
63 } else {
64 *msg = mbox->msg[i];
65 *msglen = mbox->msglen[i];
67 return 0;
70 int mbox_set(struct mbox *mbox, int i, char *msg, long msz)
72 if (i < 0 || i >= mbox->n)
73 return 1;
74 free(mbox->mod[i]);
75 mbox->mod[i] = malloc(msz + 1);
76 if (mbox->mod[i]) {
77 mbox->modlen[i] = msz;
78 memcpy(mbox->mod[i], msg, msz);
79 mbox->mod[i][msz] = '\0';
81 return 0;
84 int mbox_len(struct mbox *mbox)
86 return mbox->n;
89 static int mbox_mails(struct mbox *mbox, char *s, char *e)
91 int i;
92 s = mbox_from_(s, e);
93 for (i = 0; s && s < e; i++) {
94 char *r = s;
95 mbox->msg[i] = s;
96 s = mbox_from_(s + 6, e);
97 mbox->msglen[i] = s ? s - r : mbox->buf + mbox->len - r;
99 mbox->n = i;
100 return 0;
103 static int filesize(int fd)
105 struct stat stat;
106 fstat(fd, &stat);
107 return stat.st_size;
110 static int mbox_read(struct mbox *mbox)
112 int fd = open(mbox->path, O_RDONLY);
113 if (fd < 0)
114 return 1;
115 mbox->len = filesize(fd);
116 mbox->buf = malloc(mbox->len + 1);
117 if (!mbox->buf)
118 return 1;
119 xread(fd, mbox->buf, mbox->len);
120 mbox->buf[mbox->len] = '\0';
121 close(fd);
122 set_atime(mbox->path); /* update mbox access time */
123 mbox->n = mbox_count(mbox->buf, mbox->buf + mbox->len);
124 mbox->msg = malloc(mbox->n * sizeof(mbox->msg[0]));
125 mbox->msglen = malloc(mbox->n * sizeof(mbox->msglen[0]));
126 mbox->mod = malloc(mbox->n * sizeof(mbox->mod[0]));
127 mbox->modlen = malloc(mbox->n * sizeof(mbox->modlen[0]));
128 memset(mbox->mod, 0, mbox->n * sizeof(mbox->mod[0]));
129 if (!mbox->msg || !mbox->msglen || !mbox->mod || !mbox->modlen)
130 return 1;
131 if (mbox_mails(mbox, mbox->buf, mbox->buf + mbox->len))
132 return 1;
133 return 0;
136 static char *sdup(char *s)
138 int n = strlen(s) + 1;
139 char *r = malloc(n);
140 if (r)
141 memcpy(r, s, n);
142 return r;
145 struct mbox *mbox_open(char *path)
147 struct mbox *mbox;
148 mbox = malloc(sizeof(*mbox));
149 if (!mbox)
150 return NULL;
151 memset(mbox, 0, sizeof(*mbox));
152 mbox->path = sdup(path);
153 if (!mbox->path || mbox_read(mbox)) {
154 mbox_free(mbox);
155 return NULL;
157 return mbox;
160 void mbox_free(struct mbox *mbox)
162 int i;
163 for (i = 0; i < mbox->n; i++)
164 free(mbox->mod[i]);
165 free(mbox->msg);
166 free(mbox->msglen);
167 free(mbox->mod);
168 free(mbox->modlen);
169 free(mbox->path);
170 free(mbox->buf);
171 free(mbox);
174 static int mbox_modified(struct mbox *mbox)
176 int i;
177 for (i = 0; i < mbox->n; i++)
178 if (mbox->mod[i])
179 return 1;
180 return 0;
183 int mbox_copy(struct mbox *mbox, char *path)
185 int fd;
186 int i;
187 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
188 if (fd < 0)
189 return -1;
190 for (i = 0; i < mbox->n; i++) {
191 char *msg = mbox->mod[i] ? mbox->mod[i] : mbox->msg[i];
192 long len = mbox->mod[i] ? mbox->modlen[i] : mbox->msglen[i];
193 xwrite(fd, msg, len);
195 close(fd);
196 return 0;
199 int mbox_save(struct mbox *mbox)
201 int fd;
202 int i = 0;
203 char *newbuf;
204 long off = 0;
205 long newlen;
206 if (!mbox_modified(mbox))
207 return 0;
208 fd = open(mbox->path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
209 newlen = filesize(fd) - mbox->len;
210 if (newlen > 0) {
211 newbuf = malloc(newlen);
212 lseek(fd, mbox->len, 0);
213 xread(fd, newbuf, newlen);
215 while (i < mbox->n && !mbox->mod[i])
216 off += mbox->msglen[i++];
217 lseek(fd, off, 0);
218 for (; i < mbox->n; i++) {
219 char *msg = mbox->mod[i] ? mbox->mod[i] : mbox->msg[i];
220 long len = mbox->mod[i] ? mbox->modlen[i] : mbox->msglen[i];
221 xwrite(fd, msg, len);
223 ftruncate(fd, lseek(fd, 0, 1));
224 close(fd);
225 return newlen;
228 int mbox_ith(char *path, int n, char **msg, long *msz)
230 int fd = open(path, O_RDONLY);
231 char *s, *e, *r;
232 char *buf;
233 int len;
234 int i;
235 if (fd < 0)
236 return 1;
237 len = filesize(fd);
238 buf = malloc(len + 1);
239 if (!buf)
240 return 1;
241 xread(fd, buf, len);
242 buf[len] = '\0';
243 close(fd);
244 e = buf + len;
245 s = mbox_from_(buf, e);
246 for (i = 0; s && i < n; i++)
247 s = mbox_from_(s + 1, e);
248 if (!s)
249 return 1;
250 r = mbox_from_(s + 1, e);
251 if (!r)
252 r = buf + len;
253 *msg = malloc(r - s + 1);
254 if (!*msg)
255 return 1;
256 *msz = r - s;
257 memcpy(*msg, s, *msz);
258 (*msg)[*msz] = '\0';
259 free(buf);
260 return 0;