Plan 9 from Bell Labs’s /usr/web/sources/contrib/fhs/threads.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>

char *mntpt = "/mail/fs/mbox";

typedef struct Mesg Mesg;
struct Mesg {
	char*	num;
	char*	id;		/* Message-ID */
	char*	parentid;
	int		nkids;
	Mesg**	kids;
};

Mesg*	msgs;
long	nmsgs;
Mesg**	threads;
long	nthreads;

void*
emalloc(uint n)
{
	void *p;

	p = malloc(n);
	if(p == nil)
		sysfatal("can't malloc: %r");
	memset(p, 0, n);
	setmalloctag(p, getcallerpc(&n));
	return p;
}

void*
erealloc(void *p, uint n)
{
	p = realloc(p, n);
	if(p == nil)
		sysfatal("can't realloc: %r");
	setmalloctag(p, getcallerpc(&n));
	return p;
}

char*
estrdup(char *s)
{
	char *t;

	t = emalloc(strlen(s)+1);
	strcpy(t, s);
	return t;
}

char*
digest(char *id)
{
	char *s, *d;

	s = nil;
	d = strchr(id, '<');
	if(d){
		s = strchr(++d, '>');
		if(s)
			*s = 0;
	}
	if(d == nil || s == nil)
		d = id;
	return d;
}

char*
field(char *num, char *left)
{
	char path[32], buf[8192];
	char *right;
	int fd, n;

	snprint(path, sizeof path, "%s/%s/%s", mntpt, num, left);
	fd = open(path, OREAD);
	if(fd < 0)
		sysfatal("opening file %s: %r", path);
	n = read(fd, buf, sizeof buf);
	if(n < 0)
		sysfatal("reading %s: %r", path);
	buf[n] = 0;
	right = estrdup(buf);
	close(fd);
	return right;
}

Mesg*
newmsg(Mesg *m, char *num)
{
	char *s, *t, *q;
	Biobuf *b;
	char hp[100];

	m->num = estrdup(num);
	s = field(num, "messageid");
	m->id = estrdup(digest(s));
	free(s);
	s = field(num, "inreplyto");
	m->parentid = estrdup(digest(s));
	free(s);
	/*
	 * If In-Reply-To doesn't exist, try References. The last
	 * <...> part is the parent id.
	 */
	if(m->parentid[0] == 0){
		snprint(hp, sizeof hp, "%s/%s/rawheader", mntpt, num);
		b = Bopen(hp, OREAD);
		if(b == nil)
			sysfatal("Bopen %s: %r", hp);
		while((s = Brdline(b, '\n')) != nil){
			s[Blinelen(b)-1] = 0;
			if(strncmp(s, "References:", 11) != 0)
				continue;
			t = strrchr(s, '<');
			if(t == nil)
				break;
			t++;
			q = strchr(t, '>');
			if(q == nil)
				break;
			*q = 0;
			free(m->parentid);
			m->parentid = estrdup(t);
		}
		Bterm(b);
	}
	m->kids = nil;
	m->nkids = 0;
	return m;
}

void
cleanup(void)
{
	int i;

	for(i = 0; i < nmsgs; i++){
		free(msgs[i].num);
		free(msgs[i].id);
		free(msgs[i].parentid);
		free(msgs[i].kids);
	}
	free(msgs);
	free(threads);
}
	
Mesg*
findparent(Mesg *c)
{
	int i;
	char *pid, *mid;
	Mesg *m, *p;

	p = nil;
	pid = c->parentid;
	for(i = 0; i < nmsgs; i++){
		m = &msgs[i];
		mid = m->id;
		if(c != m && strcmp(mid, pid) == 0){
			p = m;
			p->kids = erealloc(p->kids, (p->nkids+1)*sizeof(Mesg*));
			p->kids[p->nkids++] = c;
			break;
		}
	}
	return p;
}

void
printthreads(Mesg **ms, int len, int depth)
{
	int i;
	char *subj, *from, ind[100];

	strcpy(ind, "");
	if(depth < nelem(ind)-1){
		memset(ind, '\t', depth);
		ind[depth] = 0;
	}
	for(i = 0; i < len; i++){
		subj = field(ms[i]->num, "subject");
		from = field(ms[i]->num, "from");
		if(depth == 0)
			print("%s%s/ %s %s\n", ind, ms[i]->num, from, subj);
		else
			print("%s%s/ %s\n", ind, ms[i]->num, from);
		printthreads(ms[i]->kids, ms[i]->nkids, depth+1);
	}
}

void
usage(void)
{
	fprint(2, "usage: upas/threads [upasmntpt]\n");
	exits("usage");
}

void
main(int argc, char *argv[])
{
	int fd;
	long i, n;
	Dir *ms;
	Mesg *p;
	
	ARGBEGIN {
	default:
		usage();
	} ARGEND

	if(argc > 0)
		mntpt = argv[0];
	fd = open(mntpt, OREAD);
	if(fd < 0)
		sysfatal("opening %s: %r", mntpt);
	n = dirreadall(fd, &ms);
	msgs = emalloc(n*sizeof(Mesg));
	for(i = 0; i < n; i++)
		if(isdigit(ms[i].name[0])){
			newmsg(&msgs[nmsgs], ms[i].name);
			nmsgs++;
		}
	close(fd);

	/* nthreads <= nmesg */
	threads = emalloc(nmsgs*sizeof(Mesg*));
	for(i = 0; i < nmsgs; i++){
		p = findparent(&msgs[i]);
		if(p == nil)
			threads[nthreads++] = &msgs[i];
	}
	printthreads(threads, nthreads, 0);
	cleanup();

	exits(nil);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.