henesyinit from lsubb0c8bdb6 years agoHistory
855 lines · 15.9 KB · C
RawDownload
/* * Web discussion groups. * The group is identified by an argument. * Each group is kept as a flat directory. * There we keep a file per article. * Each file is made of a series of sections. * The first section is considered the article * The following ones are the replies. * The Id determines to which post they are replying. * Number | Id.Number * title * Author * body lines... * \a (ascii 07 / bell) */  #include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h>#include "httpd.h"#include "httpsrv.h"#include "article.h" enum {	Nfront	= 10,	// max # in front page};  typedef struct Req  Req;struct Req{	char*	group;	char*	file;	int	op;	HSPairs*args;}; typedef struct Opf Opf;struct Opf {	char	op;	void	(*f)(Req*);}; static	Hio*	hout;static	Hio	houtb;static	int	vermaj;static	HConnect*hcon; static	int	debug = 0;  static	char	Dfltreq[]= "o=i&g=dso";static	char	Top[]	= "/groups";static	char	Mark[]	= "DYNAMIC"; /*  * Strings seen in output, to help with localization. */static	char	Msearchresults[] = "Resultados de la búsqueda";static	char	Mreturn[] = "Volver.";static	char	Msendnew[]= "Enviar nuevo articulo";static	char	Mreply[] = "Responder";static	char	Mreplyto[]= "Responder a...";static	char	Manswers[] = "resp.";static	char	Mgoonreading[] = "Seguir leyendo otros";static	char	Mgoback[] = "Volver atras";static	char	Mreadmore[] = "Leer mas";static	char	Mreturntoindex[] = "Volver a la portada";static	char	Mwrote[] = "dice...";static	char	Mby[] = "Por";static	char	Mrequiredfieldmissing[] =		"No has escrito en un campo requerido.\n"		"Usa back en tu navegador e intenta de nuevo\n";static	char	Mclickheretoreturn[] = "<p>Hecho. Pulsa "		"<a href=\"/magic/group?o=i&g=%s\">aquí</a> "		"para volver.\n";static	char	Mbodywithlonglines[]= 	"Tienes lineas muy largas. Usa back en tu navegador\n"	"y usa return para que tu mensaje tenga lineas\n"	"que se puedan leer bien (max 80 caracteres).\n"; static voidbadreq(void){	hfail(hcon, HBadReq);	exits(nil);} static voidnotfound(char* o){	hfail(hcon, HNotFound, o);	exits(nil);} static voidfailure(void){	hfail(hcon, HTempFail);	exits(nil);} static voidheaders(char* title){	if(vermaj){		hokheaders(hcon);		hprint(hout, "Content-type: text/html; charset=UTF-8\r\n");		hflush(hout);	}	if (title != nil)		hprint(hout, "<head><title>%s</title></head><body>\n", title);} static voidnotice(char* fmt, ...){	va_list arg;	char buf[1024], *out; 	va_start(arg, fmt);	out = vseprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	*out = 0;	headers("notice");	hprint(hout, "%s", buf);	hprint(hout, "</body>\n");} static char*getarg(Req* r, char arg, int must){	HSPairs*p; 	for (p = r->args; p != nil; p = p->next){		if (p->s[0] == arg)			return p->t;	}	if (must)		badreq();	return nil;} static voidparsereq(char* s, Req* r){	char*	v; 	memset(r, 0, sizeof(Req));	r->args = hparsequery(hcon, s); 	v = getarg(r, 'o', 1);	r->op = *v;	v = getarg(r, 'g', 1);	r->group = strdup(v);} static voidoutfilehdr(Biobuf* bin){	char*	ln; 	while(ln = Brdstr(bin, '\n', 1)){		if (strcmp(ln, Mark) == 0){			free(ln);			return;		}		hprint(hout, "%s\n", ln);		free(ln);	}} static voidoutfiletail(Biobuf* bin){	char*	ln; 	while(ln = Brdstr(bin, '\n', 1)){		hprint(hout, "%s\n", ln);		free(ln);	}} static voidgetpostintro(Post* p, char* intro, int max, int* more){	char*	e;	char*	w;	int	l; 	e = strecpy(intro, intro+max-4, p->body);	l = e - intro;	*more = (p->body[l] != 0);	if (*more){		w = strrchr(intro, ' ');		if (w)			e = w;		strcpy(e, "...");	}} static char* Mon[] = {	"Ene", "Feb", "Mar", "Abr", "May", "Jun",	"Jul", "Ago", "Sep", "Oct", "Nov", "Dic"}; static char*artdate(ulong mt){	Tm*	tm;	static char str[40]; 	if (mt == 0)		return "";	tm = localtime(mt);	seprint(str, str+40, "(%d-%s)", tm->mday, Mon[tm->mon]);	return str;} static Biobuf*bopenfile(char* group, char* art, ulong* mt){	char*	file;	Biobuf*	ib;	Dir*	d; 	file = smprint("%s/%s/%s", Top, group, art);	if (strstr(file, "..")){		free(file);		badreq();	}	if (mt != nil){		*mt = 0;		d = dirstat(file);		if (d != nil){			*mt = d->mtime;			free(d);		}	}	ib = Bopen(file, OREAD);	free(file);	return ib;} static intoutpostintro(char* g, char* file, int verbose){	Biobuf*	bin;	Post*	p;	int	n;	char	intro[120];	int	more;	char*	date;	ulong	mt; 	bin = bopenfile(g, file, &mt);	if (bin == nil)		return 0;	if (debug)		fprint(2, "%s/%s\n", g, file);	p = readarticle(bin, &n);	if (p == nil){		Bterm(bin);		return 0;	}	date = artdate(mt);	if(debug)		fprint(2, "article %s\n", p->title);	switch(verbose){	case 0:		hprint(hout,"<b><a href=\"/magic/group?o=a&g=%s&a=%s\">",			g, file);		hprint(hout, "%s</a> (%s; %d posts)</b><br>\n", p->title, p->author, n);		break;	case 1:		hprint(hout,"<p> <a href=\"/magic/group?o=a&g=%s&a=%s\">",			g, file);		hprint(hout, "<font size=+1><b>%s</b> %s</a> ", p->title, date);		hprint(hout, "<font size=-1><b>(%s %s)</b><br>\n", Mby, p->author);		break;	default:		hprint(hout, "<p><font size=+1><hr><b>%s</b> %s", p->title, date);		hprint(hout, "<br><font size=-1><b>%s %s</b> <br>\n", Mby, p->author);		getpostintro(p, intro, sizeof(intro), &more);		hprint(hout, "<font size=+0>%s<br>\n", intro);		if (n > 1)			hprint(hout,				"<a href=\"/magic/group?o=a&g=%s&a=%s\">Leer "				"mas</a> (%d %s.)<p>\n", g, file, n-1, Manswers);		else			hprint(hout,				"<a href=\"/magic/group?o=a&g=%s&a=%s\">%s"				"</a><p>\n",g, file, Mreadmore);	}	closepost(p);	Bterm(bin);	return 1;} static char*readfile(char* fname){	Dir*	d;	vlong	len;	int	fd;	char*	buf; 	fd = open(fname, OREAD);	if (fd < 0)		return nil;	d = dirfstat(fd);	assert (d != nil);	len = d->length;	free(d);	buf = malloc(len +1);	buf[0] = 0;	readn(fd, buf, len);	close(fd);	buf[len] = 0;	return buf;} static intidxsort(void* a, void* b){	Dir* da = a;	Dir* db = b; 	if (da->name[0] != 'A')		return 1;	return (int)(da->mtime - db->mtime);} static char*readindex(Req* req, char*** entsp, int* nentsp){	Dir*	d;	char**	ents;	int	fd;	char*	buf;	char*	dir;	int	nd;	long	l;	int	i, j;	char*	s; 	/* Experiment, read all article files, and	 * sort by mtime.	 */	if (strstr(req->group, ".."))		notfound("..");	dir = smprint("%s/%s", Top, req->group);	fd = open(dir, OREAD);	if (fd < 0)		failure();	nd = dirreadall(fd, &d);	close(fd);	if (nd <= 0){		*entsp = nil;		*nentsp = 0;		return nil;	}	qsort(d, nd, sizeof(d[0]), idxsort);	l = 0;	for (i = 0; i < nd; i++){		if (d[i].name[0] != 'A')			continue;		l += strlen(d[i].name) + 2;	}	s = buf = malloc(l);	ents=malloc(sizeof(char*)*(nd+1));	if (buf == nil){		free(d);		failure();	}	for (i = j = 0; i < nd; i++){		//hprint(hout, "debug: art = %s\n<br>", d[i].name);		if (d[i].name[0] == 'A'){			ents[j++] = s;			s = strecpy(s, buf+l, d[i].name);			*s++ = 0;		}	}	*entsp = ents;	*nentsp= j;	free(d);	return buf;} static voidgetidxreq(Req* req){	static char prevfmt[] = "<a href=\"/magic/group?o=i&g=%s&S=%d\">%s</a><p>\n";	static char nextfmt[] = "<a href=\"/magic/group?o=i&g=%s&S=%d\">%s</a><p>\n";	char*	idx;	char**	ents;	int	nents;	char*	buf;	Biobuf*	ib;	int	i;	int	start;	int	n;	char*	s; 	idx = smprint("%s/%s/index.html", Top, req->group);	start = 0;	s = getarg(req, 'S', 0);	if (s != nil)		start=atoi(s);	ib = Bopen(idx, OREAD);	if (ib == nil)		notfound("index");	headers(nil);	outfilehdr(ib);	buf = readindex(req, &ents, &nents);	n = 0;	for (i = nents-1; i >= 0; i--){		if (start != 0 && n == start){			hprint(hout, prevfmt , req->group,				((start - Nfront) < 0 ? 0 : (start - Nfront)), Mgoback);		}		if (n >= start && n < start+Nfront)			outpostintro(req->group, ents[i], 2);		if (n == start+Nfront){			hprint(hout, nextfmt, req->group,				start + Nfront, Mgoonreading);			break;		}		n++;	}	outfiletail(ib);	Bterm(ib);	free(idx);	free(ents);	free(buf);} static voidoutpost(int tab, char* g, char* f, Post* p){	char	tabs[Nids+1];	char	*np;	char	*sp;	char*	s;	char*	titlefmt= "%s<font size=+2><b>%s</b><font size=-2>\n<p>";	char*	authfmt= "%s<font size=+1><b>%s %s</b><font size=-1><br>\n";	char*	otherfmt = "%s<font size=+1><b>%s %s</b><font size=-1><br>\n";	char*	replfmt = "%s<a href=\"/magic/group?o=r&g=%s&a=%s&"				"i=%s\">%s</a>\n"; 	memset(tabs, '\t', sizeof(tabs));	tabs[tab] = 0; 	if (tab <= 0){		if (p->title[0] != 0)			hprint(hout, titlefmt, tabs, p->title);		hprint(hout, authfmt, tabs, Mby, p->author);	} else		hprint(hout, otherfmt, tabs, p->author, Mwrote);	sp = p->body;	if (p->body[0] != 0){		while(sp != nil){			np = strchr(sp, '\n');			hprint(hout, "%s", tabs);			if (np == nil)				hprint(hout, "%s\n", sp);			else{				hwrite(hout, sp, np-sp);				hprint(hout, "\n");				np++;			}			sp = np;		}	}	if (g != nil && f != nil){		s = id2str(p->ids, p->nids);		hprint(hout, replfmt, tabs, g, f, s, Mreply);	}	hprint(hout, "<hr>\n");} static voidoutarticle(int tab, char* g, char* f, Post* p){	int	i; 	outpost(tab, g, f, p);	for (i = 0; i < p->nsons; i++)		outarticle(tab+1, g, f, p->sons[i]);} static Post*openarticle(char* group, char* art){	Post*	p;	Biobuf*	ib;	ulong	mt; 	ib = bopenfile(group, art, &mt);

Lines 1–500 of 855.