mbox.c
来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 814 行 · 第 1/2 页
C
814 行
}intemptyImp(char *mbox){ Dir *d; long mode; int fd; fd = cdCreate(mboxDir, impName(mbox), OWRITE, 0664); if(fd < 0) return -1; d = cdDirstat(mboxDir, mbox); if(d == nil){ close(fd); return -1; } fprint(fd, "%s%.*lud %.*lud\n", IMPMAGIC, NUid, d->mtime, NUid, 1UL); mode = d->mode & 0777; nulldir(d); d->mode = mode; dirfwstat(fd, d); free(d); return fd;}/* * try to match permissions with mbox */static intcreateImp(Box *box, Qid *qid){ Dir *d; long mode; int fd; fd = cdCreate(mboxDir, box->imp, OREAD, 0664); if(fd < 0) return -1; d = cdDirstat(mboxDir, box->name); if(d != nil){ mode = d->mode & 0777; nulldir(d); d->mode = mode; dirfwstat(fd, d); free(d); } if(fqid(fd, qid) < 0){ close(fd); return -1; } return fd;}/* * read or re-read a .imp file. * this is tricky: * messages can be deleted by another agent * we might still have a Msg for an expunged message, * because we haven't told the client yet. * we can have a Msg without a .imp entry. * flag information is added at the end of the .imp by copy & append * there can be duplicate messages (same digests). * * look up existing messages based on uid. * look up new messages based on in order digest matching. * * note: in the face of duplicate messages, one of which is deleted, * two active servers may decide different ones are valid, and so return * different uids for the messages. this situation will stablize when the servers exit. */static intparseImp(Biobuf *b, Box *box){ Msg *m, *mm = nil; char *s, *t, *toks[3]; ulong uid, u; int match, n; m = box->msgs; s = Brdline(b, '\n'); if(s == nil || Blinelen(b) != STRLEN(IMPMAGIC) || strncmp(s, IMPMAGIC, STRLEN(IMPMAGIC)) != 0) return 0; s = Brdline(b, '\n'); if(s == nil || Blinelen(b) != 2*NUid + 2) return 0; s[2*NUid + 1] = '\0'; u = strtoul(s, &t, 10); if(u != box->uidvalidity && box->uidvalidity != 0) return 0; box->uidvalidity = u; if(*t != ' ' || t != s + NUid) return 0; t++; u = strtoul(t, &t, 10); if(box->uidnext > u) return 0; box->uidnext = u; if(t != s + 2*NUid+1 || box->uidnext == 0) return 0; uid = ~0; while(m != nil){ s = Brdline(b, '\n'); if(s == nil) break; n = Blinelen(b) - 1; if(n != NDigest + NUid + NFlags + 2 || s[NDigest] != ' ' || s[NDigest + NUid + 1] != ' ') return 0; toks[0] = s; s[NDigest] = '\0'; toks[1] = s + NDigest + 1; s[NDigest + NUid + 1] = '\0'; toks[2] = s + NDigest + NUid + 2; s[n] = '\0'; t = toks[1]; u = strtoul(t, &t, 10); if(*t != '\0' || uid != ~0 && (uid >= u && u || u && !uid)) return 0; uid = u; /* * zero uid => added by append or copy, only flags valid * can only match messages without uids, but this message * may not be the next one, and may have been deleted. */ if(!uid){ for(; m != nil && m->uid; m = m->next) ; for(mm = m; mm != nil; mm = mm->next){ if(mm->info[IDigest] != nil && strcmp(mm->info[IDigest], toks[0]) == 0){ if(!mm->uid) mm->flags = 0; if(!impFlags(box, mm, toks[2])) return 0; m = mm->next; break; } } continue; } /* * ignore expunged messages, * and messages already assigned uids which don't match this uid. * such messages must have been deleted by another imap server, * which updated the mailbox and .imp file since we read the mailbox, * or because upas/fs got confused by consecutive duplicate messages, * the first of which was deleted by another imap server. */ for(; m != nil && (m->expunged || m->uid && m->uid < uid); m = m->next) ; if(m == nil) break; /* * only check for digest match on the next message, * since it comes before all other messages, and therefore * must be in the .imp file if they should be. */ match = mm != nil && mm->info[IDigest] != nil && strcmp(m->info[IDigest], toks[0]) == 0; if(uid && (m->uid == uid || !m->uid && match)){ if(!match) bye("inconsistent uid"); /* * wipe out recent flag if some other server saw this new message. * it will be read from the .imp file if is really should be set, * ie the message was only seen by a status command. */ if(!m->uid) m->flags = 0; if(!impFlags(box, m, toks[2])) return 0; m->uid = uid; m = m->next; } } return 1;}/* * parse .imp flags */static intimpFlags(Box *box, Msg *m, char *flags){ int i, f; f = 0; for(i = 0; i < NFlags; i++){ if(flags[i] == '-') continue; if(flags[i] != flagChars[i].name[0]) return 0; f |= flagChars[i].v; } /* * recent flags are set until the first time message's box is selected or examined. * it may be stored in the file as a side effect of a status or subscribe command; * if so, clear it out. */ if((f & MRecent) && strcmp(box->fs, "imap") == 0) box->dirtyImp = 1; f |= m->flags & MRecent; /* * all old messages with changed flags should be reported to the client */ if(m->uid && m->flags != f){ box->sendFlags = 1; m->sendFlags = 1; } m->flags = f; return 1;}/* * assign uids to any new messages * which aren't already in the .imp file. * sum up totals for flag values. */static voidboxFlags(Box *box){ Msg *m; box->recent = 0; for(m = box->msgs; m != nil; m = m->next){ if(m->uid == 0){ box->dirtyImp = 1; box->uidnext = uidRenumber(m, box->uidnext, 0); } if(m->flags & MRecent) box->recent++; }}static ulonguidRenumber(Msg *m, ulong uid, int force){ for(; m != nil; m = m->next){ if(!force && m->uid != 0) bye("uid renumbering with a valid uid"); m->uid = uid++; } return uid;}voidcloseBox(Box *box, int opened){ Msg *m, *next; /* * make sure to leave the mailbox directory so upas/fs can close the mailbox */ myChdir(mboxDir); if(box->writable){ deleteMsgs(box); if(expungeMsgs(box, 0)) closeImp(box, checkBox(box, 1)); } if(fprint(fsCtl, "close %s", box->fs) < 0 && opened) bye("can't talk to mail server"); for(m = box->msgs; m != nil; m = next){ next = m->next; freeMsg(m); } free(box->name); free(box->fs); free(box->fsDir); free(box->imp); free(box);}intdeleteMsgs(Box *box){ Msg *m; char buf[BufSize], *p, *start; int ok; if(!box->writable) return 0; /* * first pass: delete messages; gang the writes together for speed. */ ok = 1; start = seprint(buf, buf + sizeof(buf), "delete %s", box->fs); p = start; for(m = box->msgs; m != nil; m = m->next){ if((m->flags & MDeleted) && !m->expunged){ m->expunged = 1; p = seprint(p, buf + sizeof(buf), " %lud", m->id); if(p + 32 >= buf + sizeof(buf)){ if(write(fsCtl, buf, p - buf) < 0) bye("can't talk to mail server"); p = start; } } } if(p != start && write(fsCtl, buf, p - buf) < 0) bye("can't talk to mail server"); return ok;}/* * second pass: remove the message structure, * and renumber message sequence numbers. * update messages counts in mailbox. * returns true if anything changed. */intexpungeMsgs(Box *box, int send){ Msg *m, *next, *last; ulong n; n = 0; last = nil; for(m = box->msgs; m != nil; m = next){ m->seq -= n; next = m->next; if(m->expunged){ if(send) Bprint(&bout, "* %lud expunge\r\n", m->seq); if(m->flags & MRecent) box->recent--; n++; if(last == nil) box->msgs = next; else last->next = next; freeMsg(m); }else last = m; } if(n){ box->max -= n; box->dirtyImp = 1; } return n;}static voidfsInit(void){ if(fsCtl >= 0) return; fsCtl = open("/mail/fs/ctl", ORDWR); if(fsCtl < 0) bye("can't open mail file system"); if(fprint(fsCtl, "close mbox") < 0) bye("can't initialize mail file system");}static char *stoplist[] ={ "mbox", "pipeto", "forward", "names", 0};/* * reject bad mailboxes based on mailbox name */intokMbox(char *path){ char *name; int i; name = strrchr(path, '/'); if(name == nil) name = path; else name++; if(strlen(name) + STRLEN(".imp") >= MboxNameLen) return 0; for(i = 0; stoplist[i]; i++) if(strcmp(name, stoplist[i]) == 0) return 0; if(isprefix("L.", name) || isprefix("imap-tmp.", name) || issuffix(".imp", name) || strcmp("imap.subscribed", name) == 0 || isdotdot(name) || name[0] == '/') return 0; return 1;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?