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

📄 nedmail.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		p = seprint(buf, e, "%-64s %-6d ", typeid, m->len);	if(m->filename && *m->filename)		p = seprint(p, e, "(file,%s)", m->filename);	if(m->from && *m->from)		p = seprint(p, e, "(from,%s)", m->from);	if(m->subject && *m->subject)		seprint(p, e, "(subj,%s)", m->subject);	s_free(id);}char sstring[256];//	cmd := range cmd ' ' arg-list ; //	range := address//		| address ',' address//		| 'g' search ;//	address := msgno//		| search ;//	msgno := number//		| number '/' msgno ;//	search := '/' string '/'//		| '%' string '%' ;//Reprog*parsesearch(char **pp){	char *p, *np;	int c, n;	p = *pp;	c = *p++;	np = strchr(p, c);	if(np != nil){		*np++ = 0;		*pp = np;	} else {		n = strlen(p);		*pp = p + n;	}	if(*p == 0)		p = sstring;	else{		strncpy(sstring, p, sizeof(sstring));		sstring[sizeof(sstring)-1] = 0;	}	return regcomp(p);}char*parseaddr(char **pp, Message *first, Message *cur, Message *unspec, Message **mp){	int n;	Message *m;	char *p;	Reprog *prog;	int c, sign;	char buf[256];	*mp = nil;	p = *pp;	if(*p == '+'){		sign = 1;		p++;		*pp = p;	} else if(*p == '-'){		sign = -1;		p++;		*pp = p;	} else		sign = 0;	switch(*p){	default:		if(sign){			n = 1;			goto number;		}		*mp = unspec;		break;		case '0': case '1': case '2': case '3': case '4':	case '5': case '6': case '7': case '8': case '9':		n = strtoul(p, pp, 10);		if(n == 0){			if(sign)				*mp = cur;			else				*mp = &top;			break;		}	number:		m = nil;		switch(sign){		case 0:			for(m = first; m != nil; m = m->next)				if(m->id == n)					break;			break;		case -1:			if(cur != &top)				for(m = cur; m != nil && n > 0; n--)					m = m->prev;			break;		case 1:			if(cur == &top){				n--;				cur = first;			}			for(m = cur; m != nil && n > 0; n--)				m = m->next;			break;		}		if(m == nil)			return "address";		*mp = m;		break;	case '%':	case '/':	case '?':		c = *p;		prog = parsesearch(pp);		if(prog == nil)			return "badly formed regular expression";		m = nil;		switch(c){		case '%':			for(m = cur == &top ? first : cur->next; m != nil; m = m->next){				if(rawsearch(m, prog))					break;			}			break;		case '/':			for(m = cur == &top ? first : cur->next; m != nil; m = m->next){				snprintheader(buf, sizeof(buf), m);				if(regexec(prog, buf, nil, 0))					break;			}			break;		case '?':			for(m = cur == &top ? nil : cur->prev; m != nil; m = m->prev){				snprintheader(buf, sizeof(buf), m);				if(regexec(prog, buf, nil, 0))					break;			}			break;		}		if(m == nil)			return "search";		*mp = m;		free(prog);		break;	case '$':		for(m = first; m != nil && m->next != nil; m = m->next)			;		*mp = m;		*pp = p+1;		break;	case '.':		*mp = cur;		*pp = p+1;		break;	case ',':		*mp = first;		*pp = p;		break;	}	if(*mp != nil && **pp == '.'){		(*pp)++;		if((*mp)->child == nil)			return "no sub parts";		return parseaddr(pp, (*mp)->child, (*mp)->child, (*mp)->child, mp);	}	if(**pp == '+' || **pp == '-' || **pp == '/' || **pp == '%')		return parseaddr(pp, first, *mp, *mp, mp);	return nil;}////  search a message for a regular expression match//intrawsearch(Message *m, Reprog *prog){	char buf[4096+1];	int i, fd, rv;	String *path;	path = extendpath(m->path, "raw");	fd = open(s_to_c(path), OREAD);	if(fd < 0)		return 0;	// march through raw message 4096 bytes at a time	// with a 128 byte overlap to chain the re search.	rv = 0;	for(;;){		i = read(fd, buf, sizeof(buf)-1);		if(i <= 0)			break;		buf[i] = 0;		if(regexec(prog, buf, nil, 0)){			rv = 1;			break;		}		if(i < sizeof(buf)-1)			break;		if(seek(fd, -128LL, 1) < 0)			break;	}	close(fd);	s_free(path);	return rv;}char*parsecmd(char *p, Cmd *cmd, Message *first, Message *cur){	Reprog *prog;	Message *m, *s, *e, **l, *last;	char buf[256];	char *err;	int i, c;	char *q;	static char errbuf[Errlen];	cmd->delete = 0;	l = &cmd->msgs;	*l = nil;	// eat white space	while(*p == ' ')		p++;	// null command is a special case (advance and print)	if(*p == 0){		if(cur == &top){			// special case			m = first;		} else {			// walk to the next message even if we have to go up			m = cur->next;			while(m == nil && cur->parent != nil){				cur = cur->parent;				m = cur->next;			}		}		if(m == nil)			return "address";		*l = m;		m->cmd = nil;		cmd->an = 0;		cmd->f = pcmd;		return nil;	}	// global search ?	if(*p == 'g'){		p++;		// no search string means all messages		if(*p != '/' && *p != '%'){			for(m = first; m != nil; m = m->next){				*l = m;				l = &m->cmd;				*l = nil;			}		} else {			// mark all messages matching this search string			c = *p;			prog = parsesearch(&p);			if(prog == nil)				return "badly formed regular expression";			if(c == '%'){				for(m = first; m != nil; m = m->next){					if(rawsearch(m, prog)){						*l = m;						l = &m->cmd;						*l = nil;					}				}			} else {				for(m = first; m != nil; m = m->next){					snprintheader(buf, sizeof(buf), m);					if(regexec(prog, buf, nil, 0)){						*l = m;						l = &m->cmd;						*l = nil;					}				}			}			free(prog);		}	} else {			// parse an address		s = e = nil;		err = parseaddr(&p, first, cur, cur, &s);		if(err != nil)			return err;		if(*p == ','){			// this is an address range			if(s == &top)				s = first;			p++;			for(last = s; last != nil && last->next != nil; last = last->next)				;			err = parseaddr(&p, first, cur, last, &e);			if(err != nil)				return err;				// select all messages in the range			for(; s != nil; s = s->next){				*l = s;				l = &s->cmd;				*l = nil;				if(s == e)					break;			}			if(s == nil)				return "null address range";		} else {			// single address			if(s != &top){				*l = s;				s->cmd = nil;			}		}	}	// insert a space after '!'s and '|'s	for(q = p; *q; q++)		if(*q != '!' && *q != '|')			break;	if(q != p && *q != ' '){		memmove(q+1, q, strlen(q)+1);		*q = ' ';	}	cmd->an = getfields(p, cmd->av, nelem(cmd->av) - 1, 1, " \t\r\n");	if(cmd->an == 0 || *cmd->av[0] == 0)		cmd->f = pcmd;	else {		// hack to allow all messages to start with 'd'		if(*(cmd->av[0]) == 'd' && *(cmd->av[0]+1) != 0){			cmd->delete = 1;			cmd->av[0]++;		}		// search command table		for(i = 0; cmdtab[i].cmd != nil; i++)			if(strcmp(cmd->av[0], cmdtab[i].cmd) == 0)				break;		if(cmdtab[i].cmd == nil)			return "illegal command";		if(cmdtab[i].args == 0 && cmd->an > 1){			snprint(errbuf, sizeof(errbuf), "%s doesn't take an argument", cmdtab[i].cmd);			return errbuf;		}		cmd->f = cmdtab[i].f;	}	return nil; }// inefficient read from standard inputchar*readline(char *prompt, char *line, int len){	char *p, *e;	int n;retry:	interrupted = 0;	Bprint(&out, "%s", prompt);	Bflush(&out);	e = line + len;	for(p = line; p < e; p++){		n = read(0, p, 1);		if(n < 0){			if(interrupted)				goto retry;			return nil;		}		if(n == 0)			return nil;		if(*p == '\n')			break;	}	*p = 0;	return line;}voidmessagecount(Message *m){	int i;	i = 0;	for(; m != nil; m = m->next)		i++;	Bprint(&out, "%d message%s\n", i, plural(i));}Message*aichcmd(Message *m, int indent){	char	hdr[256];	if(m == &top)		return nil;	snprintHeader(hdr, sizeof(hdr), indent, m);	Bprint(&out, "%s\n", hdr);	for(m = m->child; m != nil; m = m->next)		aichcmd(m, indent+1);	return nil;}Message*Hcmd(Cmd*, Message *m){	if(m == &top)		return nil;	aichcmd(m, 0);	return nil;}Message*hcmd(Cmd*, Message *m){	char	hdr[256];	if(m == &top)		return nil;	snprintheader(hdr, sizeof(hdr), m);	Bprint(&out, "%s\n", hdr);	return nil;}Message*bcmd(Cmd*, Message *m){	int i;	Message *om = m;	if(m == &top)		m = top.child;	for(i = 0; i < 10 && m != nil; i++){		hcmd(nil, m);		om = m;		m = m->next;	}	return om;}Message*ncmd(Cmd*, Message *m){	if(m == &top)		return m->child;	return m->next;}intprintpart(String *s, char *part){	char buf[4096];	int n, fd, tot;	String *path;	path = extendpath(s, part);	fd = open(s_to_c(path), OREAD);	s_free(path);	if(fd < 0){		fprint(2, "!message dissappeared\n");		return 0;	}	tot = 0;	while((n = read(fd, buf, sizeof(buf))) > 0){		if(interrupted)			break;		if(Bwrite(&out, buf, n) <= 0)			break;		tot += n;	}	close(fd);	return tot;}intprinthtml(Message *m){	Cmd c;	c.an = 3;	c.av[1] = "/bin/htmlfmt";	c.av[2] = "-l 40 -cutf-8";	Bprint(&out, "!%s\n", c.av[1]);	Bflush(&out);	pipecmd(&c, m);	return 0;}Message*Pcmd(Cmd*, Message *m){	if(m == &top)		return &top;	if(m->parent == &top)		printpart(m->path, "unixheader");	printpart(m->path, "raw");	return m;}voidcompress(char *p){	char *np;	int last;	last = ' ';	for(np = p; *p; p++){		if(*p != ' ' || last != ' '){			last = *p;			*np++ = last;		}	}	*np = 0;}Message*pcmd(Cmd*, Message *m){	Message *nm;	Ctype *cp;	String *s;	char buf[128];	if(m == &top)		return &top;	if(m->parent == &top)		printpart(m->path, "unixheader");	if(printpart(m->path, "header") > 0)		Bprint(&out, "\n");	cp = findctype(m);	if(cp->display){		if(strcmp(m->type, "text/html") == 0)			printhtml(m);		else			printpart(m->path, "body");	} else if(strcmp(m->type, "multipart/alternative") == 0){		for(nm = m->child; nm != nil; nm = nm->next){			cp = findctype(nm);			if(cp->ext != nil && strncmp(cp->ext, "txt", 3) == 0)				break;		}		if(nm == nil)			for(nm = m->child; nm != nil; nm = nm->next){				cp = findctype(nm);				if(cp->display)					break;			}		if(nm != nil)			pcmd(nil, nm);		else			hcmd(nil, m);	} else if(strncmp(m->type, "multipart/", 10) == 0){		nm = m->child;		if(nm != nil){			// always print first part			pcmd(nil, nm);			for(nm = nm->next; nm != nil; nm = nm->next){				s = rooted(s_clone(nm->path));				cp = findctype(nm);				snprintHeader(buf, sizeof buf, -1, nm);				compress(buf);				if(strcmp(nm->disposition, "inline") == 0){					if(cp->ext != nil)						Bprint(&out, "\n--- %s %s/body.%s\n\n",							buf, s_to_c(s), cp->ext);					else						Bprint(&out, "\n--- %s %s/body\n\n",							buf, s_to_c(s));					pcmd(nil, nm);				} else {					if(cp->ext != nil)						Bprint(&out, "\n!--- %s %s/body.%s\n",							buf, s_to_c(s), cp->ext);					else						Bprint(&out, "\n!--- %s %s/body\n",							buf, s_to_c(s));				}				s_free(s);			}		} else {			hcmd(nil, m);		}	} else if(strcmp(m->type, "message/rfc822") == 0){		pcmd(nil, m->child);	} else if(plumb(m, cp) >= 0)		Bprint(&out, "\n!--- using plumber to display message of type %s\n", m->type);	else		Bprint(&out, "\n!--- cannot display messages of type %s\n", m->type);			return m;}voidprintpartindented(String *s, char *part, char *indent){	char *p;	String *path;	Biobuf *b;	path = extendpath(s, part);	b = Bopen(s_to_c(path), OREAD);	s_free(path);	if(b == nil){		fprint(2, "!message dissappeared\n");		return;	}	while((p = Brdline(b, '\n')) != nil){		if(interrupted)			break;		p[Blinelen(b)-1] = 0;		if(Bprint(&out, "%s%s\n", indent, p) < 0)			break;	}	Bprint(&out, "\n");	Bterm(b);}Message*quotecmd(Cmd*, Message *m){	Message *nm;	Ctype *cp;	if(m == &top)		return &top;	Bprint(&out, "\n");	if(m->from != nil && *m->from)		Bprint(&out, "On %s, %s wrote:\n", m->date, m->from);	cp = findctype(m);	if(cp->display){		printpartindented(m->path, "body", "> ");	} else if(strcmp(m->type, "multipart/alternative") == 0){		for(nm = m->child; nm != nil; nm = nm->next){			cp = findctype(nm);			if(cp->ext != nil && strncmp(cp->ext, "txt", 3) == 0)				break;		}		if(nm == nil)			for(nm = m->child; nm != nil; nm = nm->next){				cp = findctype(nm);				if(cp->display)					break;			}		if(nm != nil)			quotecmd(nil, nm);	} else if(strncmp(m->type, "multipart/", 10) == 0){		nm = m->child;		if(nm != nil){			cp = findctype(nm);			if(cp->display || strncmp(m->type, "multipart/", 10) == 0)				quotecmd(nil, nm);		}	}	return m;}// really delete messagesMessage*flushdeleted(Message *cur){	Message *m, **l;	char buf[1024], *p, *e, *msg;	int deld, n, fd;	int i;	doflush = 0;	deld = 0;	fd = open("/mail/fs/ctl", ORDWR);	if(fd < 0){		fprint(2, "!can't delete mail, opening /mail/fs/ctl: %r\n");		exitfs(0);	}	e = &buf[sizeof(buf)];	p = seprint(buf, e, "delete %s", mbname);	n = 0;	for(l = &top.child; *l != nil;){		m = *l;		if(!m->deleted){			l = &(*l)->next;			continue;		}		// don't return a pointer to a deleted message		if(m == cur)			cur = m->next;		deld++;		msg = strrchr(s_to_c(m->path), '/');		if(msg == nil)			msg = s_to_c(m->path);		else			msg++;		if(e-p < 10){			write(fd, buf, p-buf);			n = 0;			p = seprint(buf, e, "delete %s", mbname);		}		p = seprint(p, e, " %s", msg);		n++;		// unchain and free		*l = m->next;		if(m->next)			m->next->prev = m->prev;		freemessage(m);	}	if(n)		write(fd, buf, p-buf);	close(fd);	if(deld)		Bprint(&out, "!%d message%s deleted\n", deld, plural(deld));	// renumber	i = 1;	for(m = top.child; m != nil; m = m->next)		m->id = natural ? m->fileno : i++;	// if we're out of messages, go back to first	// if no first, return the fake first	if(cur == nil){		if(top.child)			return top.child;		else			return &top;	}	return cur;}Message*qcmd(Cmd*, Message*){	flushdeleted(nil);	if(didopen)		closemb();	Bflush(&out);	exitfs(0);	return nil;	// not reached}Message*ycmd(Cmd*, Message *m){	doflush = 1;	return icmd(nil, m);}Message*xcmd(Cmd*, Message*){	exitfs(0);	return nil;	// not reached}Message*eqcmd(Cmd*, Message *m){	if(m == &top)		Bprint(&out, "0\n");	else		Bprint(&out, "%d\n", m->id);	return nil;}Message*dcmd(Cmd*, Message *m){	if(m == &top){		Bprint(&out, "!address\n");		return nil;	}	while(m->parent != &top)		m = m->parent;	m->deleted = 1;	return m;}Message*ucmd(Cmd*, Message *m){	if(m == &top)		return nil;	while(m->parent != &top)		m = m->parent;	if(m->deleted < 0)		Bprint(&out, "!can't undelete, already flushed\n");	m->deleted = 0;	return m;}Message*icmd(Cmd*, Message *m){	int n;	n = dir2message(&top, reverse);	if(n > 0)		Bprint(&out, "%d new message%s\n", n, plural(n));	return m;}Message*

⌨️ 快捷键说明

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