14 #define MBOX_N 16 /* number of mboxes */
17 char *boxpath
[MBOX_N
]; /* mbox paths */
18 char *boxbuf
[MBOX_N
]; /* mbox bufferes */
19 long boxlen
[MBOX_N
]; /* mbox buf lengths */
20 int boxcnt
[MBOX_N
]; /* number mbox messages */
21 int boxbeg
[MBOX_N
]; /* mbox's first message */
22 int boxend
[MBOX_N
]; /* mbox's last message */
23 int cnt
; /* number of mboxes */
24 char **msg
; /* messages */
25 long *msglen
; /* message lengths */
26 char **mod
; /* modified messages */
27 long *modlen
; /* modified message lengths */
28 int msgmax
; /* size of msg arrays */
29 int msgcnt
; /* number of messages */
32 static void set_atime(char *filename
)
37 times
.actime
= time(NULL
);
38 times
.modtime
= st
.st_mtime
;
39 utime(filename
, ×
);
42 static char *mbox_from_(char *s
, char *e
)
45 while (s
&& s
+ 6 < e
) {
46 if (s
[0] == 'F' && s
[1] == 'r' && s
[2] == 'o' &&
47 s
[3] == 'm' && s
[4] == ' ')
49 r
= memchr(s
, '\n', e
- s
);
50 s
= r
&& r
+ 7 < e
? r
+ 1 : NULL
;
55 int mbox_get(struct mbox
*mbox
, int i
, char **msg
, long *msglen
)
57 if (i
< 0 || i
>= mbox
->msgcnt
)
61 *msglen
= mbox
->modlen
[i
];
64 *msglen
= mbox
->msglen
[i
];
69 int mbox_set(struct mbox
*mbox
, int i
, char *msg
, long msz
)
71 if (i
< 0 || i
>= mbox
->msgcnt
)
74 mbox
->mod
[i
] = malloc(msz
+ 1);
76 mbox
->modlen
[i
] = msz
;
77 memcpy(mbox
->mod
[i
], msg
, msz
);
78 mbox
->mod
[i
][msz
] = '\0';
83 int mbox_len(struct mbox
*mbox
)
88 static void *mextend(void *old
, long oldsz
, long newsz
, long memsz
)
90 void *new = malloc(newsz
* memsz
);
91 memcpy(new, old
, oldsz
* memsz
);
92 memset(new + oldsz
* memsz
, 0, (newsz
- oldsz
) * memsz
);
97 static int mbox_extend(struct mbox
*mbox
, int cnt
)
99 mbox
->msgmax
= mbox
->msgmax
+ cnt
;
100 mbox
->msg
= mextend(mbox
->msg
, mbox
->msgcnt
, mbox
->msgmax
, sizeof(mbox
->msg
[0]));
101 mbox
->msglen
= mextend(mbox
->msglen
, mbox
->msgcnt
, mbox
->msgmax
, sizeof(mbox
->msglen
[0]));
102 if (!mbox
->msg
|| !mbox
->msglen
)
107 static int mbox_mails(struct mbox
*mbox
, char *s
, char *e
)
109 s
= mbox_from_(s
, e
);
112 if (mbox
->msgcnt
== mbox
->msgmax
)
113 if (mbox_extend(mbox
, mbox
->msgmax
? mbox
->msgmax
: 256))
115 mbox
->msg
[mbox
->msgcnt
] = s
;
116 s
= mbox_from_(s
+ 6, e
);
117 mbox
->msglen
[mbox
->msgcnt
] = s
? s
- r
: e
- r
;
123 static int filesize(int fd
)
130 static char *sdup(char *s
)
132 int n
= strlen(s
) + 1;
139 static int mbox_read(struct mbox
*mbox
, char *path
)
141 int tag
= mbox
->cnt
++;
143 mbox
->boxpath
[tag
] = sdup(path
);
144 if (!mbox
->boxpath
[tag
])
146 fd
= open(path
, O_RDONLY
);
149 mbox
->boxlen
[tag
] = filesize(fd
);
150 mbox
->boxbuf
[tag
] = malloc(mbox
->boxlen
[tag
] + 1);
151 if (!mbox
->boxbuf
[tag
])
153 xread(fd
, mbox
->boxbuf
[tag
], mbox
->boxlen
[tag
]);
154 mbox
->boxbuf
[tag
][mbox
->boxlen
[tag
]] = '\0';
156 set_atime(mbox
->boxpath
[tag
]); /* update mbox access time */
157 mbox
->boxbeg
[tag
] = mbox
->msgcnt
;
158 if (mbox_mails(mbox
, mbox
->boxbuf
[tag
], mbox
->boxbuf
[tag
] + mbox
->boxlen
[tag
]))
160 mbox
->boxend
[tag
] = mbox
->msgcnt
;
164 struct mbox
*mbox_open(char **path
)
166 struct mbox
*mbox
= malloc(sizeof(*mbox
));
169 memset(mbox
, 0, sizeof(*mbox
));
170 for (; *path
; path
++) {
171 if (mbox
->cnt
+ 1 < MBOX_N
&& mbox_read(mbox
, *path
)) {
176 mbox
->mod
= calloc(mbox
->msgcnt
, sizeof(mbox
->mod
[0]));
177 mbox
->modlen
= calloc(mbox
->msgcnt
, sizeof(mbox
->modlen
[0]));
178 if (!mbox
->mod
|| !mbox
->modlen
) {
185 void mbox_free(struct mbox
*mbox
)
188 for (i
= 0; i
< mbox
->cnt
; i
++) {
189 free(mbox
->boxpath
[i
]);
190 free(mbox
->boxbuf
[i
]);
193 for (i
= 0; i
< mbox
->msgcnt
; i
++)
203 static int mbox_modified(struct mbox
*mbox
, int tag
)
206 for (i
= mbox
->boxbeg
[tag
]; i
< mbox
->boxend
[tag
]; i
++)
212 int mbox_copy(struct mbox
*mbox
, char *path
)
216 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
219 for (i
= mbox
->boxbeg
[0]; i
< mbox
->boxend
[0]; i
++) {
220 char *msg
= mbox
->mod
[i
] ? mbox
->mod
[i
] : mbox
->msg
[i
];
221 long len
= mbox
->mod
[i
] ? mbox
->modlen
[i
] : mbox
->msglen
[i
];
222 xwrite(fd
, msg
, len
);
228 int mbox_savetag(struct mbox
*mbox
, int tag
)
235 if (!mbox_modified(mbox
, tag
))
237 for (i
= mbox
->boxbeg
[tag
]; i
< mbox
->boxend
[tag
] && !mbox
->mod
[i
]; i
++)
238 off
+= mbox
->msglen
[i
];
239 fd
= open(mbox
->boxpath
[tag
], O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
240 newlen
= filesize(fd
) - mbox
->boxlen
[tag
];
242 newbuf
= malloc(newlen
);
243 lseek(fd
, mbox
->boxlen
[tag
], 0);
244 xread(fd
, newbuf
, newlen
);
246 ftruncate(fd
, lseek(fd
, off
, 0));
247 for (; i
< mbox
->boxend
[tag
]; i
++) {
248 char *msg
= mbox
->mod
[i
] ? mbox
->mod
[i
] : mbox
->msg
[i
];
249 long len
= mbox
->mod
[i
] ? mbox
->modlen
[i
] : mbox
->msglen
[i
];
251 xwrite(fd
, msg
, len
);
255 xwrite(fd
, newbuf
, newlen
);
262 int mbox_save(struct mbox
*mbox
)
264 return mbox_savetag(mbox
, 0);
267 /* return file index of a message and its position within that file */
268 int mbox_pos(struct mbox
*mbox
, int n
, int *idx
)
271 for (i
= 1; i
< mbox
->cnt
; i
++)
272 if (n
< mbox
->boxbeg
[i
])
274 *idx
= n
- mbox
->boxbeg
[i
- 1];
278 int mbox_ith(char *path
, int n
, char **msg
, long *msz
)
280 int fd
= open(path
, O_RDONLY
);
288 buf
= malloc(len
+ 1);
295 s
= mbox_from_(buf
, e
);
296 for (i
= 0; s
&& i
< n
; i
++)
297 s
= mbox_from_(s
+ 1, e
);
300 r
= mbox_from_(s
+ 1, e
);
303 *msg
= malloc(r
- s
+ 1);
307 memcpy(*msg
, s
, *msz
);
313 int mbox_off(char *path
, long beg
, long end
, char **msg
, long *msz
)
315 int fd
= open(path
, O_RDONLY
);
319 if (lseek(fd
, beg
, 0) < 0) {
323 *msg
= malloc(end
- beg
+ 1);
326 nr
= xread(fd
, *msg
, end
- beg
);