6 findcache(Mcache *c, Message *m)
10 for(i = 0; i < c->ntab; i++)
17 prcache(Mcache *c, char *prefix)
24 for(j = 0; j < c->ntab; j++){
26 dprint("%s%d/%s\t%p\t%d\t%ld\n", prefix, j, m->name, m, m->refs, m->csize);
38 for(i = 0; i < c->ntab; i++)
39 for(j = i + 1; j < c->ntab; j++)
40 if(c->ctab[i] == c->ctab[j])
44 for(j = 0; j < c->ntab; j++)
45 dprint("%d\t%p %d\t%ld\n", j, c->ctab[j], c->ctab[j]->refs, c->ctab[j]->size);
50 addcache(Mcache *c, Message *m)
54 if((i = findcache(c, m)) < 0){
55 if(c->ntab + 1 == nelem(c->ctab))
61 return i; /* silly shortcut to prevent excessive printage. */
62 dprint("addcache rotate %d %d\n", i, c->ntab);
64 memmove(c->ctab + i, c->ctab + i + 1, (c->ntab - i - 1)*sizeof c->ctab[0]);
69 dprint("addcache %d %d %p\n", i, c->ntab, m);
75 notecache(Mailbox *mb, Message *m, long sz)
77 assert(Topmsg(mb, m));
78 assert(sz >= 0 && sz <= Maxmsg);
85 cachefree0(Mailbox *mb, Message *m, int force)
90 if(!force && !mb->fetch)
92 for(s = m->part; s; s = s->next)
93 cachefree(mb, s, force);
94 dprint("cachefree: %D %p, %p\n", m->fileid, m, m->start);
107 for(i = 0; i < nelem(m->references); i++){
108 free(m->references[i]);
109 m->references[i] = 0;
127 m->cstate &= ~(Cheader|Cbody);
134 cachefree(Mailbox *mb, Message *m, int force)
138 sz = cachefree0(mb, m, force);
139 for(i = 0; i < mb->ntab; i++)
140 if(m == mb->ctab[i]){
142 memmove(mb->ctab + i, mb->ctab + i + 1, sizeof m*mb->ntab - i);
150 Maxntab = nelem(mbl->ctab) - 10,
160 for(i = 0; i < c->ntab; i++)
161 sz += c->ctab[i]->csize;
170 for(i = 0; i < c->ntab; i++)
171 if(c->ctab[i]->csize > Maxmsg)
178 chkcsize(Mailbox *mb, vlong sz, vlong sz0)
184 if(sumcache(mb) == mb->cached)
185 if(scancache(mb) == 0)
187 eprint("sz0 %lld sz %lld sum %lld sumca %lld\n", sz0, sz, sumcache(mb), mb->cached);
188 eprint("%lld\n", sumcache(mb));
190 for(j = 0; j < c->ntab; j++){
192 eprint("%d %p %d %ld %ld\n", j, m, m->refs, m->csize, m->size);
198 * strategy: start with i = 0. while cache exceeds limits,
199 * find j so that all the [i:j] elements have refs == 0.
200 * uncache all the [i:j], reduce ntab by i-j. the tail
201 * [j+1:ntab] is shifted to [i:ntab], and finally i = i+1.
202 * we may safely skip the new i, since the condition
203 * that stopped our scan there still holds.
206 putcache(Mailbox *mb, Message *m)
219 sz < cachetarg && mb->ntab - (j - i) < Maxntab){
222 chkcsize(mb, sz, sz0);
229 if(sz == mb->cached){
234 for(k = i; k < j; k++)
235 cachefree0(mb, p[k], 0);
237 memmove(p + i, p + j, (mb->ntab - i)*sizeof *p);
239 chkcsize(mb, sz, sz0);
241 for(i = 0; i < mb->ntab; i++)
243 if((mb->ntab > 1 || k != mb->ntab) && Topmsg(mb, m))
244 eprint("cache overflow: %D %llud bytes; %d entries\n",
245 m? m->fileid: 1ll, mb->cached, mb->ntab);
248 debug = 1; prcache(mb, "");
253 squeeze(Message *m, uvlong o, long l, int c)
258 q = memchr(m->start + o, c, l);
262 e = m->start + o + l;
263 for(p = q; q < e; q++){
274 msgrealloc(Message *m, ulong l)
276 long l0, h0, m0, me, b0;
278 l0 = m->end - m->start;
280 h0 = m->hend - m->start;
281 m0 = m->mheader - m->start;
282 me = m->mhend - m->start;
283 b0 = m->body - m->start;
284 assert(h0 >= 0 && m0 >= 0 && me >= 0 && b0 >= 0);
285 m->start = erealloc(m->start, l + 1);
286 m->rbody = m->start + b0;
287 m->rbend = m->end = m->start + l0;
289 m->header = m->start;
290 m->hend = m->start + h0;
293 m->body = m->start + b0;
294 m->bend = m->start + l0;
296 m->mheader = m->start + m0;
297 m->mhend = m->start + me;
301 * the way we squeeze out bad characters is exceptionally sneaky.
304 fetch(Mailbox *mb, Message *m, uvlong o, ulong l)
310 l0 = m->end - m->start;
312 dprint("fetch %lud sz %lud o %llud l %lud badchars %d\n", l0, m->size, o, l, m->badchars);
313 if(l0 == m->size || o > m->size)
319 l += m->ibadchars - m->badchars;
322 msgrealloc(m, o + m->badchars + l);
326 if(mb->fetch(mb, m, o + m->badchars, l) == -1){
327 logmsg(m, "can't fetch %D %llud %lud", m->fileid, o, l);
332 l += m->size - sz0; /* awful botch for gmail */
334 /* grumble. poor planning. */
336 memmove(m->start + o, m->start + o + m->badchars, l);
337 n = squeeze(m, o, l, 0);
338 n += squeeze(m, o, l - n, '\r');
340 if(m->ibadchars == 0)
341 dprint(" %ld more badchars\n", n);
344 msgrealloc(m, o + l);
347 m->bend = m->rbend = m->end = m->start + o + l;
349 if(o + l + n == m->size && m->cstate&Cidx){
350 dprint(" redux %llud %ld\n", o + l, n);
356 eprint("unhandled case in fetch\n");
362 cachehash(Mailbox *mb, Message *m)
364 if(m->whole == m->whole->whole)
365 henter(PATH(mb->id, Qmbox), m->name,
366 (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);
368 henter(PATH(m->whole->id, Qdir), m->name,
369 (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);
370 henter(PATH(m->id, Qdir), "xxx",
371 (Qid){PATH(m->id, Qmax), 0, QTFILE}, m, mb); /* sleezy speedup */
375 newcachehash(Mailbox *mb, Message *m, int doplumb)
380 if(insurecache(mb, m) == 0)
382 /* avoid cachehash on error? */
386 static char *itab[] = {
403 for(i = 0; i < 8; i++)
406 p = seprint(p, e, "%s ", itab[i]);
415 middlecache(Mailbox *mb, Message *m)
420 while(!Topmsg(mb, m)){
422 if((m->cstate & Cbody) == 0)
427 dprint("middlecache %d [%D] %lud %lud\n", m->id, m->fileid, m->end - m->start, m->size);
428 return cachebody(mb, m);
432 cacheheaders(Mailbox *mb, Message *m)
438 if(!mb->fetch || m->cstate&Cheader)
441 return middlecache(mb, m);
442 dprint("cacheheaders %d %D\n", m->id, m->fileid);
444 r = fetch(mb, m, 0, m->size);
445 else for(r = 0; (o = m->end - m->start) < m->size; ){
446 if((r = fetch(mb, m, o, 4096)) < 0)
451 for(e = m->end - 2; p < e; p++){
452 p = memchr(p, '\n', e - p);
455 if(p[1] == '\n' || (p[1] == '\r' && p[2] == '\n'))
462 parseheaders(mb, m, mb->addfrom, 0);
467 digestmessage(Mailbox *mb, Message *m)
469 assert(m->digest == 0);
470 m->digest = emalloc(SHA1dlen);
471 sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
472 if(mtreeisdup(mb, m)){
473 logmsg(m, "dup detected");
474 m->deleted = Dup; /* no dups allowed */
477 dprint("%d %#A\n", m->id, m->digest);
481 cachebody(Mailbox *mb, Message *m)
485 while(!Topmsg(mb, m))
487 if(!mb->fetch || m->cstate&Cbody)
489 o = m->end - m->start;
490 dprint("cachebody %d [%D] %lud %lud %s\n", m->id, m->fileid, o, m->size, cstate(m));
492 if(fetch(mb, m, o, m->size - o) < 0)
494 if((m->cstate&Cidx) == 0){
495 assert(m->ibadchars == 0);
497 dprint("reducing size %ld %ld\n", m->size, m->size - m->badchars);
498 m->size -= m->badchars; /* sneaky */
499 m->ibadchars = m->badchars;
502 digestmessage(mb, m);
504 m->lines = countlines(m);
505 parse(mb, m, mb->addfrom, 0);
506 dprint(" →%s\n", cstate(m));
511 cacheidx(Mailbox *mb, Message *m)
515 if(cachebody(mb, m) == -1)
517 m->cstate |= Cidxstale|Cidx;
522 countparts(Message *m)
527 for(p = m->part; p; p = p->next){
535 insurecache(Mailbox *mb, Message *m)
537 if(m->deleted || !m->inmbox)
541 if((m->cstate & Cidx) == 0){
542 logmsg(m, "%s: can't cache: %s: %r", mb->path, m->name);