17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include "imap4d.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier static NamedInt flagChars[NFlags] =
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier {"s", MSeen},
107dd7cddfSDavid du Colombier {"a", MAnswered},
117dd7cddfSDavid du Colombier {"f", MFlagged},
127dd7cddfSDavid du Colombier {"D", MDeleted},
137dd7cddfSDavid du Colombier {"d", MDraft},
147dd7cddfSDavid du Colombier {"r", MRecent},
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier static int fsCtl = -1;
187dd7cddfSDavid du Colombier
197dd7cddfSDavid du Colombier static void boxFlags(Box *box);
209a747e4fSDavid du Colombier static int createImp(Box *box, Qid *qid);
217dd7cddfSDavid du Colombier static void fsInit(void);
227dd7cddfSDavid du Colombier static void mboxGone(Box *box);
237dd7cddfSDavid du Colombier static MbLock *openImp(Box *box, int new);
247dd7cddfSDavid du Colombier static int parseImp(Biobuf *b, Box *box);
257dd7cddfSDavid du Colombier static int readBox(Box *box);
267dd7cddfSDavid du Colombier static ulong uidRenumber(Msg *m, ulong uid, int force);
277dd7cddfSDavid du Colombier static int impFlags(Box *box, Msg *m, char *flags);
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier /*
307dd7cddfSDavid du Colombier * strategy:
317dd7cddfSDavid du Colombier * every mailbox file has an associated .imp file
327dd7cddfSDavid du Colombier * which maps upas/fs message digests to uids & message flags.
337dd7cddfSDavid du Colombier *
347dd7cddfSDavid du Colombier * the .imp files are locked by /mail/fs/usename/L.mbox.
357dd7cddfSDavid du Colombier * whenever the flags can be modified, the lock file
367dd7cddfSDavid du Colombier * should be opened, thereby locking the uid & flag state.
377dd7cddfSDavid du Colombier * for example, whenever new uids are assigned to messages,
387dd7cddfSDavid du Colombier * and whenever flags are changed internally, the lock file
397dd7cddfSDavid du Colombier * should be open and locked. this means the file must be
407dd7cddfSDavid du Colombier * opened during store command, and when changing the \seen
417dd7cddfSDavid du Colombier * flag for the fetch command.
427dd7cddfSDavid du Colombier *
437dd7cddfSDavid du Colombier * if no .imp file exists, a null one must be created before
447dd7cddfSDavid du Colombier * assigning uids.
457dd7cddfSDavid du Colombier *
467dd7cddfSDavid du Colombier * the .imp file has the following format
477dd7cddfSDavid du Colombier * imp : "imap internal mailbox description\n"
487dd7cddfSDavid du Colombier * uidvalidity " " uidnext "\n"
497dd7cddfSDavid du Colombier * messageLines
507dd7cddfSDavid du Colombier *
517dd7cddfSDavid du Colombier * messageLines :
527dd7cddfSDavid du Colombier * | messageLines digest " " uid " " flags "\n"
537dd7cddfSDavid du Colombier *
547dd7cddfSDavid du Colombier * uid, uidnext, and uidvalidity are 32 bit decimal numbers
557dd7cddfSDavid du Colombier * printed right justified in a field NUid characters long.
567dd7cddfSDavid du Colombier * the 0 uid implies that no uid has been assigned to the message,
577dd7cddfSDavid du Colombier * but the flags are valid. note that message lines are in mailbox
587dd7cddfSDavid du Colombier * order, except possibly for 0 uid messages.
597dd7cddfSDavid du Colombier *
607dd7cddfSDavid du Colombier * digest is an ascii hex string NDigest characters long.
617dd7cddfSDavid du Colombier *
627dd7cddfSDavid du Colombier * flags has a character for each of NFlag flag fields.
637dd7cddfSDavid du Colombier * if the flag is clear, it is represented by a "-".
647dd7cddfSDavid du Colombier * set flags are represented as a unique single ascii character.
657dd7cddfSDavid du Colombier * the currently assigned flags are, in order:
667dd7cddfSDavid du Colombier * MSeen s
677dd7cddfSDavid du Colombier * MAnswered a
687dd7cddfSDavid du Colombier * MFlagged f
697dd7cddfSDavid du Colombier * MDeleted D
707dd7cddfSDavid du Colombier * MDraft d
717dd7cddfSDavid du Colombier */
727dd7cddfSDavid du Colombier Box*
openBox(char * name,char * fsname,int writable)737dd7cddfSDavid du Colombier openBox(char *name, char *fsname, int writable)
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier Box *box;
767dd7cddfSDavid du Colombier MbLock *ml;
777dd7cddfSDavid du Colombier int n, new;
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier if(cistrcmp(name, "inbox") == 0)
8043aadf5eSDavid du Colombier if(access("msgs", AEXIST) == 0)
8143aadf5eSDavid du Colombier name = "msgs";
8243aadf5eSDavid du Colombier else
837dd7cddfSDavid du Colombier name = "mbox";
847dd7cddfSDavid du Colombier fsInit();
8543aadf5eSDavid du Colombier debuglog("imap4d open %s %s\n", name, fsname);
8643aadf5eSDavid du Colombier
87*8cf6001eSDavid du Colombier if(fprint(fsCtl, "open '/mail/box/%s/%s' %s", username, name, fsname) < 0){
8880ee5cbfSDavid du Colombier //ZZZ
899a747e4fSDavid du Colombier char err[ERRMAX];
906e955fcaSDavid du Colombier
91b8914692SDavid du Colombier rerrstr(err, sizeof err);
929a747e4fSDavid du Colombier if(strstr(err, "file does not exist") == nil)
936e955fcaSDavid du Colombier fprint(2,
946e955fcaSDavid du Colombier "imap4d at %lud: upas/fs open %s/%s as %s failed: '%s' %s",
956e955fcaSDavid du Colombier time(nil), username, name, fsname, err,
966e955fcaSDavid du Colombier ctime(time(nil))); /* NB: ctime result ends with \n */
977dd7cddfSDavid du Colombier fprint(fsCtl, "close %s", fsname);
987dd7cddfSDavid du Colombier return nil;
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier /*
1027dd7cddfSDavid du Colombier * read box to find all messages
1037dd7cddfSDavid du Colombier * each one has a directory, and is in numerical order
1047dd7cddfSDavid du Colombier */
1057dd7cddfSDavid du Colombier box = MKZ(Box);
1067dd7cddfSDavid du Colombier box->writable = writable;
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier n = strlen(name) + 1;
1097dd7cddfSDavid du Colombier box->name = emalloc(n);
1107dd7cddfSDavid du Colombier strcpy(box->name, name);
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier n += STRLEN(".imp");
1137dd7cddfSDavid du Colombier box->imp = emalloc(n);
1147dd7cddfSDavid du Colombier snprint(box->imp, n, "%s.imp", name);
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier n = strlen(fsname) + 1;
1177dd7cddfSDavid du Colombier box->fs = emalloc(n);
1187dd7cddfSDavid du Colombier strcpy(box->fs, fsname);
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier n = STRLEN("/mail/fs/") + strlen(fsname) + 1;
1217dd7cddfSDavid du Colombier box->fsDir = emalloc(n);
1227dd7cddfSDavid du Colombier snprint(box->fsDir, n, "/mail/fs/%s", fsname);
1237dd7cddfSDavid du Colombier
1247dd7cddfSDavid du Colombier box->uidnext = 1;
1257dd7cddfSDavid du Colombier new = readBox(box);
1267dd7cddfSDavid du Colombier if(new >= 0){
1277dd7cddfSDavid du Colombier ml = openImp(box, new);
1287dd7cddfSDavid du Colombier if(ml != nil){
1297dd7cddfSDavid du Colombier closeImp(box, ml);
1307dd7cddfSDavid du Colombier return box;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier }
1337dd7cddfSDavid du Colombier closeBox(box, 0);
1347dd7cddfSDavid du Colombier return nil;
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier
1377dd7cddfSDavid du Colombier /*
1387dd7cddfSDavid du Colombier * check mailbox
1397dd7cddfSDavid du Colombier * returns fd of open .imp file if imped.
1407dd7cddfSDavid du Colombier * otherwise, return value is insignificant
1417dd7cddfSDavid du Colombier *
1427dd7cddfSDavid du Colombier * careful: called by idle polling proc
1437dd7cddfSDavid du Colombier */
1447dd7cddfSDavid du Colombier MbLock*
checkBox(Box * box,int imped)1457dd7cddfSDavid du Colombier checkBox(Box *box, int imped)
1467dd7cddfSDavid du Colombier {
1477dd7cddfSDavid du Colombier MbLock *ml;
1489a747e4fSDavid du Colombier Dir *d;
1497dd7cddfSDavid du Colombier int new;
1507dd7cddfSDavid du Colombier
1517dd7cddfSDavid du Colombier if(box == nil)
1527dd7cddfSDavid du Colombier return nil;
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier /*
1557dd7cddfSDavid du Colombier * if stat fails, mailbox must be gone
1567dd7cddfSDavid du Colombier */
1579a747e4fSDavid du Colombier d = cdDirstat(box->fsDir, ".");
1589a747e4fSDavid du Colombier if(d == nil){
1597dd7cddfSDavid du Colombier mboxGone(box);
1607dd7cddfSDavid du Colombier return nil;
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier new = 0;
1639a747e4fSDavid du Colombier if(box->qid.path != d->qid.path || box->qid.vers != d->qid.vers
1649a747e4fSDavid du Colombier || box->mtime != d->mtime){
1657dd7cddfSDavid du Colombier new = readBox(box);
1669a747e4fSDavid du Colombier if(new < 0){
1679a747e4fSDavid du Colombier free(d);
1687dd7cddfSDavid du Colombier return nil;
1697dd7cddfSDavid du Colombier }
1709a747e4fSDavid du Colombier }
1719a747e4fSDavid du Colombier free(d);
1727dd7cddfSDavid du Colombier ml = openImp(box, new);
1737dd7cddfSDavid du Colombier if(ml == nil)
1747dd7cddfSDavid du Colombier box->writable = 0;
1757dd7cddfSDavid du Colombier else if(!imped){
1767dd7cddfSDavid du Colombier closeImp(box, ml);
1777dd7cddfSDavid du Colombier ml = nil;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier return ml;
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier /*
1837dd7cddfSDavid du Colombier * mailbox is unreachable, so mark all messages expunged
1847dd7cddfSDavid du Colombier * clean up .imp files as well.
1857dd7cddfSDavid du Colombier */
1867dd7cddfSDavid du Colombier static void
mboxGone(Box * box)1877dd7cddfSDavid du Colombier mboxGone(Box *box)
1887dd7cddfSDavid du Colombier {
1897dd7cddfSDavid du Colombier Msg *m;
1907dd7cddfSDavid du Colombier
1919a747e4fSDavid du Colombier if(cdExists(mboxDir, box->name) < 0)
1927dd7cddfSDavid du Colombier cdRemove(mboxDir, box->imp);
1937dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = m->next)
1947dd7cddfSDavid du Colombier m->expunged = 1;
1957dd7cddfSDavid du Colombier box->writable = 0;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier /*
1997dd7cddfSDavid du Colombier * read messages in the mailbox
2007dd7cddfSDavid du Colombier * mark message that no longer exist as expunged
2017dd7cddfSDavid du Colombier * returns -1 for failure, 0 if no new messages, 1 if new messages.
2027dd7cddfSDavid du Colombier */
2037dd7cddfSDavid du Colombier static int
readBox(Box * box)2047dd7cddfSDavid du Colombier readBox(Box *box)
2057dd7cddfSDavid du Colombier {
2067dd7cddfSDavid du Colombier Msg *msgs, *m, *last;
2079a747e4fSDavid du Colombier Dir *d;
2087dd7cddfSDavid du Colombier char *s;
2097dd7cddfSDavid du Colombier long max, id;
2109a747e4fSDavid du Colombier int i, nd, fd, new;
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier fd = cdOpen(box->fsDir, ".", OREAD);
2137dd7cddfSDavid du Colombier if(fd < 0){
2146e955fcaSDavid du Colombier syslog(0, "mail",
2156e955fcaSDavid du Colombier "imap4d at %lud: upas/fs stat of %s/%s aka %s failed: %r",
2166e955fcaSDavid du Colombier time(nil), username, box->name, box->fsDir);
2177dd7cddfSDavid du Colombier mboxGone(box);
2187dd7cddfSDavid du Colombier return -1;
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier /*
2227dd7cddfSDavid du Colombier * read box to find all messages
2237dd7cddfSDavid du Colombier * each one has a directory, and is in numerical order
2247dd7cddfSDavid du Colombier */
2259a747e4fSDavid du Colombier d = dirfstat(fd);
2269a747e4fSDavid du Colombier if(d == nil){
2277dd7cddfSDavid du Colombier close(fd);
2287dd7cddfSDavid du Colombier return -1;
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier box->mtime = d->mtime;
2317dd7cddfSDavid du Colombier box->qid = d->qid;
2327dd7cddfSDavid du Colombier last = nil;
2337dd7cddfSDavid du Colombier msgs = box->msgs;
2347dd7cddfSDavid du Colombier max = 0;
2357dd7cddfSDavid du Colombier new = 0;
2369a747e4fSDavid du Colombier free(d);
2379a747e4fSDavid du Colombier while((nd = dirread(fd, &d)) > 0){
2387dd7cddfSDavid du Colombier for(i = 0; i < nd; i++){
2397dd7cddfSDavid du Colombier s = d[i].name;
2407dd7cddfSDavid du Colombier id = strtol(s, &s, 10);
2417dd7cddfSDavid du Colombier if(id <= max || *s != '\0'
2429a747e4fSDavid du Colombier || (d[i].mode & DMDIR) != DMDIR)
2437dd7cddfSDavid du Colombier continue;
2447dd7cddfSDavid du Colombier
2457dd7cddfSDavid du Colombier max = id;
2467dd7cddfSDavid du Colombier
2477dd7cddfSDavid du Colombier while(msgs != nil){
2487dd7cddfSDavid du Colombier last = msgs;
2497dd7cddfSDavid du Colombier msgs = msgs->next;
2507dd7cddfSDavid du Colombier if(last->id == id)
2517dd7cddfSDavid du Colombier goto continueDir;
2527dd7cddfSDavid du Colombier last->expunged = 1;
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier new = 1;
2567dd7cddfSDavid du Colombier m = MKZ(Msg);
2577dd7cddfSDavid du Colombier m->id = id;
2587dd7cddfSDavid du Colombier m->fsDir = box->fsDir;
2599a747e4fSDavid du Colombier m->fs = emalloc(2 * (MsgNameLen + 1));
2609a747e4fSDavid du Colombier m->efs = seprint(m->fs, m->fs + (MsgNameLen + 1), "%lud/", id);
2617dd7cddfSDavid du Colombier m->size = ~0UL;
2627dd7cddfSDavid du Colombier m->lines = ~0UL;
2637dd7cddfSDavid du Colombier m->prev = last;
2647dd7cddfSDavid du Colombier m->flags = MRecent;
2657dd7cddfSDavid du Colombier if(!msgInfo(m))
2667dd7cddfSDavid du Colombier freeMsg(m);
2677dd7cddfSDavid du Colombier else{
2687dd7cddfSDavid du Colombier if(last == nil)
2697dd7cddfSDavid du Colombier box->msgs = m;
2707dd7cddfSDavid du Colombier else
2717dd7cddfSDavid du Colombier last->next = m;
2727dd7cddfSDavid du Colombier last = m;
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier continueDir:;
2757dd7cddfSDavid du Colombier }
2769a747e4fSDavid du Colombier free(d);
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier close(fd);
2797dd7cddfSDavid du Colombier for(; msgs != nil; msgs = msgs->next)
2807dd7cddfSDavid du Colombier msgs->expunged = 1;
2817dd7cddfSDavid du Colombier
2827dd7cddfSDavid du Colombier /*
2837dd7cddfSDavid du Colombier * make up the imap message sequence numbers
2847dd7cddfSDavid du Colombier */
2857dd7cddfSDavid du Colombier id = 1;
2867dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = m->next){
2877dd7cddfSDavid du Colombier if(m->seq && m->seq != id)
2887dd7cddfSDavid du Colombier bye("internal error assigning message numbers");
2897dd7cddfSDavid du Colombier m->seq = id++;
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier box->max = id - 1;
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier return new;
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier /*
2977dd7cddfSDavid du Colombier * read in the .imp file, or make one if it doesn't exist.
2987dd7cddfSDavid du Colombier * make sure all flags and uids are consistent.
2997dd7cddfSDavid du Colombier * return the mailbox lock.
3007dd7cddfSDavid du Colombier */
3017dd7cddfSDavid du Colombier #define IMPMAGIC "imap internal mailbox description\n"
3027dd7cddfSDavid du Colombier static MbLock*
openImp(Box * box,int new)3037dd7cddfSDavid du Colombier openImp(Box *box, int new)
3047dd7cddfSDavid du Colombier {
3059a747e4fSDavid du Colombier Qid qid;
3067dd7cddfSDavid du Colombier Biobuf b;
3077dd7cddfSDavid du Colombier MbLock *ml;
3087dd7cddfSDavid du Colombier int fd;
30980ee5cbfSDavid du Colombier //ZZZZ
31080ee5cbfSDavid du Colombier int once;
3117dd7cddfSDavid du Colombier
3127dd7cddfSDavid du Colombier ml = mbLock();
3137dd7cddfSDavid du Colombier if(ml == nil)
3147dd7cddfSDavid du Colombier return nil;
3157dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, box->imp, OREAD);
31680ee5cbfSDavid du Colombier once = 0;
31780ee5cbfSDavid du Colombier ZZZhack:
3189a747e4fSDavid du Colombier if(fd < 0 || fqid(fd, &qid) < 0){
31980ee5cbfSDavid du Colombier if(fd < 0){
3209a747e4fSDavid du Colombier char buf[ERRMAX];
32180ee5cbfSDavid du Colombier
3229a747e4fSDavid du Colombier errstr(buf, sizeof buf);
32380ee5cbfSDavid du Colombier if(cistrstr(buf, "does not exist") == nil)
3249a747e4fSDavid du Colombier fprint(2, "imap4d at %lud: imp open failed: %s\n", time(nil), buf);
32580ee5cbfSDavid du Colombier if(!once && cistrstr(buf, "locked") != nil){
32680ee5cbfSDavid du Colombier once = 1;
3279a747e4fSDavid du Colombier fprint(2, "imap4d at %lud: imp %s/%s %s locked when it shouldn't be; spinning\n", time(nil), username, box->name, box->imp);
32880ee5cbfSDavid du Colombier fd = openLocked(mboxDir, box->imp, OREAD);
32980ee5cbfSDavid du Colombier goto ZZZhack;
33080ee5cbfSDavid du Colombier }
33180ee5cbfSDavid du Colombier }
3327dd7cddfSDavid du Colombier if(fd >= 0)
3337dd7cddfSDavid du Colombier close(fd);
3349a747e4fSDavid du Colombier fd = createImp(box, &qid);
3357dd7cddfSDavid du Colombier if(fd < 0){
3367dd7cddfSDavid du Colombier mbUnlock(ml);
3377dd7cddfSDavid du Colombier return nil;
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier box->dirtyImp = 1;
3407dd7cddfSDavid du Colombier if(box->uidvalidity == 0)
3417dd7cddfSDavid du Colombier box->uidvalidity = box->mtime;
3429a747e4fSDavid du Colombier box->impQid = qid;
3437dd7cddfSDavid du Colombier new = 1;
3449a747e4fSDavid du Colombier }else if(qid.path != box->impQid.path || qid.vers != box->impQid.vers){
3457dd7cddfSDavid du Colombier Binit(&b, fd, OREAD);
3467dd7cddfSDavid du Colombier if(!parseImp(&b, box)){
3477dd7cddfSDavid du Colombier box->dirtyImp = 1;
3487dd7cddfSDavid du Colombier if(box->uidvalidity == 0)
3497dd7cddfSDavid du Colombier box->uidvalidity = box->mtime;
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier Bterm(&b);
3529a747e4fSDavid du Colombier box->impQid = qid;
3537dd7cddfSDavid du Colombier new = 1;
3547dd7cddfSDavid du Colombier }
3557dd7cddfSDavid du Colombier if(new)
3567dd7cddfSDavid du Colombier boxFlags(box);
3577dd7cddfSDavid du Colombier close(fd);
3587dd7cddfSDavid du Colombier return ml;
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier
3617dd7cddfSDavid du Colombier /*
3627dd7cddfSDavid du Colombier * close the .imp file, after writing out any changes
3637dd7cddfSDavid du Colombier */
3647dd7cddfSDavid du Colombier void
closeImp(Box * box,MbLock * ml)3657dd7cddfSDavid du Colombier closeImp(Box *box, MbLock *ml)
3667dd7cddfSDavid du Colombier {
3677dd7cddfSDavid du Colombier Msg *m;
3689a747e4fSDavid du Colombier Qid qid;
3697dd7cddfSDavid du Colombier Biobuf b;
3707dd7cddfSDavid du Colombier char buf[NFlags+1];
3717dd7cddfSDavid du Colombier int fd;
3727dd7cddfSDavid du Colombier
3737dd7cddfSDavid du Colombier if(ml == nil)
3747dd7cddfSDavid du Colombier return;
3757dd7cddfSDavid du Colombier if(!box->dirtyImp){
3767dd7cddfSDavid du Colombier mbUnlock(ml);
3777dd7cddfSDavid du Colombier return;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier
3807dd7cddfSDavid du Colombier fd = cdCreate(mboxDir, box->imp, OWRITE, 0664);
3817dd7cddfSDavid du Colombier if(fd < 0){
3827dd7cddfSDavid du Colombier mbUnlock(ml);
3837dd7cddfSDavid du Colombier return;
3847dd7cddfSDavid du Colombier }
3857dd7cddfSDavid du Colombier Binit(&b, fd, OWRITE);
3867dd7cddfSDavid du Colombier
3877dd7cddfSDavid du Colombier box->dirtyImp = 0;
3887dd7cddfSDavid du Colombier Bprint(&b, "%s", IMPMAGIC);
3897dd7cddfSDavid du Colombier Bprint(&b, "%.*lud %.*lud\n", NUid, box->uidvalidity, NUid, box->uidnext);
3907dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = m->next){
3917dd7cddfSDavid du Colombier if(m->expunged)
3927dd7cddfSDavid du Colombier continue;
3937dd7cddfSDavid du Colombier wrImpFlags(buf, m->flags, strcmp(box->fs, "imap") == 0);
3947dd7cddfSDavid du Colombier Bprint(&b, "%.*s %.*lud %s\n", NDigest, m->info[IDigest], NUid, m->uid, buf);
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier Bterm(&b);
3977dd7cddfSDavid du Colombier
3989a747e4fSDavid du Colombier if(fqid(fd, &qid) >= 0)
3999a747e4fSDavid du Colombier box->impQid = qid;
4007dd7cddfSDavid du Colombier close(fd);
4017dd7cddfSDavid du Colombier mbUnlock(ml);
4027dd7cddfSDavid du Colombier }
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier void
wrImpFlags(char * buf,int flags,int killRecent)4057dd7cddfSDavid du Colombier wrImpFlags(char *buf, int flags, int killRecent)
4067dd7cddfSDavid du Colombier {
4077dd7cddfSDavid du Colombier int i;
4087dd7cddfSDavid du Colombier
4097dd7cddfSDavid du Colombier for(i = 0; i < NFlags; i++){
4107dd7cddfSDavid du Colombier if((flags & flagChars[i].v)
4117dd7cddfSDavid du Colombier && (flagChars[i].v != MRecent || !killRecent))
4127dd7cddfSDavid du Colombier buf[i] = flagChars[i].name[0];
4137dd7cddfSDavid du Colombier else
4147dd7cddfSDavid du Colombier buf[i] = '-';
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier buf[i] = '\0';
4177dd7cddfSDavid du Colombier }
4187dd7cddfSDavid du Colombier
4197dd7cddfSDavid du Colombier int
emptyImp(char * mbox)4207dd7cddfSDavid du Colombier emptyImp(char *mbox)
4217dd7cddfSDavid du Colombier {
4229a747e4fSDavid du Colombier Dir *d;
4239a747e4fSDavid du Colombier long mode;
4247dd7cddfSDavid du Colombier int fd;
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier fd = cdCreate(mboxDir, impName(mbox), OWRITE, 0664);
4277dd7cddfSDavid du Colombier if(fd < 0)
4287dd7cddfSDavid du Colombier return -1;
4299a747e4fSDavid du Colombier d = cdDirstat(mboxDir, mbox);
4309a747e4fSDavid du Colombier if(d == nil){
4317dd7cddfSDavid du Colombier close(fd);
4327dd7cddfSDavid du Colombier return -1;
4337dd7cddfSDavid du Colombier }
4349a747e4fSDavid du Colombier fprint(fd, "%s%.*lud %.*lud\n", IMPMAGIC, NUid, d->mtime, NUid, 1UL);
4359a747e4fSDavid du Colombier mode = d->mode & 0777;
4369a747e4fSDavid du Colombier nulldir(d);
4379a747e4fSDavid du Colombier d->mode = mode;
4389a747e4fSDavid du Colombier dirfwstat(fd, d);
4399a747e4fSDavid du Colombier free(d);
4407dd7cddfSDavid du Colombier return fd;
4417dd7cddfSDavid du Colombier }
4427dd7cddfSDavid du Colombier
4437dd7cddfSDavid du Colombier /*
4447dd7cddfSDavid du Colombier * try to match permissions with mbox
4457dd7cddfSDavid du Colombier */
4467dd7cddfSDavid du Colombier static int
createImp(Box * box,Qid * qid)4479a747e4fSDavid du Colombier createImp(Box *box, Qid *qid)
4487dd7cddfSDavid du Colombier {
4499a747e4fSDavid du Colombier Dir *d;
4509a747e4fSDavid du Colombier long mode;
4517dd7cddfSDavid du Colombier int fd;
4527dd7cddfSDavid du Colombier
4537dd7cddfSDavid du Colombier fd = cdCreate(mboxDir, box->imp, OREAD, 0664);
4547dd7cddfSDavid du Colombier if(fd < 0)
4557dd7cddfSDavid du Colombier return -1;
4569a747e4fSDavid du Colombier d = cdDirstat(mboxDir, box->name);
4579a747e4fSDavid du Colombier if(d != nil){
4589a747e4fSDavid du Colombier mode = d->mode & 0777;
4599a747e4fSDavid du Colombier nulldir(d);
4609a747e4fSDavid du Colombier d->mode = mode;
4617dd7cddfSDavid du Colombier dirfwstat(fd, d);
4629a747e4fSDavid du Colombier free(d);
4637dd7cddfSDavid du Colombier }
4649a747e4fSDavid du Colombier if(fqid(fd, qid) < 0){
4657dd7cddfSDavid du Colombier close(fd);
4667dd7cddfSDavid du Colombier return -1;
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier
4697dd7cddfSDavid du Colombier return fd;
4707dd7cddfSDavid du Colombier }
4717dd7cddfSDavid du Colombier
4727dd7cddfSDavid du Colombier /*
4737dd7cddfSDavid du Colombier * read or re-read a .imp file.
4747dd7cddfSDavid du Colombier * this is tricky:
4757dd7cddfSDavid du Colombier * messages can be deleted by another agent
4767dd7cddfSDavid du Colombier * we might still have a Msg for an expunged message,
4777dd7cddfSDavid du Colombier * because we haven't told the client yet.
4787dd7cddfSDavid du Colombier * we can have a Msg without a .imp entry.
4797dd7cddfSDavid du Colombier * flag information is added at the end of the .imp by copy & append
4807dd7cddfSDavid du Colombier * there can be duplicate messages (same digests).
4817dd7cddfSDavid du Colombier *
4827dd7cddfSDavid du Colombier * look up existing messages based on uid.
4837dd7cddfSDavid du Colombier * look up new messages based on in order digest matching.
4847dd7cddfSDavid du Colombier *
4857dd7cddfSDavid du Colombier * note: in the face of duplicate messages, one of which is deleted,
4867dd7cddfSDavid du Colombier * two active servers may decide different ones are valid, and so return
4877dd7cddfSDavid du Colombier * different uids for the messages. this situation will stablize when the servers exit.
4887dd7cddfSDavid du Colombier */
4897dd7cddfSDavid du Colombier static int
parseImp(Biobuf * b,Box * box)4907dd7cddfSDavid du Colombier parseImp(Biobuf *b, Box *box)
4917dd7cddfSDavid du Colombier {
4928da4fac9SDavid du Colombier Msg *m, *mm;
4937dd7cddfSDavid du Colombier char *s, *t, *toks[3];
4947dd7cddfSDavid du Colombier ulong uid, u;
4957dd7cddfSDavid du Colombier int match, n;
4967dd7cddfSDavid du Colombier
4977dd7cddfSDavid du Colombier m = box->msgs;
4987dd7cddfSDavid du Colombier s = Brdline(b, '\n');
4997dd7cddfSDavid du Colombier if(s == nil || Blinelen(b) != STRLEN(IMPMAGIC)
5007dd7cddfSDavid du Colombier || strncmp(s, IMPMAGIC, STRLEN(IMPMAGIC)) != 0)
5017dd7cddfSDavid du Colombier return 0;
5027dd7cddfSDavid du Colombier
5037dd7cddfSDavid du Colombier s = Brdline(b, '\n');
5047dd7cddfSDavid du Colombier if(s == nil || Blinelen(b) != 2*NUid + 2)
5057dd7cddfSDavid du Colombier return 0;
5067dd7cddfSDavid du Colombier s[2*NUid + 1] = '\0';
5077dd7cddfSDavid du Colombier u = strtoul(s, &t, 10);
5087dd7cddfSDavid du Colombier if(u != box->uidvalidity && box->uidvalidity != 0)
5097dd7cddfSDavid du Colombier return 0;
5107dd7cddfSDavid du Colombier box->uidvalidity = u;
5117dd7cddfSDavid du Colombier if(*t != ' ' || t != s + NUid)
5127dd7cddfSDavid du Colombier return 0;
5137dd7cddfSDavid du Colombier t++;
5147dd7cddfSDavid du Colombier u = strtoul(t, &t, 10);
5157dd7cddfSDavid du Colombier if(box->uidnext > u)
5167dd7cddfSDavid du Colombier return 0;
5177dd7cddfSDavid du Colombier box->uidnext = u;
5187dd7cddfSDavid du Colombier if(t != s + 2*NUid+1 || box->uidnext == 0)
5197dd7cddfSDavid du Colombier return 0;
5207dd7cddfSDavid du Colombier
5217dd7cddfSDavid du Colombier uid = ~0;
5227dd7cddfSDavid du Colombier while(m != nil){
5237dd7cddfSDavid du Colombier s = Brdline(b, '\n');
5247dd7cddfSDavid du Colombier if(s == nil)
5257dd7cddfSDavid du Colombier break;
5267dd7cddfSDavid du Colombier n = Blinelen(b) - 1;
5277dd7cddfSDavid du Colombier if(n != NDigest + NUid + NFlags + 2
5287dd7cddfSDavid du Colombier || s[NDigest] != ' ' || s[NDigest + NUid + 1] != ' ')
5297dd7cddfSDavid du Colombier return 0;
5307dd7cddfSDavid du Colombier toks[0] = s;
5317dd7cddfSDavid du Colombier s[NDigest] = '\0';
5327dd7cddfSDavid du Colombier toks[1] = s + NDigest + 1;
5337dd7cddfSDavid du Colombier s[NDigest + NUid + 1] = '\0';
5347dd7cddfSDavid du Colombier toks[2] = s + NDigest + NUid + 2;
5357dd7cddfSDavid du Colombier s[n] = '\0';
5367dd7cddfSDavid du Colombier t = toks[1];
5377dd7cddfSDavid du Colombier u = strtoul(t, &t, 10);
5387dd7cddfSDavid du Colombier if(*t != '\0' || uid != ~0 && (uid >= u && u || u && !uid))
5397dd7cddfSDavid du Colombier return 0;
5407dd7cddfSDavid du Colombier uid = u;
5417dd7cddfSDavid du Colombier
5427dd7cddfSDavid du Colombier /*
5437dd7cddfSDavid du Colombier * zero uid => added by append or copy, only flags valid
5447dd7cddfSDavid du Colombier * can only match messages without uids, but this message
5457dd7cddfSDavid du Colombier * may not be the next one, and may have been deleted.
5467dd7cddfSDavid du Colombier */
5477dd7cddfSDavid du Colombier if(!uid){
5487dd7cddfSDavid du Colombier for(; m != nil && m->uid; m = m->next)
5497dd7cddfSDavid du Colombier ;
5507dd7cddfSDavid du Colombier for(mm = m; mm != nil; mm = mm->next){
551778cb651SDavid du Colombier if(mm->info[IDigest] != nil &&
552778cb651SDavid du Colombier strcmp(mm->info[IDigest], toks[0]) == 0){
5537dd7cddfSDavid du Colombier if(!mm->uid)
5547dd7cddfSDavid du Colombier mm->flags = 0;
5557dd7cddfSDavid du Colombier if(!impFlags(box, mm, toks[2]))
5567dd7cddfSDavid du Colombier return 0;
5577dd7cddfSDavid du Colombier m = mm->next;
5587dd7cddfSDavid du Colombier break;
5597dd7cddfSDavid du Colombier }
5607dd7cddfSDavid du Colombier }
5617dd7cddfSDavid du Colombier continue;
5627dd7cddfSDavid du Colombier }
5637dd7cddfSDavid du Colombier
5647dd7cddfSDavid du Colombier /*
5657dd7cddfSDavid du Colombier * ignore expunged messages,
5667dd7cddfSDavid du Colombier * and messages already assigned uids which don't match this uid.
5677dd7cddfSDavid du Colombier * such messages must have been deleted by another imap server,
5687dd7cddfSDavid du Colombier * which updated the mailbox and .imp file since we read the mailbox,
5697dd7cddfSDavid du Colombier * or because upas/fs got confused by consecutive duplicate messages,
5707dd7cddfSDavid du Colombier * the first of which was deleted by another imap server.
5717dd7cddfSDavid du Colombier */
5727dd7cddfSDavid du Colombier for(; m != nil && (m->expunged || m->uid && m->uid < uid); m = m->next)
5737dd7cddfSDavid du Colombier ;
5747dd7cddfSDavid du Colombier if(m == nil)
5757dd7cddfSDavid du Colombier break;
5767dd7cddfSDavid du Colombier
5777dd7cddfSDavid du Colombier /*
5787dd7cddfSDavid du Colombier * only check for digest match on the next message,
5797dd7cddfSDavid du Colombier * since it comes before all other messages, and therefore
5807dd7cddfSDavid du Colombier * must be in the .imp file if they should be.
5817dd7cddfSDavid du Colombier */
5828da4fac9SDavid du Colombier match = m->info[IDigest] != nil &&
583778cb651SDavid du Colombier strcmp(m->info[IDigest], toks[0]) == 0;
5847dd7cddfSDavid du Colombier if(uid && (m->uid == uid || !m->uid && match)){
5857dd7cddfSDavid du Colombier if(!match)
5867dd7cddfSDavid du Colombier bye("inconsistent uid");
5877dd7cddfSDavid du Colombier
5887dd7cddfSDavid du Colombier /*
5897dd7cddfSDavid du Colombier * wipe out recent flag if some other server saw this new message.
5907dd7cddfSDavid du Colombier * it will be read from the .imp file if is really should be set,
5917dd7cddfSDavid du Colombier * ie the message was only seen by a status command.
5927dd7cddfSDavid du Colombier */
5937dd7cddfSDavid du Colombier if(!m->uid)
5947dd7cddfSDavid du Colombier m->flags = 0;
5957dd7cddfSDavid du Colombier
5967dd7cddfSDavid du Colombier if(!impFlags(box, m, toks[2]))
5977dd7cddfSDavid du Colombier return 0;
5987dd7cddfSDavid du Colombier m->uid = uid;
5997dd7cddfSDavid du Colombier m = m->next;
6007dd7cddfSDavid du Colombier }
6017dd7cddfSDavid du Colombier }
6027dd7cddfSDavid du Colombier return 1;
6037dd7cddfSDavid du Colombier }
6047dd7cddfSDavid du Colombier
6057dd7cddfSDavid du Colombier /*
6067dd7cddfSDavid du Colombier * parse .imp flags
6077dd7cddfSDavid du Colombier */
6087dd7cddfSDavid du Colombier static int
impFlags(Box * box,Msg * m,char * flags)6097dd7cddfSDavid du Colombier impFlags(Box *box, Msg *m, char *flags)
6107dd7cddfSDavid du Colombier {
6117dd7cddfSDavid du Colombier int i, f;
6127dd7cddfSDavid du Colombier
6137dd7cddfSDavid du Colombier f = 0;
6147dd7cddfSDavid du Colombier for(i = 0; i < NFlags; i++){
6157dd7cddfSDavid du Colombier if(flags[i] == '-')
6167dd7cddfSDavid du Colombier continue;
6177dd7cddfSDavid du Colombier if(flags[i] != flagChars[i].name[0])
6187dd7cddfSDavid du Colombier return 0;
6197dd7cddfSDavid du Colombier f |= flagChars[i].v;
6207dd7cddfSDavid du Colombier }
6217dd7cddfSDavid du Colombier
6227dd7cddfSDavid du Colombier /*
6237dd7cddfSDavid du Colombier * recent flags are set until the first time message's box is selected or examined.
6247dd7cddfSDavid du Colombier * it may be stored in the file as a side effect of a status or subscribe command;
6257dd7cddfSDavid du Colombier * if so, clear it out.
6267dd7cddfSDavid du Colombier */
6277dd7cddfSDavid du Colombier if((f & MRecent) && strcmp(box->fs, "imap") == 0)
6287dd7cddfSDavid du Colombier box->dirtyImp = 1;
6297dd7cddfSDavid du Colombier f |= m->flags & MRecent;
6307dd7cddfSDavid du Colombier
6317dd7cddfSDavid du Colombier /*
6327dd7cddfSDavid du Colombier * all old messages with changed flags should be reported to the client
6337dd7cddfSDavid du Colombier */
6347dd7cddfSDavid du Colombier if(m->uid && m->flags != f){
6357dd7cddfSDavid du Colombier box->sendFlags = 1;
6367dd7cddfSDavid du Colombier m->sendFlags = 1;
6377dd7cddfSDavid du Colombier }
6387dd7cddfSDavid du Colombier m->flags = f;
6397dd7cddfSDavid du Colombier return 1;
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier
6427dd7cddfSDavid du Colombier /*
6437dd7cddfSDavid du Colombier * assign uids to any new messages
6447dd7cddfSDavid du Colombier * which aren't already in the .imp file.
6457dd7cddfSDavid du Colombier * sum up totals for flag values.
6467dd7cddfSDavid du Colombier */
6477dd7cddfSDavid du Colombier static void
boxFlags(Box * box)6487dd7cddfSDavid du Colombier boxFlags(Box *box)
6497dd7cddfSDavid du Colombier {
6507dd7cddfSDavid du Colombier Msg *m;
6517dd7cddfSDavid du Colombier
6527dd7cddfSDavid du Colombier box->recent = 0;
6537dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = m->next){
6547dd7cddfSDavid du Colombier if(m->uid == 0){
6557dd7cddfSDavid du Colombier box->dirtyImp = 1;
6567dd7cddfSDavid du Colombier box->uidnext = uidRenumber(m, box->uidnext, 0);
6577dd7cddfSDavid du Colombier }
6587dd7cddfSDavid du Colombier if(m->flags & MRecent)
6597dd7cddfSDavid du Colombier box->recent++;
6607dd7cddfSDavid du Colombier }
6617dd7cddfSDavid du Colombier }
6627dd7cddfSDavid du Colombier
6637dd7cddfSDavid du Colombier static ulong
uidRenumber(Msg * m,ulong uid,int force)6647dd7cddfSDavid du Colombier uidRenumber(Msg *m, ulong uid, int force)
6657dd7cddfSDavid du Colombier {
6667dd7cddfSDavid du Colombier for(; m != nil; m = m->next){
6677dd7cddfSDavid du Colombier if(!force && m->uid != 0)
6687dd7cddfSDavid du Colombier bye("uid renumbering with a valid uid");
6697dd7cddfSDavid du Colombier m->uid = uid++;
6707dd7cddfSDavid du Colombier }
6717dd7cddfSDavid du Colombier return uid;
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier
6747dd7cddfSDavid du Colombier void
closeBox(Box * box,int opened)6757dd7cddfSDavid du Colombier closeBox(Box *box, int opened)
6767dd7cddfSDavid du Colombier {
6777dd7cddfSDavid du Colombier Msg *m, *next;
6787dd7cddfSDavid du Colombier
6797dd7cddfSDavid du Colombier /*
6807dd7cddfSDavid du Colombier * make sure to leave the mailbox directory so upas/fs can close the mailbox
6817dd7cddfSDavid du Colombier */
6827dd7cddfSDavid du Colombier myChdir(mboxDir);
6837dd7cddfSDavid du Colombier
6847dd7cddfSDavid du Colombier if(box->writable){
6857dd7cddfSDavid du Colombier deleteMsgs(box);
68659cc4ca5SDavid du Colombier if(expungeMsgs(box, 0))
68759cc4ca5SDavid du Colombier closeImp(box, checkBox(box, 1));
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier
6907dd7cddfSDavid du Colombier if(fprint(fsCtl, "close %s", box->fs) < 0 && opened)
6917dd7cddfSDavid du Colombier bye("can't talk to mail server");
6927dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = next){
6937dd7cddfSDavid du Colombier next = m->next;
6947dd7cddfSDavid du Colombier freeMsg(m);
6957dd7cddfSDavid du Colombier }
6967dd7cddfSDavid du Colombier free(box->name);
6977dd7cddfSDavid du Colombier free(box->fs);
6987dd7cddfSDavid du Colombier free(box->fsDir);
6997dd7cddfSDavid du Colombier free(box->imp);
7007dd7cddfSDavid du Colombier free(box);
7017dd7cddfSDavid du Colombier }
7027dd7cddfSDavid du Colombier
7037dd7cddfSDavid du Colombier int
deleteMsgs(Box * box)7047dd7cddfSDavid du Colombier deleteMsgs(Box *box)
7057dd7cddfSDavid du Colombier {
7067dd7cddfSDavid du Colombier Msg *m;
70759cc4ca5SDavid du Colombier char buf[BufSize], *p, *start;
7087dd7cddfSDavid du Colombier int ok;
7097dd7cddfSDavid du Colombier
7107dd7cddfSDavid du Colombier if(!box->writable)
7117dd7cddfSDavid du Colombier return 0;
7127dd7cddfSDavid du Colombier
7137dd7cddfSDavid du Colombier /*
71459cc4ca5SDavid du Colombier * first pass: delete messages; gang the writes together for speed.
7157dd7cddfSDavid du Colombier */
7167dd7cddfSDavid du Colombier ok = 1;
71759cc4ca5SDavid du Colombier start = seprint(buf, buf + sizeof(buf), "delete %s", box->fs);
71859cc4ca5SDavid du Colombier p = start;
7197dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = m->next){
7207dd7cddfSDavid du Colombier if((m->flags & MDeleted) && !m->expunged){
7217dd7cddfSDavid du Colombier m->expunged = 1;
72259cc4ca5SDavid du Colombier p = seprint(p, buf + sizeof(buf), " %lud", m->id);
72359cc4ca5SDavid du Colombier if(p + 32 >= buf + sizeof(buf)){
72459cc4ca5SDavid du Colombier if(write(fsCtl, buf, p - buf) < 0)
72559cc4ca5SDavid du Colombier bye("can't talk to mail server");
72659cc4ca5SDavid du Colombier p = start;
7277dd7cddfSDavid du Colombier }
7287dd7cddfSDavid du Colombier }
72959cc4ca5SDavid du Colombier }
73059cc4ca5SDavid du Colombier if(p != start && write(fsCtl, buf, p - buf) < 0)
73159cc4ca5SDavid du Colombier bye("can't talk to mail server");
7327dd7cddfSDavid du Colombier
7337dd7cddfSDavid du Colombier return ok;
7347dd7cddfSDavid du Colombier }
7357dd7cddfSDavid du Colombier
7367dd7cddfSDavid du Colombier /*
7377dd7cddfSDavid du Colombier * second pass: remove the message structure,
7387dd7cddfSDavid du Colombier * and renumber message sequence numbers.
7397dd7cddfSDavid du Colombier * update messages counts in mailbox.
7407dd7cddfSDavid du Colombier * returns true if anything changed.
7417dd7cddfSDavid du Colombier */
7427dd7cddfSDavid du Colombier int
expungeMsgs(Box * box,int send)7437dd7cddfSDavid du Colombier expungeMsgs(Box *box, int send)
7447dd7cddfSDavid du Colombier {
7457dd7cddfSDavid du Colombier Msg *m, *next, *last;
7467dd7cddfSDavid du Colombier ulong n;
7477dd7cddfSDavid du Colombier
7487dd7cddfSDavid du Colombier n = 0;
7497dd7cddfSDavid du Colombier last = nil;
7507dd7cddfSDavid du Colombier for(m = box->msgs; m != nil; m = next){
7517dd7cddfSDavid du Colombier m->seq -= n;
7527dd7cddfSDavid du Colombier next = m->next;
7537dd7cddfSDavid du Colombier if(m->expunged){
7547dd7cddfSDavid du Colombier if(send)
7557dd7cddfSDavid du Colombier Bprint(&bout, "* %lud expunge\r\n", m->seq);
7567dd7cddfSDavid du Colombier if(m->flags & MRecent)
7577dd7cddfSDavid du Colombier box->recent--;
7587dd7cddfSDavid du Colombier n++;
7597dd7cddfSDavid du Colombier if(last == nil)
7607dd7cddfSDavid du Colombier box->msgs = next;
7617dd7cddfSDavid du Colombier else
7627dd7cddfSDavid du Colombier last->next = next;
7637dd7cddfSDavid du Colombier freeMsg(m);
7647dd7cddfSDavid du Colombier }else
7657dd7cddfSDavid du Colombier last = m;
7667dd7cddfSDavid du Colombier }
7677dd7cddfSDavid du Colombier if(n){
7687dd7cddfSDavid du Colombier box->max -= n;
7697dd7cddfSDavid du Colombier box->dirtyImp = 1;
7707dd7cddfSDavid du Colombier }
7717dd7cddfSDavid du Colombier return n;
7727dd7cddfSDavid du Colombier }
7737dd7cddfSDavid du Colombier
7747dd7cddfSDavid du Colombier static void
fsInit(void)7757dd7cddfSDavid du Colombier fsInit(void)
7767dd7cddfSDavid du Colombier {
7777dd7cddfSDavid du Colombier if(fsCtl >= 0)
7787dd7cddfSDavid du Colombier return;
7797dd7cddfSDavid du Colombier fsCtl = open("/mail/fs/ctl", ORDWR);
7807dd7cddfSDavid du Colombier if(fsCtl < 0)
7817dd7cddfSDavid du Colombier bye("can't open mail file system");
7827dd7cddfSDavid du Colombier if(fprint(fsCtl, "close mbox") < 0)
7837dd7cddfSDavid du Colombier bye("can't initialize mail file system");
7847dd7cddfSDavid du Colombier }
7857dd7cddfSDavid du Colombier
7867dd7cddfSDavid du Colombier static char *stoplist[] =
7877dd7cddfSDavid du Colombier {
7887dd7cddfSDavid du Colombier "mbox",
7897dd7cddfSDavid du Colombier "pipeto",
7907dd7cddfSDavid du Colombier "forward",
7917dd7cddfSDavid du Colombier "names",
79243aadf5eSDavid du Colombier "pipefrom",
79343aadf5eSDavid du Colombier "headers",
79443aadf5eSDavid du Colombier "imap.ok",
7957dd7cddfSDavid du Colombier 0
7967dd7cddfSDavid du Colombier };
7977dd7cddfSDavid du Colombier
7983468a491SDavid du Colombier enum {
7993468a491SDavid du Colombier Maxokbytes = 4096,
8003468a491SDavid du Colombier Maxfolders = Maxokbytes / 4,
8013468a491SDavid du Colombier };
8023468a491SDavid du Colombier
8033468a491SDavid du Colombier static char *folders[Maxfolders];
80443aadf5eSDavid du Colombier static char *folderbuff;
80543aadf5eSDavid du Colombier
80643aadf5eSDavid du Colombier static void
readokfolders(void)80743aadf5eSDavid du Colombier readokfolders(void)
80843aadf5eSDavid du Colombier {
80943aadf5eSDavid du Colombier int fd, nr;
81043aadf5eSDavid du Colombier
81143aadf5eSDavid du Colombier fd = open("imap.ok", OREAD);
8123468a491SDavid du Colombier if(fd < 0)
8133468a491SDavid du Colombier return;
8143468a491SDavid du Colombier folderbuff = malloc(Maxokbytes);
8153468a491SDavid du Colombier if(folderbuff == nil) {
8163468a491SDavid du Colombier close(fd);
8173468a491SDavid du Colombier return;
8183468a491SDavid du Colombier }
8193468a491SDavid du Colombier nr = read(fd, folderbuff, Maxokbytes-1); /* once is ok */
8203468a491SDavid du Colombier close(fd);
8213468a491SDavid du Colombier if(nr < 0){
82243aadf5eSDavid du Colombier free(folderbuff);
82343aadf5eSDavid du Colombier folderbuff = nil;
82443aadf5eSDavid du Colombier return;
82543aadf5eSDavid du Colombier }
82643aadf5eSDavid du Colombier folderbuff[nr] = 0;
82743aadf5eSDavid du Colombier tokenize(folderbuff, folders, nelem(folders));
82843aadf5eSDavid du Colombier }
82943aadf5eSDavid du Colombier
8307dd7cddfSDavid du Colombier /*
8317dd7cddfSDavid du Colombier * reject bad mailboxes based on mailbox name
8327dd7cddfSDavid du Colombier */
8337dd7cddfSDavid du Colombier int
okMbox(char * path)8347dd7cddfSDavid du Colombier okMbox(char *path)
8357dd7cddfSDavid du Colombier {
8367dd7cddfSDavid du Colombier char *name;
8377dd7cddfSDavid du Colombier int i;
8387dd7cddfSDavid du Colombier
83943aadf5eSDavid du Colombier if(folderbuff == nil && access("imap.ok", AREAD) == 0)
84043aadf5eSDavid du Colombier readokfolders();
8417dd7cddfSDavid du Colombier name = strrchr(path, '/');
8427dd7cddfSDavid du Colombier if(name == nil)
8437dd7cddfSDavid du Colombier name = path;
8447dd7cddfSDavid du Colombier else
8457dd7cddfSDavid du Colombier name++;
84643aadf5eSDavid du Colombier if(folderbuff != nil){
84743aadf5eSDavid du Colombier for(i = 0; i < nelem(folders) && folders[i] != nil; i++)
84843aadf5eSDavid du Colombier if(cistrcmp(folders[i], name) == 0)
84943aadf5eSDavid du Colombier return 1;
85043aadf5eSDavid du Colombier return 0;
85143aadf5eSDavid du Colombier }
8529a747e4fSDavid du Colombier if(strlen(name) + STRLEN(".imp") >= MboxNameLen)
8537dd7cddfSDavid du Colombier return 0;
8547dd7cddfSDavid du Colombier for(i = 0; stoplist[i]; i++)
8557dd7cddfSDavid du Colombier if(strcmp(name, stoplist[i]) == 0)
8567dd7cddfSDavid du Colombier return 0;
8577dd7cddfSDavid du Colombier if(isprefix("L.", name) || isprefix("imap-tmp.", name)
8587dd7cddfSDavid du Colombier || issuffix(".imp", name)
8599a747e4fSDavid du Colombier || strcmp("imap.subscribed", name) == 0
8607dd7cddfSDavid du Colombier || isdotdot(name) || name[0] == '/')
8617dd7cddfSDavid du Colombier return 0;
8627dd7cddfSDavid du Colombier return 1;
8637dd7cddfSDavid du Colombier }
864