📄 mbox.c
字号:
}}static voidcencoding(Message *m, Header *h, char *p){ p += h->len; p = skipwhite(p); if(cistrncmp(p, "base64", 6) == 0) m->encoding = Ebase64; else if(cistrncmp(p, "quoted-printable", 16) == 0) m->encoding = Equoted;}static voidcdisposition(Message *m, Header *h, char *p){ p += h->len; p = skipwhite(p); while(*p){ if(cistrncmp(p, "inline", 6) == 0){ m->disposition = Dinline; } else if(cistrncmp(p, "attachment", 10) == 0){ m->disposition = Dfile; } else if(cistrncmp(p, "filename=", 9) == 0){ p += 9; setfilename(m, p); } p = skiptosemi(p); }}ulong msgallocd, msgfreed;Message*newmessage(Message *parent){ static int id; Message *m; msgallocd++; m = emalloc(sizeof(*m)); memset(m, 0, sizeof(*m)); m->disposition = Dnone; m->type = s_copy("text/plain"); m->charset = s_copy("iso-8859-1"); m->id = newid(); if(parent) sprint(m->name, "%d", ++(parent->subname)); if(parent == nil) parent = m; m->whole = parent; m->hlen = -1; return m;}// delete a message from a mailboxvoiddelmessage(Mailbox *mb, Message *m){ Message **l; int i; mb->vers++; msgfreed++; if(m->whole != m){ // unchain from parent for(l = &m->whole->part; *l && *l != m; l = &(*l)->next) ; if(*l != nil) *l = m->next; // clear out of name lookup hash table if(m->whole->whole == m->whole) hfree(PATH(mb->id, Qmbox), m->name); else hfree(PATH(m->whole->id, Qdir), m->name); for(i = 0; i < Qmax; i++) hfree(PATH(m->id, Qdir), dirtab[i]); } /* recurse through sub-parts */ while(m->part) delmessage(mb, m->part); /* free memory */ if(m->mallocd) free(m->start); if(m->hallocd) free(m->header); if(m->ballocd) free(m->body); s_free(m->unixfrom); s_free(m->unixdate); s_free(m->unixheader); s_free(m->from822); s_free(m->sender822); s_free(m->to822); s_free(m->bcc822); s_free(m->cc822); s_free(m->replyto822); s_free(m->date822); s_free(m->inreplyto822); s_free(m->subject822); s_free(m->messageid822); s_free(m->addrs); s_free(m->mimeversion); s_free(m->sdigest); s_free(m->boundary); s_free(m->type); s_free(m->charset); s_free(m->filename); free(m);}// mark messages (identified by path) for deletionvoiddelmessages(int ac, char **av){ Mailbox *mb; Message *m; int i, needwrite; qlock(&mbllock); for(mb = mbl; mb != nil; mb = mb->next) if(strcmp(av[0], mb->name) == 0){ qlock(mb); break; } qunlock(&mbllock); if(mb == nil) return; needwrite = 0; for(i = 1; i < ac; i++){ for(m = mb->root->part; m != nil; m = m->next) if(strcmp(m->name, av[i]) == 0){ if(!m->deleted){ mailplumb(mb, m, 1); needwrite = 1; m->deleted = 1; logmsg("deleting", m); } break; } } if(needwrite) syncmbox(mb, 1); qunlock(mb);}/* * the following are called with the mailbox qlocked */voidmsgincref(Message *m){ m->refs++;}voidmsgdecref(Mailbox *mb, Message *m){ m->refs--; if(m->refs == 0 && m->deleted) syncmbox(mb, 1);}/* * the following are called with mbllock'd */voidmboxincref(Mailbox *mb){ assert(mb->refs > 0); mb->refs++;}voidmboxdecref(Mailbox *mb){ assert(mb->refs > 0); qlock(mb); mb->refs--; if(mb->refs == 0){ delmessage(mb, mb->root); if(mb->ctl) hfree(PATH(mb->id, Qmbox), "ctl"); if(mb->close) (*mb->close)(mb); free(mb); } else qunlock(mb);}intcistrncmp(char *a, char *b, int n){ while(n-- > 0){ if(tolower(*a++) != tolower(*b++)) return -1; } return 0;}intcistrcmp(char *a, char *b){ for(;;){ if(tolower(*a) != tolower(*b++)) return -1; if(*a++ == 0) break; } return 0;}static char*skipwhite(char *p){ while(isspace(*p)) p++; return p;}static char*skiptosemi(char *p){ while(*p && *p != ';') p++; while(*p == ';' || isspace(*p)) p++; return p;}static char*getstring(char *p, String *s, int dolower){ s = s_reset(s); p = skipwhite(p); if(*p == '"'){ p++; for(;*p && *p != '"'; p++) if(dolower) s_putc(s, tolower(*p)); else s_putc(s, *p); if(*p == '"') p++; s_terminate(s); return p; } for(; *p && !isspace(*p) && *p != ';'; p++) if(dolower) s_putc(s, tolower(*p)); else s_putc(s, *p); s_terminate(s); return p;}static voidsetfilename(Message *m, char *p){ m->filename = s_reset(m->filename); getstring(p, m->filename, 0); for(p = s_to_c(m->filename); *p; p++) if(*p == ' ' || *p == '\t' || *p == ';') *p = '_';}//// undecode message body//voiddecode(Message *m){ int i, len; char *x; if(m->decoded) return; switch(m->encoding){ case Ebase64: len = m->bend - m->body; i = (len*3)/4+1; // room for max chars + null x = emalloc(i); len = dec64((uchar*)x, i, m->body, len); if(m->ballocd) free(m->body); m->body = x; m->bend = x + len; m->ballocd = 1; break; case Equoted: len = m->bend - m->body; x = emalloc(len+2); // room for null and possible extra nl len = decquoted(x, m->body, m->bend, 0); if(m->ballocd) free(m->body); m->body = x; m->bend = x + len; m->ballocd = 1; break; default: break; } m->decoded = 1;}// convert latin1 to utfvoidconvert(Message *m){ int len; char *x; // don't convert if we're not a leaf, not text, or already converted if(m->converted) return; if(m->part != nil) return; if(cistrncmp(s_to_c(m->type), "text", 4) != 0) return; len = xtoutf(s_to_c(m->charset), &x, m->body, m->bend); if(len > 0){ if(m->ballocd) free(m->body); m->body = x; m->bend = x + len; m->ballocd = 1; } m->converted = 1;}static inthex2int(int x){ if(x >= '0' && x <= '9') return x - '0'; if(x >= 'A' && x <= 'F') return (x - 'A') + 10; if(x >= 'a' && x <= 'f') return (x - 'a') + 10; return 0;}// underscores are translated in 2047 headers (uscores=1) // but not in the body (uscores=0)static char*decquotedline(char *out, char *in, char *e, int uscores){ int c, soft; /* dump trailing white space */ while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n')) e--; /* trailing '=' means no newline */ if(*e == '='){ soft = 1; e--; } else soft = 0; while(in <= e){ c = (*in++) & 0xff; switch(c){ case '_': if(uscores){ *out++ = ' '; break; } default: *out++ = c; break; case '=': c = hex2int(*in++)<<4; c |= hex2int(*in++); *out++ = c; break; } } if(!soft) *out++ = '\n'; *out = 0; return out;}intdecquoted(char *out, char *in, char *e, int uscores){ char *p, *nl; p = out; while((nl = strchr(in, '\n')) != nil && nl < e){ p = decquotedline(p, in, nl, uscores); in = nl + 1; } if(in < e) p = decquotedline(p, in, e-1, uscores); // make sure we end with a new line if(*(p-1) != '\n'){ *p++ = '\n'; *p = 0; } return p - out;}static char*lowercase(char *p){ char *op; int c; for(op = p; c = *p; p++) if(isupper(c)) *p = tolower(c); return op;}// translate latin1 directly since it fits neatly in utfstatic intlatin1toutf(char **out, char *in, char *e){ int n; char *p; Rune r; n = 0; for(p = in; p < e; p++) if(*p & 0x80) n++; if(n == 0) return 0; n += e-in; *out = p = malloc(n+1); if(p == nil) return 0; for(; in < e; in++){ r = (uchar)*in; p += runetochar(p, &r); } *p = 0; return p - *out;}// translate any thing using the tcs programintxtoutf(char *charset, char **out, char *in, char *e){ char *av[4]; int totcs[2]; int fromtcs[2]; int n, len, sofar; char *p; // might not need to convert if(cistrcmp(charset, "us-ascii") == 0 || cistrcmp(charset, "utf-8") == 0) return 0; if(cistrcmp(charset, "iso-8859-1") == 0) return latin1toutf(out, in, e); len = e-in+1; sofar = 0; *out = p = malloc(len+1); if(p == nil) return 0; av[0] = charset; av[1] = "-f"; av[2] = charset; av[3] = 0; if(pipe(totcs) < 0) goto error; if(pipe(fromtcs) < 0){ close(totcs[0]); close(totcs[1]); goto error; } switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ case -1: close(fromtcs[0]); close(fromtcs[1]); close(totcs[0]); close(totcs[1]); goto error; case 0: close(fromtcs[0]); close(totcs[1]); dup(fromtcs[1], 1); dup(totcs[0], 0); close(fromtcs[1]); close(totcs[0]); dup(open("/dev/null", OWRITE), 2); exec("/bin/tcs", av); _exits(0); default: close(fromtcs[1]); close(totcs[0]); switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ case -1: close(fromtcs[0]); close(totcs[1]); goto error; case 0: close(fromtcs[0]); while(in < e){ n = write(totcs[1], in, e-in); if(n <= 0) break; in += n; } close(totcs[1]); _exits(0); default: close(totcs[1]); for(;;){ n = read(fromtcs[0], &p[sofar], len-sofar); if(n <= 0) break; sofar += n; p[sofar] = 0; if(sofar == len){ len += 1024; p = realloc(p, len+1); if(p == nil) goto error; *out = p; } } close(fromtcs[0]); break; } break; } if(sofar == 0) goto error; return sofar;error: free(*out); *out = nil; return 0;}void *emalloc(ulong n){ void *p; p = mallocz(n, 1); if(!p){ fprint(2, "%s: out of memory alloc %lud\n", argv0, n); exits("out of memory"); } setmalloctag(p, getcallerpc(&n)); return p;}void *erealloc(void *p, ulong n){ if(n == 0) n = 1; p = realloc(p, n); if(!p){ fprint(2, "%s: out of memory realloc %lud\n", argv0, n); exits("out of memory"); } setrealloctag(p, getcallerpc(&p)); return p;}voidmailplumb(Mailbox *mb, Message *m, int delete){ Plumbmsg p; Plumbattr a[7]; char buf[256]; int ai; char lenstr[10], *from, *subject, *date; static int fd = -1; if(m->subject822 == nil) subject = ""; else subject = s_to_c(m->subject822); if(m->from822 != nil) from = s_to_c(m->from822); else if(m->unixfrom != nil) from = s_to_c(m->unixfrom); else from = ""; if(m->unixdate != nil) date = s_to_c(m->unixdate); else date = ""; sprint(lenstr, "%ld", m->end-m->start); if(biffing && !delete) print("[ %s / %s / %s ]\n", from, subject, lenstr); if(!plumbing) return; if(fd < 0) fd = plumbopen("send", OWRITE); if(fd < 0) return; p.src = "mailfs"; p.dst = "seemail"; p.wdir = "/mail/fs"; p.type = "text"; ai = 0; a[ai].name = "filetype"; a[ai].value = "mail"; a[++ai].name = "sender"; a[ai].value = from; a[ai-1].next = &a[ai]; a[++ai].name = "length"; a[ai].value = lenstr; a[ai-1].next = &a[ai]; a[++ai].name = "mailtype"; a[ai].value = delete?"delete":"new"; a[ai-1].next = &a[ai]; a[++ai].name = "date"; a[ai].value = date; a[ai-1].next = &a[ai]; if(m->sdigest){ a[++ai].name = "digest"; a[ai].value = s_to_c(m->sdigest); a[ai-1].next = &a[ai]; } a[ai].next = nil; p.attr = a; snprint(buf, sizeof(buf), "%s/%s/%s", mntpt, mb->name, m->name); p.ndata = strlen(buf); p.data = buf; plumbsend(fd, &p);}//// count the number of lines in the body (for imap4)//voidcountlines(Message *m){ int i; char *p; i = 0; for(p = strchr(m->rbody, '\n'); p != nil && p < m->rbend; p = strchr(p+1, '\n')) i++; sprint(m->lines, "%d", i);}char *LOG = "fs";voidlogmsg(char *s, Message *m){ int pid; if(!logging) return; pid = getpid(); if(m == nil) syslog(0, LOG, "%s.%d: %s", user, pid, s); else syslog(0, LOG, "%s.%d: %s msg from %s digest %s", user, pid, s, m->from822 ? s_to_c(m->from822) : "?", s_to_c(m->sdigest));}/* * squeeze nulls out of the body */static voidnullsqueeze(Message *m){ char *p, *q; q = memchr(m->body, 0, m->end-m->body); if(q == nil) return; for(p = m->body; q < m->end; q++){ if(*q == 0) continue; *p++ = *q; } m->bend = m->rbend = m->end = p;}//// convert an RFC822 date into a Unix style date// for when the Unix From line isn't there (e.g. POP3).// enough client programs depend on having a Unix date// that it's easiest to write this conversion code once, right here.//// people don't follow RFC822 particularly closely,// so we use strtotm, which is a bunch of heuristics.//extern int strtotm(char*, Tm*);String*date822tounix(char *s){ char *p, *q; Tm tm; if(strtotm(s, &tm) < 0) return nil; p = asctime(&tm); if(q = strchr(p, '\n')) *q = '\0'; return s_copy(p);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -