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

📄 marshal.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#include "common.h"#include <ctype.h>typedef struct Attach Attach;typedef struct Alias Alias;typedef struct Addr Addr;typedef struct Ctype Ctype;struct Attach {	Attach	*next;	char	*path;	char	*type;	int	ainline;	Ctype	*ctype;};struct Alias{	Alias	*next;	int	n;	Addr	*addr;};struct Addr{	Addr	*next;	char	*v;};enum {	Hfrom,	Hto,	Hcc,	Hbcc,	Hsender,	Hreplyto,	Hinreplyto,	Hdate,	Hsubject,	Hmime,	Hpriority,	Hmsgid,	Hcontent,	Hx,	Hprecedence,	Nhdr,};enum {	PGPsign = 1,	PGPencrypt = 2,};char *hdrs[Nhdr] = {[Hfrom]		"from:",[Hto]		"to:",[Hcc]		"cc:",[Hbcc]		"bcc:",[Hreplyto]	"reply-to:",[Hinreplyto]	"in-reply-to:",[Hsender]	"sender:",[Hdate]		"date:",[Hsubject]	"subject:",[Hpriority]	"priority:",[Hmsgid]	"message-id:",[Hmime]		"mime-",[Hcontent]	"content-",[Hx]		"x-",[Hprecedence]	"precedence",};struct Ctype {	char	*type;	char 	*ext;	int	display;};Ctype ctype[] = {	{ "text/plain",			"txt",	1,	},	{ "text/html",			"html",	1,	},	{ "text/html",			"htm",	1,	},	{ "text/tab-separated-values",	"tsv",	1,	},	{ "text/richtext",		"rtx",	1,	},	{ "message/rfc822",		"txt",	1,	},	{ "", 				0,	0,	},};Ctype *mimetypes;int pid = -1;int pgppid = -1;Attach*	mkattach(char*, char*, int);int	readheaders(Biobuf*, int*, String**, Addr**, int);void	body(Biobuf*, Biobuf*, int);char*	mkboundary(void);int	printdate(Biobuf*);int	printfrom(Biobuf*);int	printto(Biobuf*, Addr*);int	printcc(Biobuf*, Addr*);int	printsubject(Biobuf*, char*);int	printinreplyto(Biobuf*, char*);int	sendmail(Addr*, Addr*, int*, char*);void	attachment(Attach*, Biobuf*);int	cistrncmp(char*, char*, int);int	cistrcmp(char*, char*);char*	waitforsubprocs(void);int	enc64(char*, int, uchar*, int);Addr*	expand(int, char**);Alias*	readaliases(void);Addr*	expandline(String**, Addr*);void	Bdrain(Biobuf*);void	freeaddr(Addr *);int	pgpopts(char*);int	pgpfilter(int*, int, int);void	readmimetypes(void);char*	estrdup(char*);void*	emalloc(int);void*	erealloc(void*, int);void	freeaddr(Addr*);void	freeaddrs(Addr*);void	freealias(Alias*);void	freealiases(Alias*);int	doublequote(Fmt*);int	rfc2047fmt(Fmt*);char*	mksubject(char*);int rflag, lbflag, xflag, holding, nflag, Fflag, eightflag, dflag;int pgpflag = 0;char *user;char *login;Alias *aliases;int rfc822syntaxerror;char lastchar;char *replymsg;enum{	Ok = 0,	Nomessage = 1,	Nobody = 2,	Error = -1,};#pragma varargck	type	"Z"	char*#pragma varargck	type	"U"	char*voidusage(void){	fprint(2, "usage: %s [-Fr#xn] [-s subject] [-c ccrecipient] [-t type] [-aA attachment] [-p[es]] [-R replymsg] -8 | recipient-list\n",		argv0);	exits("usage");}voidfatal(char *fmt, ...){	char buf[1024];	va_list arg;	if(pid >= 0)		postnote(PNPROC, pid, "die");	if(pgppid >= 0)		postnote(PNPROC, pgppid, "die");	va_start(arg, fmt);	vseprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	fprint(2, "%s: %s\n", argv0, buf);	holdoff(holding);	exits(buf);}voidmain(int argc, char **argv){	Attach *first, **l, *a;	char *subject, *type, *boundary;	int flags, fd;	Biobuf in, out, *b;	Addr *to;	Addr *cc;	String *file, *hdrstring;	int noinput, headersrv;	int ccargc;	char *ccargv[32];	noinput = 0;	subject = nil;	first = nil;	l = &first;	type = nil;	hdrstring = nil;	ccargc = 0;	quotefmtinstall();	fmtinstall('Z', doublequote);	fmtinstall('U', rfc2047fmt);	ARGBEGIN{	case 't':		type = ARGF();		if(type == nil)			usage();		break;	case 'a':		flags = 0;		goto aflag;	case 'A':		flags = 1;	aflag:		a = mkattach(ARGF(), type, flags);		if(a == nil)			exits("bad args");		type = nil;		*l = a;		l = &a->next;		break;	case 'C':		if(ccargc >= nelem(ccargv)-1)			sysfatal("too many cc's");		ccargv[ccargc] = ARGF();		if(ccargv[ccargc] == nil)			usage();		ccargc++;		break;	case 'R':		replymsg = ARGF();		break;	case 's':		subject = ARGF();		break;	case 'F':		Fflag = 1;		// file message		break;	case 'r':		rflag = 1;		// for sendmail		break;	case 'd':		dflag = 1;		// for sendmail		break;	case '#':		lbflag = 1;		// for sendmail		break;	case 'x':		xflag = 1;		// for sendmail		break;	case 'n':			// no standard input		nflag = 1;		break;	case '8':			// read recipients from rfc822 header		eightflag = 1;		break;	case 'p':			// pgp flag: encrypt, sign, or both		if(pgpopts(ARGF()) < 0)			sysfatal("bad pgp options");		break;	default:		usage();		break;	}ARGEND;	login = getlog();	user = getenv("upasname");	if(user == nil || *user == 0)		user = login;	if(user == nil || *user == 0)		sysfatal("can't read user name");	if(Binit(&in, 0, OREAD) < 0)		sysfatal("can't Binit 0: %r");	if(nflag && eightflag)		sysfatal("can't use both -n and -8");	if(eightflag && argc >= 1)		usage();	else if(!eightflag && argc < 1)		usage();	aliases = readaliases();	if(!eightflag){		to = expand(argc, argv);		cc = expand(ccargc, ccargv);	} else {		to = nil;		cc = nil;	}	flags = 0;	headersrv = Nomessage;	if(!nflag && !xflag && !lbflag &&!dflag) {		// pass through headers, keeping track of which we've seen,		// perhaps building to list.		holding = holdon();		headersrv = readheaders(&in, &flags, &hdrstring, eightflag ? &to : nil, 1);		if(rfc822syntaxerror){			Bdrain(&in);			fatal("rfc822 syntax error, message not sent");		}		if(to == nil){			Bdrain(&in);			fatal("no addresses found, message not sent");		}		switch(headersrv){		case Error:		// error			fatal("reading");			break;		case Nomessage:		// no message, just exit mimicking old behavior			noinput = 1;			if(first == nil)				exits(0);			break;		}	}	fd = sendmail(to, cc, &pid, Fflag ? argv[0] : nil);	if(fd < 0)		sysfatal("execing sendmail: %r\n:");	if(xflag || lbflag || dflag){		close(fd);		exits(waitforsubprocs());	}		if(Binit(&out, fd, OWRITE) < 0)		fatal("can't Binit 1: %r");	if(!nflag){		if(Bwrite(&out, s_to_c(hdrstring), s_len(hdrstring)) != s_len(hdrstring))			fatal("write error");		s_free(hdrstring);		hdrstring = nil;		// read user's standard headers		file = s_new();		mboxpath("headers", user, file, 0);		b = Bopen(s_to_c(file), OREAD);		if(b != nil){			switch(readheaders(b, &flags, &hdrstring, nil, 0)){			case Error:	// error				fatal("reading");			}			Bterm(b);			if(Bwrite(&out, s_to_c(hdrstring), s_len(hdrstring)) != s_len(hdrstring))				fatal("write error");			s_free(hdrstring);			hdrstring = nil;		}	}	// add any headers we need	if((flags & (1<<Hdate)) == 0)		if(printdate(&out) < 0)			fatal("writing");	if((flags & (1<<Hfrom)) == 0)		if(printfrom(&out) < 0)			fatal("writing");	if((flags & (1<<Hto)) == 0)		if(printto(&out, to) < 0)			fatal("writing");	if((flags & (1<<Hcc)) == 0)		if(printcc(&out, cc) < 0)			fatal("writing");	if((flags & (1<<Hsubject)) == 0 && subject != nil)		if(printsubject(&out, subject) < 0)			fatal("writing");	if(replymsg != nil)		if(printinreplyto(&out, replymsg) < 0)			fatal("writing");	Bprint(&out, "MIME-Version: 1.0\n");	if(pgpflag){	// interpose pgp process between us and sendmail to handle body		Bflush(&out);		Bterm(&out);		fd = pgpfilter(&pgppid, fd, pgpflag);		if(Binit(&out, fd, OWRITE) < 0)			fatal("can't Binit 1: %r");	}	// if attachments, stick in multipart headers	boundary = nil;	if(first != nil){		boundary = mkboundary();		Bprint(&out, "Content-Type: multipart/mixed;\n");		Bprint(&out, "\tboundary=\"%s\"\n\n", boundary);		Bprint(&out, "This is a multi-part message in MIME format.\n");		Bprint(&out, "--%s\n", boundary);		Bprint(&out, "Content-Disposition: inline\n");	}	if(!nflag){		if(!noinput && headersrv == Ok){			body(&in, &out, 1);		}	} else		Bprint(&out, "\n");	holdoff(holding);	Bflush(&out);	for(a = first; a != nil; a = a->next){		if(lastchar != '\n')			Bprint(&out, "\n");		Bprint(&out, "--%s\n", boundary);		attachment(a, &out);	}	if(first != nil){		if(lastchar != '\n')			Bprint(&out, "\n");		Bprint(&out, "--%s--\n", boundary);	}	Bterm(&out);	close(fd);	exits(waitforsubprocs());}// evaluate pgp option stringintpgpopts(char *s){	if(s == nil || s[0] == '\0')		return -1;	while(*s){		switch(*s++){		case 's':  case 'S':			pgpflag |= PGPsign;			break;		case 'e': case 'E':			pgpflag |= PGPencrypt;			break;		default:			return -1;		}	}	return 0;}// read headers from stdin into a String, expanding local aliases,// keep track of which headers are there, which addresses we have// remove Bcc: line.intreadheaders(Biobuf *in, int *fp, String **sp, Addr **top, int strict){	Addr *to;	String *s, *sline;	char *p;	int i, seen, hdrtype;	s = s_new();	sline = nil;	to = nil;	hdrtype = -1;	seen = 0;	for(;;) {		if((p = Brdline(in, '\n')) != nil) {			seen = 1;			p[Blinelen(in)-1] = 0;			// coalesce multiline headers			if((*p == ' ' || *p == '\t') && sline){				s_append(sline, "\n");				s_append(sline, p);				p[Blinelen(in)-1] = '\n';				continue;			}		}		// process the current header, it's all been read		if(sline) {			assert(hdrtype != -1);			if(top){				switch(hdrtype){				case Hto:				case Hcc:				case Hbcc:					to = expandline(&sline, to);					break;				}			}			if(hdrtype == Hsubject){				s_append(s, mksubject(s_to_c(sline)));				s_append(s, "\n");			}else if(top==nil || hdrtype!=Hbcc){				s_append(s, s_to_c(sline));				s_append(s, "\n");			}			s_free(sline);			sline = nil;		}		if(p == nil)			break;		// if no :, it's not a header, seek back and break		if(strchr(p, ':') == nil){			p[Blinelen(in)-1] = '\n';			Bseek(in, -Blinelen(in), 1);			break;		}		sline = s_copy(p);		// classify the header.  If we don't recognize it, break.  This is		// to take care of user's that start messages with lines that contain		// ':'s but that aren't headers.  This is a bit hokey.  Since I decided		// to let users type headers, I need some way to distinguish.  Therefore,		// marshal tries to know all likely headers and will indeed screw up if		// the user types an unlikely one. -- presotto		hdrtype = -1;		for(i = 0; i < nelem(hdrs); i++){			if(cistrncmp(hdrs[i], p, strlen(hdrs[i])) == 0){				*fp |= 1<<i;				hdrtype = i;				break;			}		}		if(strict){			if(hdrtype == -1){				p[Blinelen(in)-1] = '\n';				Bseek(in, -Blinelen(in), 1);				break;			}		} else			hdrtype = 0;		p[Blinelen(in)-1] = '\n';	}	*sp = s;	if(top)		*top = to;	if(seen == 0){		if(Blinelen(in) == 0)			return Nomessage;		else			return Ok;	}	if(p == nil)		return Nobody;	return Ok;}// pass the body to sendmail, make sure body starts and ends with a newlinevoidbody(Biobuf *in, Biobuf *out, int docontenttype){	char *buf, *p;	int i, n, len;	n = 0;	len = 16*1024;	buf = emalloc(len);	// first char must be newline	i = Bgetc(in);	if(i > 0){		if(i != '\n')			buf[n++] = '\n';		buf[n++] = i;	} else {		buf[n++] = '\n';	}	// read into memory	if(docontenttype){		while(docontenttype){			if(n == len){				len += len>>2;				buf = realloc(buf, len);				if(buf == nil)					sysfatal("%r");			}			p = buf+n;			i = Bread(in, p, len - n);			if(i < 0)				fatal("input error2");			if(i == 0)				break;			n += i;			for(; i > 0; i--)				if((*p++ & 0x80) && docontenttype){					Bprint(out, "Content-Type: text/plain; charset=\"UTF-8\"\n");					Bprint(out, "Content-Transfer-Encoding: 8bit\n");					docontenttype = 0;					break;				}		}		if(docontenttype){			Bprint(out, "Content-Type: text/plain; charset=\"US-ASCII\"\n");			Bprint(out, "Content-Transfer-Encoding: 7bit\n");		}	}	// write what we already read	if(Bwrite(out, buf, n) < 0)		fatal("output error");	if(n > 0)		lastchar = buf[n-1];	else		lastchar = '\n';	// pass the rest	for(;;){		n = Bread(in, buf, len);		if(n < 0)			fatal("input error2");		if(n == 0)			break;		if(Bwrite(out, buf, n) < 0)			fatal("output error");		lastchar = buf[n-1];	}}// pass the body to sendmail encoding with base64////  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.//voidbody64(Biobuf *in, Biobuf *out){	uchar buf[3*18*54];	char obuf[3*18*54*2];	int m, n;	Bprint(out, "\n");	for(;;){		n = Bread(in, buf, sizeof(buf));		if(n < 0)

⌨️ 快捷键说明

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