⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msg.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#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 + -