msg.c
来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 1,781 行 · 第 1/3 页
C
1,781 行
{ int m, mm, nn; nn = 0; for(; n > 0; n -= m){ m = 18 * 3; if(m > n) m = n; mm = enc64(out, lim - nn, in, m); in += m; out += mm; *out++ = '\r'; *out++ = '\n'; nn += mm + 2; } return nn;}static voidbody64(int in, int out){ uchar buf[3*18*54]; char obuf[3*18*54*2]; int m, n; for(;;){ n = read(in, buf, sizeof(buf)); if(n < 0) return; if(n == 0) break; m = enc64x18(obuf, sizeof(obuf), buf, n); if(write(out, obuf, m) < 0) return; }}/* * strip all non-printable characters from a file */static voidbodystrip(int in, int out){ uchar buf[3*18*54]; int m, n, i, c; for(;;){ n = read(in, buf, sizeof(buf)); if(n < 0) return; if(n == 0) break; m = 0; for(i = 0; i < n; i++){ c = buf[i]; if(c > 0x1f && c < 0x7f /* normal characters */ || c >= 0x9 && c <= 0xd) /* \t, \n, vertical tab, form feed, \r */ buf[m++] = c; } if(m && write(out, buf, m) < 0) return; }}/* * read in the message body to count \n without a preceding \r */static intmsgBodySize(Msg *m){ Dir *d; char buf[BufSize + 2], *s, *se; vlong length; ulong size, lines, bad; int n, fd, c; if(m->lines != ~0UL) return 1; fd = msgFile(m, "rawbody"); if(fd < 0) return 0; d = dirfstat(fd); if(d == nil){ close(fd); return 0; } length = d->length; free(d); size = 0; lines = 0; bad = 0; buf[0] = ' '; for(;;){ n = read(fd, &buf[1], BufSize); if(n <= 0) break; size += n; se = &buf[n + 1]; for(s = &buf[1]; s < se; s++){ c = *s; if(c == '\0'){ close(fd); return msgBogus(m, BogusBody); } if(c != '\n') continue; if(s[-1] != '\r') bad++; lines++; } buf[0] = buf[n]; } if(size != length) bye("bad length reading rawbody"); size += bad; m->size = size; m->lines = lines; close(fd); return 1;}/* * retrieve information from the unixheader file */static intmsgUnix(Msg *m, int top){ Tm tm; char *s, *ss; if(m->unixDate != nil) return 1; if(!top){bogus: m->unixDate = estrdup(""); m->unixFrom = unixFrom(nil); return 1; } if(msgReadFile(m, "unixheader", &ss) < 0) return 0; s = ss; s = strchr(s, ' '); if(s == nil){ free(ss); goto bogus; } s++; m->unixFrom = unixFrom(s); s = (char*)headStr; if(date2tm(&tm, s) == nil) s = m->info[IUnixDate]; if(s == nil){ free(ss); goto bogus; } m->unixDate = estrdup(s); free(ss); return 1;}/* * parse the address in the unix header * last line of defence, so must return something */static MAddr *unixFrom(char *s){ MAddr *a; char *e, *t; if(s == nil) return nil; headStr = (uchar*)s; t = emalloc(strlen(s) + 2); e = headAddrSpec(t, nil); if(e == nil) a = nil; else{ if(*e != '\0') *e++ = '\0'; else e = site; a = MKZ(MAddr); a->box = estrdup(t); a->host = estrdup(e); } free(t); return a;}/* * read in the entire header, * and parse out any existing mime headers */static intmsgHeader(Msg *m, Header *h, char *file){ char *s, *ss, *t, *te; ulong lines, n, nn; long ns; int dated, c; if(h->buf != nil) return 1; ns = msgReadFile(m, file, &ss); if(ns < 0) return 0; s = ss; n = ns; /* * count lines ending with \n and \r\n * add an extra line at the end, since upas/fs headers * don't have a terminating \r\n */ lines = 1; te = s + ns; for(t = s; t < te; t++){ c = *t; if(c == '\0') return msgBogus(m, BogusHeader); if(c != '\n') continue; if(t == s || t[-1] != '\r') n++; lines++; } if(t > s && t[-1] != '\n'){ if(t[-1] != '\r') n++; n++; } n += 2; h->buf = emalloc(n + 1); h->size = n; h->lines = lines; /* * make sure all headers end in \r\n */ nn = 0; for(t = s; t < te; t++){ c = *t; if(c == '\n'){ if(!nn || h->buf[nn - 1] != '\r') h->buf[nn++] = '\r'; lines++; } h->buf[nn++] = c; } if(nn && h->buf[nn-1] != '\n'){ if(h->buf[nn-1] != '\r') h->buf[nn++] = '\r'; h->buf[nn++] = '\n'; } h->buf[nn++] = '\r'; h->buf[nn++] = '\n'; h->buf[nn] = '\0'; if(nn != n) bye("misconverted header %d %d", nn, n); free(s); /* * and parse some mime headers */ headStr = (uchar*)h->buf; dated = 0; while(s = headAtom(headFieldStop)){ if(cistrcmp(s, "content-type") == 0) mimeType(h); else if(cistrcmp(s, "content-transfer-encoding") == 0) mimeEncoding(h); else if(cistrcmp(s, "content-id") == 0) mimeId(h); else if(cistrcmp(s, "content-description") == 0) mimeDescription(h); else if(cistrcmp(s, "content-disposition") == 0) mimeDisposition(h); else if(cistrcmp(s, "content-md5") == 0) mimeMd5(h); else if(cistrcmp(s, "content-language") == 0) mimeLanguage(h); else if(h == &m->head && cistrcmp(s, "from") == 0) m->from = headMAddr(m->from); else if(h == &m->head && cistrcmp(s, "to") == 0) m->to = headMAddr(m->to); else if(h == &m->head && cistrcmp(s, "reply-to") == 0) m->replyTo = headMAddr(m->replyTo); else if(h == &m->head && cistrcmp(s, "sender") == 0) m->sender = headMAddr(m->sender); else if(h == &m->head && cistrcmp(s, "cc") == 0) m->cc = headMAddr(m->cc); else if(h == &m->head && cistrcmp(s, "bcc") == 0) m->bcc = headMAddr(m->bcc); else if(h == &m->head && cistrcmp(s, "date") == 0) dated = 1; headSkip(); free(s); } if(h == &m->head){ if(m->from == nil){ m->from = m->unixFrom; if(m->from != nil){ s = maddrStr(m->from); msgAddHead(m, "From", s); free(s); } } if(m->sender == nil) m->sender = m->from; if(m->replyTo == nil) m->replyTo = m->from; if(infoIsNil(m->info[IDate])) m->info[IDate] = m->unixDate; if(!dated && m->from != nil) msgAddDate(m); } return 1;}/* * prepend head: body to the cached header */static voidmsgAddHead(Msg *m, char *head, char *body){ char *s; long size, n; n = strlen(head) + strlen(body) + 4; size = m->head.size + n; s = emalloc(size + 1); snprint(s, size + 1, "%s: %s\r\n%s", head, body, m->head.buf); free(m->head.buf); m->head.buf = s; m->head.size = size; m->head.lines++;}static voidmsgAddDate(Msg *m){ Tm tm; char buf[64]; /* don't bother if we don't have a date */ if(infoIsNil(m->info[IDate])) return; date2tm(&tm, m->info[IDate]); rfc822date(buf, sizeof(buf), &tm); msgAddHead(m, "Date", buf);}static MimeHdr*mkMimeHdr(char *s, char *t, MimeHdr *next){ MimeHdr *mh; mh = MK(MimeHdr); mh->s = s; mh->t = t; mh->next = next; return mh;}static voidfreeMimeHdr(MimeHdr *mh){ MimeHdr *last; while(mh != nil){ last = mh; mh = mh->next; free(last->s); free(last->t); free(last); }}static voidcleanupHeader(Header *h){ freeMimeHdr(h->type); freeMimeHdr(h->id); freeMimeHdr(h->description); freeMimeHdr(h->encoding); freeMimeHdr(h->md5); freeMimeHdr(h->disposition); freeMimeHdr(h->language);}/* * parser for rfc822 & mime header fields *//* * type : 'content-type' ':' token '/' token params */static voidmimeType(Header *h){ char *s, *t; if(headChar(1) != ':') return; s = headAtom(mimeTokenStop); if(s == nil || headChar(1) != '/'){ free(s); return; } t = headAtom(mimeTokenStop); if(t == nil){ free(s); return; } h->type = mkMimeHdr(s, t, mimeParams());}/* * params : * | params ';' token '=' token * | params ';' token '=' quoted-str */static MimeHdr*mimeParams(void){ MimeHdr head, *last; char *s, *t; head.next = nil; last = &head; for(;;){ if(headChar(1) != ';') break; s = headAtom(mimeTokenStop); if(s == nil || headChar(1) != '='){ free(s); break; } if(headChar(0) == '"'){ t = headQuoted('"', '"'); stripQuotes(t); }else t = headAtom(mimeTokenStop); if(t == nil){ free(s); break; } last->next = mkMimeHdr(s, t, nil); last = last->next; } return head.next;}/* * encoding : 'content-transfer-encoding' ':' token */static voidmimeEncoding(Header *h){ char *s; if(headChar(1) != ':') return; s = headAtom(mimeTokenStop); if(s == nil) return; h->encoding = mkMimeHdr(s, nil, nil);}/* * mailaddr : ':' addresses */static MAddr*headMAddr(MAddr *old){ MAddr *a; if(headChar(1) != ':') return old; if(headChar(0) == '\n') return old; a = headAddresses(); if(a == nil) return old; freeMAddr(old); return a;}/* * addresses : address | addresses ',' address */static MAddr*headAddresses(void){ MAddr *addr, *tail, *a; addr = headAddress(); if(addr == nil) return nil; tail = addr; while(headChar(0) == ','){ headChar(1); a = headAddress(); if(a == nil){ freeMAddr(addr); return nil; } tail->next = a; tail = a; } return addr;}/* * address : mailbox | group * group : phrase ':' mboxes ';' | phrase ':' ';' * mailbox : addr-spec * | optphrase '<' addr-spec '>' * | optphrase '<' route ':' addr-spec '>' * optphrase : | phrase * route : '@' domain * | route ',' '@' domain * personal names are the phrase before '<', * or a comment before or after a simple addr-spec */static MAddr*headAddress(void){ MAddr *addr; uchar *hs; char *s, *e, *w, *personal; int c; s = emalloc(strlen((char*)headStr) + 2); e = s; personal = headSkipWhite(1); c = headChar(0); if(c == '<') w = nil; else{ w = headWord(); c = headChar(0); } if(c == '.' || c == '@' || c == ',' || c == '\n' || c == '\0'){ lastWhite = headStr; e = headAddrSpec(s, w); if(personal == nil){ hs = headStr; headStr = lastWhite; personal = headSkipWhite(1); headStr = hs; } }else{ if(c != '<' || w != nil){ free(personal); if(!headPhrase(e, w)){ free(s); return nil; } /* * ignore addresses with groups, * so the only thing left if < */ c = headChar(1); if(c != '<'){ free(s); return nil; } personal = estrdup(s); }else headChar(1); /* * after this point, we need to free personal before returning. * set e to nil to everything afterwards fails. * * ignore routes, they are useless, and heavily discouraged in rfc1123. * imap4 reports them up to, but not including, the terminating : */ e = s;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?