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

📄 mbox.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "common.h"#include <ctype.h>#include <plumb.h>#include <libsec.h>#include "dat.h"typedef struct Header Header;struct Header {	char *type;	void (*f)(Message*, Header*, char*);	int len;};/* headers */static	void	ctype(Message*, Header*, char*);static	void	cencoding(Message*, Header*, char*);static	void	cdisposition(Message*, Header*, char*);static	void	date822(Message*, Header*, char*);static	void	from822(Message*, Header*, char*);static	void	to822(Message*, Header*, char*);static	void	sender822(Message*, Header*, char*);static	void	replyto822(Message*, Header*, char*);static	void	subject822(Message*, Header*, char*);static	void	inreplyto822(Message*, Header*, char*);static	void	cc822(Message*, Header*, char*);static	void	bcc822(Message*, Header*, char*);static	void	messageid822(Message*, Header*, char*);static	void	mimeversion(Message*, Header*, char*);static	void	nullsqueeze(Message*);enum{	Mhead=	11,	/* offset of first mime header */};Header head[] ={	{ "date:", date822, },	{ "from:", from822, },	{ "to:", to822, },	{ "sender:", sender822, },	{ "reply-to:", replyto822, },	{ "subject:", subject822, },	{ "cc:", cc822, },	{ "bcc:", bcc822, },	{ "in-reply-to:", inreplyto822, },	{ "mime-version:", mimeversion, },	{ "message-id:", messageid822, },[Mhead]	{ "content-type:", ctype, },	{ "content-transfer-encoding:", cencoding, },	{ "content-disposition:", cdisposition, },	{ 0, },};static	void	fatal(char *fmt, ...);static	void	initquoted(void);static	void	startheader(Message*);static	void	startbody(Message*);static	char*	skipwhite(char*);static	char*	skiptosemi(char*);static	char*	getstring(char*, String*, int);static	void	setfilename(Message*, char*);static	char*	lowercase(char*);static	int	is8bit(Message*);static	int	headerline(char**, String*);static	void	initheaders(void);static void	parseattachments(Message*, Mailbox*);int		debug;char *Enotme = "path not served by this file server";enum{	Chunksize = 1024,};Mailboxinit *boxinit[] = {	imap4mbox,	pop3mbox,	plan9mbox,};char*syncmbox(Mailbox *mb, int doplumb){	return (*mb->sync)(mb, doplumb);}/* create a new mailbox */char*newmbox(char *path, char *name, int std){	Mailbox *mb, **l;	char *p, *rv;	int i;	initheaders();	mb = emalloc(sizeof(*mb));	strncpy(mb->path, path, sizeof(mb->path)-1);	if(name == nil){		p = strrchr(path, '/');		if(p == nil)			p = path;		else			p++;		if(*p == 0){			free(mb);			return "bad mbox name";		}		strncpy(mb->name, p, sizeof(mb->name)-1);	} else {		strncpy(mb->name, name, sizeof(mb->name)-1);	}	rv = nil;	// check for a mailbox type	for(i=0; i<nelem(boxinit); i++)		if((rv = (*boxinit[i])(mb, path)) != Enotme)			break;	if(i == nelem(boxinit)){		free(mb);		return "bad path";	}	// on error, give up	if(rv){		free(mb);		return rv;	}	// make sure name isn't taken	qlock(&mbllock);	for(l = &mbl; *l != nil; l = &(*l)->next){		if(strcmp((*l)->name, mb->name) == 0){			if(strcmp(path, (*l)->path) == 0)				rv = nil;			else				rv = "mbox name in use";			if(mb->close)				(*mb->close)(mb);			free(mb);			qunlock(&mbllock);			return rv;		}	}	// always try locking	mb->dolock = 1;	mb->refs = 1;	mb->next = nil;	mb->id = newid();	mb->root = newmessage(nil);	mb->std = std;	*l = mb;	qunlock(&mbllock);	qlock(mb);	if(mb->ctl){		henter(PATH(mb->id, Qmbox), "ctl",			(Qid){PATH(mb->id, Qmboxctl), 0, QTFILE}, nil, mb);	}	rv = syncmbox(mb, 0);	qunlock(mb);	return rv;}// close the named mailboxvoidfreembox(char *name){	Mailbox **l, *mb;	qlock(&mbllock);	for(l=&mbl; *l != nil; l=&(*l)->next){		if(strcmp(name, (*l)->name) == 0){			mb = *l;			*l = mb->next;			mboxdecref(mb);			break;		}	}	hfree(PATH(0, Qtop), name);	qunlock(&mbllock);}static voidinitheaders(void){	Header *h;	static int already;	if(already)		return;	already = 1;	for(h = head; h->type != nil; h++)		h->len = strlen(h->type);}/* *  parse a Unix style header */voidparseunix(Message *m){	char *p;	String *h;	h = s_new();	for(p = m->start + 5; *p && *p != '\r' && *p != '\n'; p++)		s_putc(h, *p);	s_terminate(h);	s_restart(h);	m->unixfrom = s_parse(h, s_reset(m->unixfrom));	m->unixdate = s_append(s_reset(m->unixdate), h->ptr);	s_free(h);}/* *  parse a message */voidparseheaders(Message *m, int justmime, Mailbox *mb, int addfrom){	String *hl;	Header *h;	char *p, *q;	int i;	if(m->whole == m->whole->whole){		henter(PATH(mb->id, Qmbox), m->name,			(Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);	} else {		henter(PATH(m->whole->id, Qdir), m->name,			(Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);	}	for(i = 0; i < Qmax; i++)		henter(PATH(m->id, Qdir), dirtab[i],			(Qid){PATH(m->id, i), 0, QTFILE}, m, mb);	// parse mime headers	p = m->header;	hl = s_new();	while(headerline(&p, hl)){		if(justmime)			h = &head[Mhead];		else			h = head;		for(; h->type; h++){			if(cistrncmp(s_to_c(hl), h->type, h->len) == 0){				(*h->f)(m, h, s_to_c(hl));				break;			}		}		s_reset(hl);	}	s_free(hl);	// the blank line isn't really part of the body or header	if(justmime){		m->mhend = p;		m->hend = m->header;	} else {		m->hend = p;	}	if(*p == '\n')		p++;	m->rbody = m->body = p;	// if type is text, get any nulls out of the body.  This is	// for the two seans and imap clients that get confused.	if(strncmp(s_to_c(m->type), "text/", 5) == 0)		nullsqueeze(m);	//	// cobble together Unix-style from line	// for local mailbox messages, we end up recreating the	// original header.	// for pop3 messages, the best we can do is 	// use the From: information and the RFC822 date.	//	if(m->unixdate == nil || strcmp(s_to_c(m->unixdate), "???") == 0	|| strcmp(s_to_c(m->unixdate), "Thu Jan 1 00:00:00 GMT 1970") == 0){		if(m->unixdate){			s_free(m->unixdate);			m->unixdate = nil;		}		// look for the date in the first Received: line.		// it's likely to be the right time zone (it's	 	// the local system) and in a convenient format.		if(cistrncmp(m->header, "received:", 9)==0){			if((q = strchr(m->header, ';')) != nil){				p = q;				while((p = strchr(p, '\n')) != nil){					if(p[1] != ' ' && p[1] != '\t' && p[1] != '\n')						break;					p++;				}				if(p){					*p = '\0';					m->unixdate = date822tounix(q+1);					*p = '\n';				}			}		}		// fall back on the rfc822 date			if(m->unixdate==nil && m->date822)			m->unixdate = date822tounix(s_to_c(m->date822));	}	if(m->unixheader != nil)		s_free(m->unixheader);	// only fake header for top-level messages for pop3 and imap4	// clients (those protocols don't include the unix header).	// adding the unix header all the time screws up mime-attached	// rfc822 messages.	if(!addfrom && !m->unixfrom){		m->unixheader = nil;		return;	}	m->unixheader = s_copy("From ");	if(m->unixfrom && strcmp(s_to_c(m->unixfrom), "???") != 0)		s_append(m->unixheader, s_to_c(m->unixfrom));	else if(m->from822)		s_append(m->unixheader, s_to_c(m->from822));	else		s_append(m->unixheader, "???");	s_append(m->unixheader, " ");	if(m->unixdate)		s_append(m->unixheader, s_to_c(m->unixdate));	else		s_append(m->unixheader, "Thu Jan  1 00:00:00 GMT 1970");	s_append(m->unixheader, "\n");}String*promote(String **sp){	String *s;	if(*sp != nil)		s = s_clone(*sp);	else		s = nil;	return s;}voidparsebody(Message *m, Mailbox *mb){	Message *nm;	// recurse	if(strncmp(s_to_c(m->type), "multipart/", 10) == 0){		parseattachments(m, mb);	} else if(strcmp(s_to_c(m->type), "message/rfc822") == 0){		decode(m);		parseattachments(m, mb);		nm = m->part;		// promote headers		if(m->replyto822 == nil && m->from822 == nil && m->sender822 == nil){			m->from822 = promote(&nm->from822);			m->to822 = promote(&nm->to822);			m->date822 = promote(&nm->date822);			m->sender822 = promote(&nm->sender822);			m->replyto822 = promote(&nm->replyto822);			m->subject822 = promote(&nm->subject822);			m->unixdate = promote(&nm->unixdate);		}	}}voidparse(Message *m, int justmime, Mailbox *mb, int addfrom){	parseheaders(m, justmime, mb, addfrom);	parsebody(m, mb);}static voidparseattachments(Message *m, Mailbox *mb){	Message *nm, **l;	char *p, *x;	// if there's a boundary, recurse...	if(m->boundary != nil){		p = m->body;		nm = nil;		l = &m->part;		for(;;){			x = strstr(p, s_to_c(m->boundary));			/* no boundary, we're done */			if(x == nil){				if(nm != nil)					nm->rbend = nm->bend = nm->end = m->bend;				break;			}			/* boundary must be at the start of a line */			if(x != m->body && *(x-1) != '\n'){				p = x+1;				continue;			}			if(nm != nil)				nm->rbend = nm->bend = nm->end = x;			x += strlen(s_to_c(m->boundary));			/* is this the last part? ignore anything after it */			if(strncmp(x, "--", 2) == 0)				break;			p = strchr(x, '\n');			if(p == nil)				break;			nm = newmessage(m);			nm->start = nm->header = nm->body = nm->rbody = ++p;			nm->mheader = nm->header;			*l = nm;			l = &nm->next;		}		for(nm = m->part; nm != nil; nm = nm->next)			parse(nm, 1, mb, 0);		return;	}	// if we've got an rfc822 message, recurse...	if(strcmp(s_to_c(m->type), "message/rfc822") == 0){		nm = newmessage(m);		m->part = nm;		nm->start = nm->header = nm->body = nm->rbody = m->body;		nm->end = nm->bend = nm->rbend = m->bend;		parse(nm, 0, mb, 0);	}}/* *  pick up a header line */static intheaderline(char **pp, String *hl){	char *p, *x;	s_reset(hl);	p = *pp;	x = strpbrk(p, ":\n");	if(x == nil || *x == '\n')		return 0;	for(;;){		x = strchr(p, '\n');		if(x == nil)			x = p + strlen(p);		s_nappend(hl, p, x-p);		p = x;		if(*p != '\n' || *++p != ' ' && *p != '\t')			break;		while(*p == ' ' || *p == '\t')			p++;		s_putc(hl, ' ');	}	*pp = p;	return 1;}static String*addr822(char *p){	String *s, *list;	int incomment, addrdone, inanticomment, quoted;	int n;	int c;	list = s_new();	s = s_new();	quoted = incomment = addrdone = inanticomment = 0;	n = 0;	for(; *p; p++){		c = *p;		// whitespace is ignored		if(!quoted && isspace(c) || c == '\r')			continue;		// strings are always treated as atoms		if(!quoted && c == '"'){			if(!addrdone && !incomment)				s_putc(s, c);			for(p++; *p; p++){				if(!addrdone && !incomment)					s_putc(s, *p);				if(!quoted && *p == '"')					break;				if(*p == '\\')					quoted = 1;				else					quoted = 0;			}			if(*p == 0)				break;			quoted = 0;			continue;		}		// ignore everything in an expicit comment		if(!quoted && c == '('){			incomment = 1;			continue;		}		if(incomment){			if(!quoted && c == ')')				incomment = 0;			quoted = 0;			continue;		}		// anticomments makes everything outside of them comments		if(!quoted && c == '<' && !inanticomment){			inanticomment = 1;			s = s_reset(s);			continue;		}		if(!quoted && c == '>' && inanticomment){			addrdone = 1;			inanticomment = 0;			continue;		}		// commas separate addresses		if(!quoted && c == ',' && !inanticomment){			s_terminate(s);			addrdone = 0;			if(n++ != 0)				s_append(list, " ");			s_append(list, s_to_c(s));			s = s_reset(s);			continue;		}		// what's left is part of the address		s_putc(s, c);		// quoted characters are recognized only as characters		if(c == '\\')			quoted = 1;		else			quoted = 0;	}	if(*s_to_c(s) != 0){		s_terminate(s);		if(n++ != 0)			s_append(list, " ");		s_append(list, s_to_c(s));	}	s_free(s);	if(n == 0){		s_free(list);		return nil;	}	return list;}static voidto822(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->to822);	m->to822 = addr822(p);}static voidcc822(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->cc822);	m->cc822 = addr822(p);}static voidbcc822(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->bcc822);	m->bcc822 = addr822(p);}static voidfrom822(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->from822);	m->from822 = addr822(p);}static voidsender822(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->sender822);	m->sender822 = addr822(p);}static voidreplyto822(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->replyto822);	m->replyto822 = addr822(p);}static voidmimeversion(Message *m, Header *h, char *p){	p += strlen(h->type);	s_free(m->mimeversion);	m->mimeversion = addr822(p);}static voidkilltrailingwhite(char *p){	char *e;	e = p + strlen(p) - 1;	while(e > p && isspace(*e))		*e-- = 0;}static voiddate822(Message *m, Header *h, char *p){	p += strlen(h->type);	p = skipwhite(p);	s_free(m->date822);	m->date822 = s_copy(p);	p = s_to_c(m->date822);	killtrailingwhite(p);}static voidsubject822(Message *m, Header *h, char *p){	p += strlen(h->type);	p = skipwhite(p);	s_free(m->subject822);	m->subject822 = s_copy(p);	p = s_to_c(m->subject822);	killtrailingwhite(p);}static voidinreplyto822(Message *m, Header *h, char *p){	p += strlen(h->type);	p = skipwhite(p);	s_free(m->inreplyto822);	m->inreplyto822 = s_copy(p);	p = s_to_c(m->inreplyto822);	killtrailingwhite(p);}static voidmessageid822(Message *m, Header *h, char *p){	p += strlen(h->type);	p = skipwhite(p);	s_free(m->messageid822);	m->messageid822 = s_copy(p);	p = s_to_c(m->messageid822);	killtrailingwhite(p);}static intisattribute(char **pp, char *attr){	char *p;	int n;	n = strlen(attr);	p = *pp;	if(cistrncmp(p, attr, n) != 0)		return 0;	p += n;	while(*p == ' ')		p++;	if(*p++ != '=')		return 0;	while(*p == ' ')		p++;	*pp = p;	return 1;}static voidctype(Message *m, Header *h, char *p){	String *s;	p += h->len;	p = skipwhite(p);	p = getstring(p, m->type, 1);		while(*p){		if(isattribute(&p, "boundary")){			s = s_new();			p = getstring(p, s, 0);			m->boundary = s_reset(m->boundary);			s_append(m->boundary, "--");			s_append(m->boundary, s_to_c(s));			s_free(s);		} else if(cistrncmp(p, "multipart", 9) == 0){			/*			 *  the first unbounded part of a multipart message,			 *  the preamble, is not displayed or saved			 */		} else if(isattribute(&p, "name")){			if(m->filename == nil)				setfilename(m, p);		} else if(isattribute(&p, "charset")){			p = getstring(p, s_reset(m->charset), 0);		}				p = skiptosemi(p);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -