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

📄 nedmail.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#include "common.h"#include <ctype.h>#include <plumb.h>typedef struct Message Message;typedef struct Ctype Ctype;typedef struct Cmd Cmd;char	root[Pathlen];char	mbname[Elemlen];int	rootlen;int	didopen;char	*user;char	wd[2048];String	*mbpath;int	natural;int	doflush;int interrupted;struct Message {	Message	*next;	Message	*prev;	Message	*cmd;	Message	*child;	Message	*parent;	String	*path;	int	id;	int	len;	int	fileno;	// number of directory	String	*info;	char	*from;	char	*to;	char	*cc;	char	*replyto;	char	*date;	char	*subject;	char	*type;	char	*disposition;	char	*filename;	char	deleted;	char	stored;};Message top;struct Ctype {	char	*type;	char 	*ext;	int	display;	char	*plumbdest;	Ctype	*next;};Ctype ctype[] = {	{ "text/plain",			"txt",	1,	0	},	{ "text/html",			"htm",	1,	0	},	{ "text/html",			"html",	1,	0	},	{ "text/tab-separated-values",	"tsv",	1,	0	},	{ "text/richtext",		"rtx",	1,	0	},	{ "text/rtf",			"rtf",	1,	0	},	{ "text",			"txt",	1,	0	},	{ "message/rfc822",		"msg",	0,	0	},	{ "image/bmp",			"bmp",	0,	"image"	},	{ "image/jpeg",			"jpg",	0,	"image"	},	{ "image/gif",			"gif",	0,	"image"	},	{ "image/png",			"png",	0,	"image"	},	{ "application/pdf",		"pdf",	0,	"postscript"	},	{ "application/postscript",	"ps",	0,	"postscript"	},	{ "application/",		0,	0,	0	},	{ "image/",			0,	0,	0	},	{ "multipart/",			"mul",	0,	0	},};Message*	acmd(Cmd*, Message*);Message*	bcmd(Cmd*, Message*);Message*	dcmd(Cmd*, Message*);Message*	eqcmd(Cmd*, Message*);Message*	hcmd(Cmd*, Message*);Message*	Hcmd(Cmd*, Message*);Message*	helpcmd(Cmd*, Message*);Message*	icmd(Cmd*, Message*);Message*	pcmd(Cmd*, Message*);Message*	qcmd(Cmd*, Message*);Message*	rcmd(Cmd*, Message*);Message*	scmd(Cmd*, Message*);Message*	ucmd(Cmd*, Message*);Message*	wcmd(Cmd*, Message*);Message*	xcmd(Cmd*, Message*);Message*	ycmd(Cmd*, Message*);Message*	pipecmd(Cmd*, Message*);Message*	rpipecmd(Cmd*, Message*);Message*	bangcmd(Cmd*, Message*);Message*	Pcmd(Cmd*, Message*);Message*	mcmd(Cmd*, Message*);Message*	fcmd(Cmd*, Message*);Message*	quotecmd(Cmd*, Message*);struct {	char		*cmd;	int		args;	Message*	(*f)(Cmd*, Message*);	char		*help;} cmdtab[] = {	{ "a",	1,	acmd,	"a        reply to sender and recipients" },	{ "A",	1,	acmd,	"A        reply to sender and recipients with copy" },	{ "b",	0,	bcmd,	"b        print the next 10 headers" },	{ "d",	0,	dcmd,	"d        mark for deletion" },	{ "f",	0,	fcmd,	"f        file message by from address" },	{ "h",	0,	hcmd,	"h        print elided message summary (,h for all)" },	{ "help", 0,	helpcmd, "help     print this info" },	{ "H",	0,	Hcmd,	"H        print message's MIME structure " },	{ "i",	0,	icmd,	"i        incorporate new mail" },	{ "m",	1,	mcmd,	"m addr   forward mail" },	{ "M",	1,	mcmd,	"M addr   forward mail with message" },	{ "p",	0,	pcmd,	"p        print the processed message" },	{ "P",	0,	Pcmd,	"P        print the raw message" },	{ "\"",	0,	quotecmd, "\"        print a quoted version of msg" },	{ "q",	0,	qcmd,	"q        exit and remove all deleted mail" },	{ "r",	1,	rcmd,	"r [addr] reply to sender plus any addrs specified" },	{ "rf",	1,	rcmd,	"rf [addr]file message and reply" },	{ "R",	1,	rcmd,	"R [addr] reply including copy of message" },	{ "Rf",	1,	rcmd,	"Rf [addr]file message and reply with copy" },	{ "s",	1,	scmd,	"s file   append raw message to file" },	{ "u",	0,	ucmd,	"u        remove deletion mark" },	{ "w",	1,	wcmd,	"w file   store message contents as file" },	{ "x",	0,	xcmd,	"x        exit without flushing deleted messages" },	{ "y",	0,	ycmd,	"y        synchronize with mail box" },	{ "=",	1,	eqcmd,	"=        print current message number" },	{ "|",	1,	pipecmd, "|cmd     pipe message body to a command" },	{ "||",	1,	rpipecmd, "||cmd     pipe raw message to a command" },	{ "!",	1,	bangcmd, "!cmd     run a command" },	{ nil,	0,	nil, 	nil },};enum{	NARG=	32,};struct Cmd {	Message	*msgs;	Message	*(*f)(Cmd*, Message*);	int	an;	char	*av[NARG];	int	delete;};Biobuf out;int startedfs;int reverse;int longestfrom = 12;String*		file2string(String*, char*);int		dir2message(Message*, int);int		filelen(String*, char*);String*		extendpath(String*, char*);void		snprintheader(char*, int, Message*);void		cracktime(char*, char*, int);int		cistrncmp(char*, char*, int);int		cistrcmp(char*, char*);Reprog*		parsesearch(char**);char*		parseaddr(char**, Message*, Message*, Message*, Message**);char*		parsecmd(char*, Cmd*, Message*, Message*);char*		readline(char*, char*, int);void		messagecount(Message*);void		system(char*, char**, int);void		mkid(String*, Message*);int		switchmb(char*, char*);void		closemb(void);int		lineize(char*, char**, int);int		rawsearch(Message*, Reprog*);Message*	dosingleton(Message*, char*);String*		rooted(String*);int		plumb(Message*, Ctype*);String*		addrecolon(char*);void		exitfs(char*);Message*	flushdeleted(Message*);voidusage(void){	fprint(2, "usage: %s [-nr] [-f mailfile] [-s mailfile]\n", argv0);	fprint(2, "       %s -c dir\n", argv0);	exits("usage");}voidcatchnote(void*, char *note){	if(strstr(note, "interrupt") != nil){		interrupted = 1;		noted(NCONT);	}	noted(NDFLT);}char *plural(int n){	if (n == 1)		return "";	return "s";		}voidmain(int argc, char **argv){	Message *cur, *m, *x;	char cmdline[4*1024];	Cmd cmd;	Ctype *cp;	char *err;	int n, cflag;	char *av[4];	String *prompt;	char *file, *singleton;	Binit(&out, 1, OWRITE);	file = nil;	singleton = nil;	reverse = 1;	cflag = 0;	ARGBEGIN {	case 'c':		cflag = 1;		break;	case 'f':		file = EARGF(usage());		break;	case 's':		singleton = EARGF(usage());		break;	case 'r':		reverse = 0;		break;	case 'n':		natural = 1;		reverse = 0;		break;	default:		usage();		break;	} ARGEND;	user = getlog();	if(user == nil || *user == 0)		sysfatal("can't read user name");	if(cflag){		if(argc > 0)			creatembox(user, argv[0]);		else			creatembox(user, nil);		exits(0);	}	if(argc)		usage();	if(access("/mail/fs/ctl", 0) < 0){		startedfs = 1;		av[0] = "fs";		av[1] = "-p";		av[2] = 0;		system("/bin/upas/fs", av, -1);	}	switchmb(file, singleton);	top.path = s_copy(root);	for(cp = ctype; cp < ctype+nelem(ctype)-1; cp++)		cp->next = cp+1;	if(singleton != nil){		cur = dosingleton(&top, singleton);		if(cur == nil){			Bprint(&out, "no message\n");			exitfs(0);		}		pcmd(nil, cur);	} else {		cur = &top;		n = dir2message(&top, reverse);		if(n < 0)			sysfatal("can't read %s", s_to_c(top.path));		Bprint(&out, "%d message%s\n", n, plural(n));	}	notify(catchnote);	prompt = s_new();	for(;;){		s_reset(prompt);		if(cur == &top)			s_append(prompt, ": ");		else {			mkid(prompt, cur);			s_append(prompt, ": ");		}		// leave space at the end of cmd line in case parsecmd needs to		// add a space after a '|' or '!'		if(readline(s_to_c(prompt), cmdline, sizeof(cmdline)-1) == nil)			break;		err = parsecmd(cmdline, &cmd, top.child, cur);		if(err != nil){			Bprint(&out, "!%s\n", err);			continue;		}		if(singleton != nil && cmd.f == icmd){			Bprint(&out, "!illegal command\n");			continue;		}		interrupted = 0;		if(cmd.msgs == nil || cmd.msgs == &top){			x = (*cmd.f)(&cmd, &top);			if(x != nil)				cur = x;		} else for(m = cmd.msgs; m != nil; m = m->cmd){			x = m;			if(cmd.delete){				dcmd(&cmd, x);				// dp acts differently than all other commands				// since its an old lesk idiom that people love.				// it deletes the current message, moves the current				// pointer ahead one and prints.				if(cmd.f == pcmd){					if(x->next == nil){						Bprint(&out, "!address\n");						cur = x;						break;					} else						x = x->next;				}			}			x = (*cmd.f)(&cmd, x);			if(x != nil)				cur = x;			if(interrupted)				break;			if(singleton != nil && (cmd.delete || cmd.f == dcmd))				qcmd(nil, nil);		}		if(doflush)			cur = flushdeleted(cur);	}	qcmd(nil, nil);}//// read the message info//Message*file2message(Message *parent, char *name){	Message *m;	String *path;	char *f[10];	m = mallocz(sizeof(Message), 1);	if(m == nil)		return nil;	m->path = path = extendpath(parent->path, name);	m->fileno = atoi(name);	m->info = file2string(path, "info");	lineize(s_to_c(m->info), f, nelem(f));	m->from = f[0];	m->to = f[1];	m->cc = f[2];	m->replyto = f[3];	m->date = f[4];	m->subject = f[5];	m->type = f[6];	m->disposition = f[7];	m->filename = f[8];	m->len = filelen(path, "raw");	if(strstr(m->type, "multipart") != nil || strcmp(m->type, "message/rfc822") == 0)		dir2message(m, 0);	m->parent = parent;	return m;}voidfreemessage(Message *m){	Message *nm, *next;	for(nm = m->child; nm != nil; nm = next){		next = nm->next;		freemessage(nm);	}	s_free(m->path);	s_free(m->info);	free(m);}////  read a directory into a list of messages//intdir2message(Message *parent, int reverse){	int i, n, fd, highest, newmsgs;	Dir *d;	Message *first, *last, *m;	fd = open(s_to_c(parent->path), OREAD);	if(fd < 0)		return -1;	// count current entries	first = parent->child;	highest = newmsgs = 0;	for(last = parent->child; last != nil && last->next != nil; last = last->next)		if(last->fileno > highest)			highest = last->fileno;	if(last != nil)		if(last->fileno > highest)			highest = last->fileno;	n = dirreadall(fd, &d);	for(i = 0; i < n; i++){		if((d[i].qid.type & QTDIR) == 0)			continue;		if(atoi(d[i].name) <= highest)			continue;		m = file2message(parent, d[i].name);		if(m == nil)			break;		newmsgs++;		if(reverse){			m->next = first;			if(first != nil)				first->prev = m;			first = m;		} else {			if(first == nil)				first = m;			else				last->next = m;			m->prev = last;			last = m;		}	}	free(d);	close(fd);	parent->child = first;	// renumber and file longest from	i = 1;	longestfrom = 12;	for(m = first; m != nil; m = m->next){		m->id = natural ? m->fileno : i++;		n = strlen(m->from);		if(n > longestfrom)			longestfrom = n;	}	return newmsgs;}////  point directly to a message//Message*dosingleton(Message *parent, char *path){	char *p, *np;	Message *m;	// walk down to message and read it	if(strlen(path) < rootlen)		return nil;	if(path[rootlen] != '/')		return nil;	p = path+rootlen+1;	np = strchr(p, '/');	if(np != nil)		*np = 0;	m = file2message(parent, p);	if(m == nil)		return nil;	parent->child = m;	m->id = 1;	// walk down to requested component	while(np != nil){		*np = '/';		np = strchr(np+1, '/');		if(np != nil)			*np = 0;		for(m = m->child; m != nil; m = m->next)			if(strcmp(path, s_to_c(m->path)) == 0)				return m;		if(m == nil)			return nil;	}	return m;}////  read a file into a string//String*file2string(String *dir, char *file){	String *s;	int fd, n, m;	s = extendpath(dir, file);	fd = open(s_to_c(s), OREAD);	s_grow(s, 512);			/* avoid multiple reads on info files */	s_reset(s);	if(fd < 0)		return s;	for(;;){		n = s->end - s->ptr;		if(n == 0){			s_grow(s, 128);			continue;		}		m = read(fd, s->ptr, n);		if(m <= 0)			break;		s->ptr += m;		if(m < n)			break;	}	s_terminate(s);	close(fd);	return s;}////  get the length of a file//intfilelen(String *dir, char *file){	String *path;	Dir *d;	int rv;	path = extendpath(dir, file);	d = dirstat(s_to_c(path));	if(d == nil){		s_free(path);		return -1;	}	s_free(path);	rv = d->length;	free(d);	return rv;}////  walk the path name an element//String*extendpath(String *dir, char *name){	String *path;	if(strcmp(s_to_c(dir), ".") == 0)		path = s_new();	else {		path = s_copy(s_to_c(dir));		s_append(path, "/");	}	s_append(path, name);	return path;}intcistrncmp(char *a, char *b, int n){	while(n-- > 0){		if(tolower(*a++) != tolower(*b++))			return -1;	}	return 0;}intcistrcmp(char *a, char *b){	for(;;){		if(tolower(*a) != tolower(*b++))			return -1;		if(*a++ == 0)			break;	}	return 0;}char*nosecs(char *t){	char *p;	p = strchr(t, ':');	if(p == nil)		return t;	p = strchr(p+1, ':');	if(p != nil)		*p = 0;	return t;}char *months[12] ={	"jan", "feb", "mar", "apr", "may", "jun",	"jul", "aug", "sep", "oct", "nov", "dec"};intmonth(char *m){	int i;	for(i = 0; i < 12; i++)		if(cistrcmp(m, months[i]) == 0)			return i+1;	return 1;}enum{	Yearsecs= 365*24*60*60};voidcracktime(char *d, char *out, int len){	char in[64];	char *f[6];	int n;	Tm tm;	long now, then;	char *dtime;	*out = 0;	if(d == nil)		return;	strncpy(in, d, sizeof(in));	in[sizeof(in)-1] = 0;	n = getfields(in, f, 6, 1, " \t\r\n");	if(n != 6){		// unknown style		snprint(out, 16, "%10.10s", d);		return;	}	now = time(0);	memset(&tm, 0, sizeof tm);	if(strchr(f[0], ',') != nil && strchr(f[4], ':') != nil){		// 822 style		tm.year = atoi(f[3])-1900;		tm.mon = month(f[2]);		tm.mday = atoi(f[1]);		dtime = nosecs(f[4]);		then = tm2sec(&tm);	} else if(strchr(f[3], ':') != nil){		// unix style		tm.year = atoi(f[5])-1900;		tm.mon = month(f[1]);		tm.mday = atoi(f[2]);		dtime = nosecs(f[3]);		then = tm2sec(&tm);	} else {		then = now;		tm = *localtime(now);		dtime = "";	}	if(now - then < Yearsecs/2)		snprint(out, len, "%2d/%2.2d %s", tm.mon, tm.mday, dtime);	else		snprint(out, len, "%2d/%2.2d  %4d", tm.mon, tm.mday, tm.year+1900);}Ctype*findctype(Message *m){	char *p;	char ftype[128];	int n, pfd[2];	Ctype *a, *cp;	static Ctype nulltype	= { "", 0, 0, 0 };	static Ctype bintype 	= { "application/octet-stream", "bin", 0, 0 };	for(cp = ctype; cp; cp = cp->next)		if(strncmp(cp->type, m->type, strlen(cp->type)) == 0)			return cp;/*	use file(1) for any unknown mimetypes * *	if (strcmp(m->type, bintype.type) != 0) *		return &nulltype; */	if(pipe(pfd) < 0)		return &bintype;	*ftype = 0;	switch(fork()){	case -1:		break;	case 0:		close(pfd[1]);		close(0);		dup(pfd[0], 0);		close(1);		dup(pfd[0], 1);		execl("/bin/file", "file", "-m", s_to_c(extendpath(m->path, "body")), nil);		exits(0);	default:		close(pfd[0]);		n = read(pfd[1], ftype, sizeof(ftype));		if(n > 0)			ftype[n] = 0;		close(pfd[1]);		waitpid();		break;	}	if (*ftype=='\0' || (p = strchr(ftype, '/')) == nil)		return &bintype;	*p++ = 0;	a = mallocz(sizeof(Ctype), 1);	a->type = strdup(ftype);	a->ext = strdup(p);	a->display = 0;	a->plumbdest = strdup(ftype);	for(cp = ctype; cp->next; cp = cp->next)		continue;	cp->next = a;	a->next = nil;	return a;}voidmkid(String *s, Message *m){	char buf[32];	if(m->parent != &top){		mkid(s, m->parent);		s_append(s, ".");	}	sprint(buf, "%d", m->id);	s_append(s, buf);}voidsnprintheader(char *buf, int len, Message *m){	char timebuf[32];	String *id;	char *p, *q;;	// create id	id = s_new();	mkid(id, m);	if(*m->from == 0){		// no from		snprint(buf, len, "%-3s    %s %6d  %s",			s_to_c(id),			m->type,			m->len,			m->filename);	} else if(*m->subject){		q = p = strdup(m->subject);		while(*p == ' ')			p++;		if(strlen(p) > 50)			p[50] = 0;		cracktime(m->date, timebuf, sizeof(timebuf));		snprint(buf, len, "%-3s %c%c%c %6d  %11.11s %-*.*s %s",			s_to_c(id),			m->child ? 'H' : ' ',			m->deleted ? 'd' : ' ',			m->stored ? 's' : ' ',			m->len,			timebuf,			longestfrom, longestfrom, m->from,			p);		free(q);	} else {		cracktime(m->date, timebuf, sizeof(timebuf));		snprint(buf, len, "%-3s %c%c%c %6d  %11.11s %s",			s_to_c(id),			m->child ? 'H' : ' ',			m->deleted ? 'd' : ' ',			m->stored ? 's' : ' ',			m->len,			timebuf,			m->from);	}	s_free(id);}char *spaces = "                                                                    ";voidsnprintHeader(char *buf, int len, int indent, Message *m){	String *id;	char typeid[64];	char *p, *e;	// create id	id = s_new();	mkid(id, m);	e = buf + len;	snprint(typeid, sizeof typeid, "%s    %s", s_to_c(id), m->type);	if(indent < 6)		p = seprint(buf, e, "%-32s %-6d ", typeid, m->len);	else

⌨️ 快捷键说明

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