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

📄 nntpfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Network news transport protocol (NNTP) file server. * * Unfortunately, the file system differs from that expected * by Charles Forsyth's rin news reader.  This is partially out * of my own laziness, but it makes the bookkeeping here * a lot easier. */#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h>typedef struct Netbuf Netbuf;typedef struct Group Group;struct Netbuf {	Biobuf br;	Biobuf bw;	int lineno;	int fd;	int code;			/* last response code */	int auth;			/* Authorization required? */	char response[128];	/* last response */	Group *currentgroup;	char *addr;	char *user;	char *pass;	ulong extended;	/* supported extensions */};struct Group {	char *name;	Group *parent;	Group **kid;	int num;	int nkid;	int lo, hi;	int canpost;	int isgroup;	/* might just be piece of hierarchy */	ulong mtime;	ulong atime;};/* * First eight fields are, in order:  *	article number, subject, author, date, message-ID,  *	references, byte count, line count  * We don't support OVERVIEW.FMT; when I see a server with more * interesting fields, I'll implement support then.  In the meantime, * the standard defines the first eight fields. *//* Extensions */enum {	Nxover   = (1<<0),	Nxhdr    = (1<<1),	Nxpat    = (1<<2),	Nxlistgp = (1<<3),};Group *root;Netbuf *net;ulong now;int netdebug;int readonly;void*erealloc(void *v, ulong n){	v = realloc(v, n);	if(v == nil)		sysfatal("out of memory reallocating %lud", n);	setmalloctag(v, getcallerpc(&v));	return v;}void*emalloc(ulong n){	void *v;	v = malloc(n);	if(v == nil)		sysfatal("out of memory allocating %lud", n);	memset(v, 0, n);	setmalloctag(v, getcallerpc(&n));	return v;}char*estrdup(char *s){	int l;	char *t;	if (s == nil)		return nil;	l = strlen(s)+1;	t = emalloc(l);	memcpy(t, s, l);	setmalloctag(t, getcallerpc(&s));	return t;}char*estrdupn(char *s, int n){	int l;	char *t;	l = strlen(s);	if(l > n)		l = n;	t = emalloc(l+1);	memmove(t, s, l);	t[l] = '\0';	setmalloctag(t, getcallerpc(&s));	return t;}char*Nrdline(Netbuf *n){	char *p;	int l;	n->lineno++;	Bflush(&n->bw);	if((p = Brdline(&n->br, '\n')) == nil){		werrstr("nntp eof");		return nil;	}	p[l=Blinelen(&n->br)-1] = '\0';	if(l > 0 && p[l-1] == '\r')		p[l-1] = '\0';if(netdebug)	fprint(2, "-> %s\n", p);	return p;}intnntpresponse(Netbuf *n, int e, char *cmd){	int r;	char *p;	for(;;){		p = Nrdline(n);		if(p==nil){			strcpy(n->response, "early nntp eof");			return -1;		}		r = atoi(p);		if(r/100 == 1){	/* BUG? */			fprint(2, "%s\n", p);			continue;		}		break;	}	strecpy(n->response, n->response+sizeof(n->response), p);	if((r=atoi(p)) == 0){		close(n->fd);		n->fd = -1;		fprint(2, "bad nntp response: %s\n", p);		werrstr("bad nntp response");		return -1;	}	n->code = r;	if(0 < e && e<10 && r/100 != e){		fprint(2, "%s: expected %dxx: got %s\n", cmd, e, n->response);		return -1;	}	if(10 <= e && e<100 && r/10 != e){		fprint(2, "%s: expected %dx: got %s\n", cmd, e, n->response);		return -1;	}	if(100 <= e && r != e){		fprint(2, "%s: expected %d: got %s\n", cmd, e, n->response);		return -1;	}	return r;}int nntpauth(Netbuf*);int nntpxcmdprobe(Netbuf*);int nntpcurrentgroup(Netbuf*, Group*);/* XXX: bug OVER/XOVER et al. */static struct {	ulong n;	char *s;} extensions [] = {	{ Nxover, "OVER" },	{ Nxhdr, "HDR" },	{ Nxpat, "PAT" },	{ Nxlistgp, "LISTGROUP" },	{ 0, nil }};static int indial;intnntpconnect(Netbuf *n){	n->currentgroup = nil;	close(n->fd);	if((n->fd = dial(n->addr, nil, nil, nil)) < 0){			snprint(n->response, sizeof n->response, "dial: %r");		return -1;	}	Binit(&n->br, n->fd, OREAD);	Binit(&n->bw, n->fd, OWRITE);	if(nntpresponse(n, 20, "greeting") < 0)		return -1;	readonly = (n->code == 201);	indial = 1;	if(n->auth != 0)		nntpauth(n);//	nntpxcmdprobe(n);	indial = 0;	return 0;}intnntpcmd(Netbuf *n, char *cmd, int e){	int tried;	tried = 0;	for(;;){		if(netdebug)			fprint(2, "<- %s\n", cmd);		Bprint(&n->bw, "%s\r\n", cmd);		if(nntpresponse(n, e, cmd)>=0 && (e < 0 || n->code/100 != 5))			return 0;		/* redial */		if(indial || tried++ || nntpconnect(n) < 0)			return -1;	}}intnntpauth(Netbuf *n){	char cmd[256];	snprint(cmd, sizeof cmd, "AUTHINFO USER %s", n->user);	if (nntpcmd(n, cmd, -1) < 0 || n->code != 381) {		fprint(2, "Authentication failed: %s\n", n->response);		return -1;	}	snprint(cmd, sizeof cmd, "AUTHINFO PASS %s", n->pass);	if (nntpcmd(n, cmd, -1) < 0 || n->code != 281) {		fprint(2, "Authentication failed: %s\n", n->response);		return -1;	}	return 0;}intnntpxcmdprobe(Netbuf *n){	int i;	char *p;	n->extended = 0;	if (nntpcmd(n, "LIST EXTENSIONS", 0) < 0 || n->code != 202)		return 0;	while((p = Nrdline(n)) != nil) {		if (strcmp(p, ".") == 0)			break;		for(i=0; extensions[i].s != nil; i++)			if (cistrcmp(extensions[i].s, p) == 0) {				n->extended |= extensions[i].n;				break;			}	}	return 0;}/* XXX: searching, lazy evaluation */static intovercmp(void *v1, void *v2){	int a, b;	a = atoi(*(char**)v1);	b = atoi(*(char**)v2);	if(a < b)		return -1;	else if(a > b)		return 1;	return 0;}enum {	XoverChunk = 100,};char *xover[XoverChunk];int xoverlo;int xoverhi;int xovercount;Group *xovergroup;char*nntpover(Netbuf *n, Group *g, int m){	int i, lo, hi, mid, msg;	char *p;	char cmd[64];	if (g->isgroup == 0)	/* BUG: should check extension capabilities */		return nil;	if(g != xovergroup || m < xoverlo || m >= xoverhi){		lo = (m/XoverChunk)*XoverChunk;		hi = lo+XoverChunk;			if(lo < g->lo)			lo = g->lo;		else if (lo > g->hi)			lo = g->hi;		if(hi < lo || hi > g->hi)			hi = g->hi;			if(nntpcurrentgroup(n, g) < 0)			return nil;			if(lo == hi)			snprint(cmd, sizeof cmd, "XOVER %d", hi);		else			snprint(cmd, sizeof cmd, "XOVER %d-%d", lo, hi-1);		if(nntpcmd(n, cmd, 224) < 0)			return nil;		for(i=0; (p = Nrdline(n)) != nil; i++) {			if(strcmp(p, ".") == 0)				break;			if(i >= XoverChunk)				sysfatal("news server doesn't play by the rules");			free(xover[i]);			xover[i] = emalloc(strlen(p)+2);			strcpy(xover[i], p);			strcat(xover[i], "\n");		}		qsort(xover, i, sizeof(xover[0]), overcmp);		xovercount = i;		xovergroup = g;		xoverlo = lo;		xoverhi = hi;	}	lo = 0;	hi = xovercount;	/* search for message */	while(lo < hi){		mid = (lo+hi)/2;		msg = atoi(xover[mid]);		if(m == msg)			return xover[mid];		else if(m < msg)			hi = mid;		else			lo = mid+1;	}	return nil;}/* * Return the new Group structure for the group name. * Destroys name. */static int printgroup(char*,Group*);Group*findgroup(Group *g, char *name, int mk){	int lo, hi, m;	char *p, *q;	static int ngroup;	for(p=name; *p; p=q){		if(q = strchr(p, '.'))			*q++ = '\0';		else			q = p+strlen(p);		lo = 0;		hi = g->nkid;		while(hi-lo > 1){			m = (lo+hi)/2;			if(strcmp(p, g->kid[m]->name) < 0)				hi = m;			else				lo = m;		}		assert(lo==hi || lo==hi-1);		if(lo==hi || strcmp(p, g->kid[lo]->name) != 0){			if(mk==0)				return nil;			if(g->nkid%16 == 0)				g->kid = erealloc(g->kid, (g->nkid+16)*sizeof(g->kid[0]));			/* 			 * if we're down to a single place 'twixt lo and hi, the insertion might need			 * to go at lo or at hi.  strcmp to find out.  the list needs to stay sorted.		 	 */			if(lo==hi-1 && strcmp(p, g->kid[lo]->name) < 0)				hi = lo;			if(hi < g->nkid)				memmove(g->kid+hi+1, g->kid+hi, sizeof(g->kid[0])*(g->nkid-hi));			g->nkid++;			g->kid[hi] = emalloc(sizeof(*g));			g->kid[hi]->parent = g;			g = g->kid[hi];			g->name = estrdup(p);			g->num = ++ngroup;			g->mtime = time(0);		}else			g = g->kid[lo];	}	if(mk)		g->isgroup = 1;	return g;}static intprintgroup(char *s, Group *g){	if(g->parent == g)		return 0;	if(printgroup(s, g->parent))		strcat(s, ".");	strcat(s, g->name);	return 1;}static char*Nreaddata(Netbuf *n){	char *p, *q;	int l;	p = nil;	l = 0;	for(;;){		q = Nrdline(n);		if(q==nil){			free(p);			return nil;		}		if(strcmp(q, ".")==0)			return p;		if(q[0]=='.')			q++;		p = erealloc(p, l+strlen(q)+1+1);		strcpy(p+l, q);		strcat(p+l, "\n");		l += strlen(p+l);	}}/* * Return the output of a HEAD, BODY, or ARTICLE command. */char*nntpget(Netbuf *n, Group *g, int msg, char *retr){	char *s;	char cmd[1024];	if(g->isgroup == 0){		werrstr("not a group");		return nil;	}	if(strcmp(retr, "XOVER") == 0){		s = nntpover(n, g, msg);		if(s == nil)			s = "";		return estrdup(s);	}	if(nntpcurrentgroup(n, g) < 0)		return nil;	sprint(cmd, "%s %d", retr, msg);	nntpcmd(n, cmd, 0);	if(n->code/10 != 22)		return nil;	return Nreaddata(n);}intnntpcurrentgroup(Netbuf *n, Group *g){	char cmd[1024];	if(n->currentgroup != g){		strcpy(cmd, "GROUP ");		printgroup(cmd, g);		if(nntpcmd(n, cmd, 21) < 0)			return -1;		n->currentgroup = g;	}	return 0;}voidnntprefreshall(Netbuf *n){	char *f[10], *p;	int hi, lo, nf;	Group *g;	if(nntpcmd(n, "LIST", 21) < 0)		return;	while(p = Nrdline(n)){		if(strcmp(p, ".")==0)			break;		nf = getfields(p, f, nelem(f), 1, "\t\r\n ");		if(nf != 4){			int i;			for(i=0; i<nf; i++)				fprint(2, "%s%s", i?" ":"", f[i]);			fprint(2, "\n");			fprint(2, "syntax error in group list, line %d", n->lineno);			return;		}		g = findgroup(root, f[0], 1);		hi = strtol(f[1], 0, 10)+1;

⌨️ 快捷键说明

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