📄 msg.c
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <libsec.h>#include <auth.h>#include <fcall.h>#include "imap4d.h"static void body64(int in, int out);static void bodystrip(int in, int out);static void cleanupHeader(Header *h);static char *domBang(char *s);static void freeMAddr(MAddr *a);static void freeMimeHdr(MimeHdr *mh);static char *headAddrSpec(char *e, char *w);static MAddr *headAddresses(void);static MAddr *headAddress(void);static char *headAtom(char *disallowed);static int headChar(int eat);static char *headDomain(char *e);static MAddr *headMAddr(MAddr *old);static char *headPhrase(char *e, char *w);static char *headQuoted(int start, int stop);static char *headSkipWhite(int);static void headSkip(void);static char *headSubDomain(void);static char *headText(void);static void headToEnd(void);static char *headWord(void);static void mimeDescription(Header *h);static void mimeDisposition(Header *h);static void mimeEncoding(Header *h);static void mimeId(Header *h);static void mimeLanguage(Header *h);static void mimeMd5(Header *h);static MimeHdr *mimeParams(void);static void mimeType(Header *h);static MimeHdr *mkMimeHdr(char *s, char *t, MimeHdr *next);static void msgAddDate(Msg *m);static void msgAddHead(Msg *m, char *head, char *body);static int msgBodySize(Msg *m);static int msgHeader(Msg *m, Header *h, char *file);static long msgReadFile(Msg *m, char *file, char **ss);static int msgUnix(Msg *m, int top);static void stripQuotes(char *q);static MAddr *unixFrom(char *s);static char bogusBody[] = "This message contains null characters, so it cannot be displayed correctly.\r\n" "Most likely you were sent a bogus message or a binary file.\r\n" "\r\n" "Each of the following attachments has a different version of the message.\r\n" "The first is inlined with all non-printable characters stripped.\r\n" "The second contains the message as it was stored in your mailbox.\r\n" "The third has the initial header stripped.\r\n";static char bogusMimeText[] = "Content-Disposition: inline\r\n" "Content-Type: text/plain; charset=\"US-ASCII\"\r\n" "Content-Transfer-Encoding: 7bit\r\n";static char bogusMimeBinary[] = "Content-Disposition: attachment\r\n" "Content-Type: application/octet-stream\r\n" "Content-Transfer-Encoding: base64\r\n";/* * stop list for header fields */static char *headFieldStop = ":";static char *mimeTokenStop = "()<>@,;:\\\"/[]?=";static char *headAtomStop = "()<>@,;:\\\".[]";static uchar *headStr;static uchar *lastWhite;longselectFields(char *dst, long n, char *hdr, SList *fields, int matches){ SList *f; uchar *start; char *s; long m, nf; headStr = (uchar*)hdr; m = 0; for(;;){ start = headStr; s = headAtom(headFieldStop); if(s == nil) break; headSkip(); for(f = fields; f != nil; f = f->next){ if(cistrcmp(s, f->s) == !matches){ nf = headStr - start; if(m + nf > n) return 0; memmove(&dst[m], start, nf); m += nf; } } free(s); } if(m + 3 > n) return 0; dst[m++] = '\r'; dst[m++] = '\n'; dst[m] = '\0'; return m;}voidfreeMsg(Msg *m){ Msg *k, *last; free(m->iBuf); freeMAddr(m->to); if(m->replyTo != m->from) freeMAddr(m->replyTo); if(m->sender != m->from) freeMAddr(m->sender); if(m->from != m->unixFrom) freeMAddr(m->from); freeMAddr(m->unixFrom); freeMAddr(m->cc); freeMAddr(m->bcc); free(m->unixDate); cleanupHeader(&m->head); cleanupHeader(&m->mime); for(k = m->kids; k != nil; ){ last = k; k = k->next; freeMsg(last); } free(m);}ulongmsgSize(Msg *m){ return m->head.size + m->size;}intinfoIsNil(char *s){ return s == nil || s[0] == '\0';}char*maddrStr(MAddr *a){ char *host, *addr; int n; host = a->host; if(host == nil) host = ""; n = strlen(a->box) + strlen(host) + 2; if(a->personal != nil) n += strlen(a->personal) + 3; addr = emalloc(n); if(a->personal != nil) snprint(addr, n, "%s <%s@%s>", a->personal, a->box, host); else snprint(addr, n, "%s@%s", a->box, host); return addr;}/* * return actual name of f in m's fs directory * this is special cased when opening m/rawbody, m/mimeheader, or m/rawheader, * if the message was corrupted. in that case, * a temporary file is made to hold the base64 encoding of m/raw. */intmsgFile(Msg *m, char *f){ Msg *parent, *p; Dir d; Tm tm; char buf[64], nbuf[2]; uchar dbuf[64]; int i, n, fd, fd1, fd2; if(!m->bogus || strcmp(f, "") != 0 && strcmp(f, "rawbody") != 0 && strcmp(f, "rawheader") != 0 && strcmp(f, "mimeheader") != 0 && strcmp(f, "info") != 0 && strcmp(f, "unixheader") != 0){ if(strlen(f) > MsgNameLen) bye("internal error: msgFile name too long"); strcpy(m->efs, f); return cdOpen(m->fsDir, m->fs, OREAD); } /* * walk up the stupid runt message parts for non-multipart messages */ parent = m->parent; if(parent != nil && parent->parent != nil){ m = parent; parent = m->parent; } p = m; if(parent != nil) p = parent; if(strcmp(f, "info") == 0 || strcmp(f, "unixheader") == 0){ strcpy(p->efs, f); return cdOpen(p->fsDir, p->fs, OREAD); } fd = imapTmp(); if(fd < 0) return -1; /* * craft the message parts for bogus messages */ if(strcmp(f, "") == 0){ /* * make a fake directory for each kid * all we care about is the name */ if(parent == nil){ nulldir(&d); d.mode = DMDIR|0600; d.qid.type = QTDIR; d.name = nbuf; nbuf[1] = '\0'; for(i = '1'; i <= '4'; i++){ nbuf[0] = i; n = convD2M(&d, dbuf, sizeof(dbuf)); if(n <= BIT16SZ) fprint(2, "bad convD2M %d\n", n); write(fd, dbuf, n); } } }else if(strcmp(f, "mimeheader") == 0){ if(parent != nil){ switch(m->id){ case 1: case 2: fprint(fd, "%s", bogusMimeText); break; case 3: case 4: fprint(fd, "%s", bogusMimeBinary); break; } } }else if(strcmp(f, "rawheader") == 0){ if(parent == nil){ date2tm(&tm, m->unixDate); rfc822date(buf, sizeof(buf), &tm); fprint(fd, "Date: %s\r\n" "From: imap4 daemon <%s@%s>\r\n" "To: <%s@%s>\r\n" "Subject: This message was illegal or corrupted\r\n" "MIME-Version: 1.0\r\n" "Content-Type: multipart/mixed;\r\n\tboundary=\"upas-%s\"\r\n", buf, username, site, username, site, m->info[IDigest]); } }else if(strcmp(f, "rawbody") == 0){ fd1 = msgFile(p, "raw"); strcpy(p->efs, "rawbody"); fd2 = cdOpen(p->fsDir, p->fs, OREAD); if(fd1 < 0 || fd2 < 0){ close(fd); close(fd1); close(fd2); return -1; } if(parent == nil){ fprint(fd, "This is a multi-part message in MIME format.\r\n" "--upas-%s\r\n" "%s" "\r\n" "%s" "\r\n", m->info[IDigest], bogusMimeText, bogusBody); fprint(fd, "--upas-%s\r\n" "%s" "\r\n", m->info[IDigest], bogusMimeText); bodystrip(fd1, fd); fprint(fd, "--upas-%s\r\n" "%s" "\r\n", m->info[IDigest], bogusMimeBinary); seek(fd1, 0, 0); body64(fd1, fd); fprint(fd, "--upas-%s\r\n" "%s" "\r\n", m->info[IDigest], bogusMimeBinary); body64(fd2, fd); fprint(fd, "--upas-%s--\r\n", m->info[IDigest]); }else{ switch(m->id){ case 1: fprint(fd, "%s", bogusBody); break; case 2: bodystrip(fd1, fd); break; case 3: body64(fd1, fd); break; case 4: body64(fd2, fd); break; } } close(fd1); close(fd2); } seek(fd, 0, 0); return fd;}intmsgIsMulti(Header *h){ return h->type != nil && cistrcmp("multipart", h->type->s) == 0;}intmsgIsRfc822(Header *h){ return h->type != nil && cistrcmp("message", h->type->s) == 0 && cistrcmp("rfc822", h->type->t) == 0;}/* * check if a message has been deleted by someone else */voidmsgDead(Msg *m){ if(m->expunged) return; *m->efs = '\0'; if(!cdExists(m->fsDir, m->fs)) m->expunged = 1;}/* * make sure the message has valid associated info * used for ISubject, IDigest, IInReplyTo, IMessageId. */intmsgInfo(Msg *m){ char *s; int i; if(m->info[0] != nil) return 1; i = msgReadFile(m, "info", &m->iBuf); if(i < 0) return 0; s = m->iBuf; for(i = 0; i < IMax; i++){ m->info[i] = s; s = strchr(s, '\n'); if(s == nil) break; *s++ = '\0'; } for(; i < IMax; i++) m->info[i] = nil; for(i = 0; i < IMax; i++) if(infoIsNil(m->info[i])) m->info[i] = nil; return 1;}/* * make sure the message has valid mime structure * and sub-messages */intmsgStruct(Msg *m, int top){ Msg *k, head, *last; Dir *d; char *s; ulong max, id; int i, nd, fd, ns; if(m->kids != nil) return 1; if(m->expunged || !msgInfo(m) || !msgUnix(m, top) || !msgBodySize(m) || !msgHeader(m, &m->mime, "mimeheader") || (top || msgIsRfc822(&m->mime) || msgIsMulti(&m->mime)) && !msgHeader(m, &m->head, "rawheader")){ if(top && m->bogus && !(m->bogus & BogusTried)){ m->bogus |= BogusTried; return msgStruct(m, top); } msgDead(m); return 0; } /* * if a message has no kids, it has a kid which is just the body of the real message */ if(!msgIsMulti(&m->head) && !msgIsMulti(&m->mime) && !msgIsRfc822(&m->head) && !msgIsRfc822(&m->mime)){ k = MKZ(Msg); k->id = 1; k->fsDir = m->fsDir; k->bogus = m->bogus; k->parent = m->parent; ns = m->efs - m->fs; k->fs = emalloc(ns + (MsgNameLen + 1)); memmove(k->fs, m->fs, ns); k->efs = k->fs + ns; *k->efs = '\0'; k->size = m->size; m->kids = k; return 1; } /* * read in all child messages messages */ fd = msgFile(m, ""); if(fd < 0){ msgDead(m); return 0; } max = 0; head.next = nil; last = &head; while((nd = dirread(fd, &d)) > 0){ for(i = 0; i < nd; i++){ s = d[i].name; id = strtol(s, &s, 10); if(id <= max || *s != '\0' || (d[i].mode & DMDIR) != DMDIR) continue; max = id; k = MKZ(Msg); k->id = id; k->fsDir = m->fsDir; k->bogus = m->bogus; k->parent = m; ns = strlen(m->fs); k->fs = emalloc(ns + 2 * (MsgNameLen + 1)); k->efs = seprint(k->fs, k->fs + ns + (MsgNameLen + 1), "%s%lud/", m->fs, id); k->prev = last; k->size = ~0UL; k->lines = ~0UL; last->next = k; last = k; } } close(fd); m->kids = head.next; /* * if kids fail, just whack them */ top = top && (msgIsRfc822(&m->head) || msgIsMulti(&m->head)); for(k = m->kids; k != nil; k = k->next){ if(!msgStruct(k, top)){ for(k = m->kids; k != nil; ){ last = k; k = k->next; freeMsg(last); } m->kids = nil; break; } } return 1;}static longmsgReadFile(Msg *m, char *file, char **ss){ Dir *d; char *s, buf[BufSize]; vlong length; long n, nn; int fd; fd = msgFile(m, file); if(fd < 0){ msgDead(m); return -1; } n = read(fd, buf, BufSize); if(n < BufSize){ close(fd); if(n < 0){ *ss = nil; return -1; } s = emalloc(n + 1); memmove(s, buf, n); s[n] = '\0'; *ss = s; return n; } d = dirfstat(fd); if(d == nil){ close(fd); return -1; } length = d->length; free(d); nn = length; s = emalloc(nn + 1); memmove(s, buf, n); if(nn > n) nn = readn(fd, s+n, nn-n) + n; close(fd); if(nn != length){ free(s); return -1; } s[nn] = '\0'; *ss = s; return nn;}static voidfreeMAddr(MAddr *a){ MAddr *p; while(a != nil){ p = a; a = a->next; free(p->personal); free(p->box); free(p->host); free(p); }}/* * the message is corrupted or illegal. * reset message fields. msgStruct will reparse the message, * relying on msgFile to make up corrected body parts. */static intmsgBogus(Msg *m, int flags){ if(!(m->bogus & flags)) m->bogus |= flags; m->lines = ~0; free(m->head.buf); free(m->mime.buf); memset(&m->head, 0, sizeof(Header)); memset(&m->mime, 0, sizeof(Header)); return 0;}/* * stolen from upas/marshal; base64 encodes from one fd to another. * * the size of buf is very important to enc64. Anything other than * a multiple of 3 will cause enc64 to output a termination sequence. * To ensure that a full buf corresponds to a multiple of complete lines, * we make buf a multiple of 3*18 since that's how many enc64 sticks on * a single line. This avoids short lines in the output which is pleasing * but not necessary. */static intenc64x18(char *out, int lim, uchar *in, int n)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -