Plan 9 from Bell Labs’s /usr/web/sources/contrib/stallion/src/getpop3/getpop3.c

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


/*
 * download mail from pop server,
 * deliver to plan9
 */

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

int Debug = 0;

typedef struct Link Link;
struct Link {
	Biobuf *i;
	Biobuf *o;
};

/* this should be a library routine */
int
system(char *cmd) 
{
	Waitmsg *w;

	switch(fork()){
	case -1:
		return -1;
	case 0:
		execl("/bin/rc", "rc", "-c", cmd, 0);
		_exits(0);
	default:
		if((w = wait()) == nil) {
			werrstr("wait() fails");
			return -1;
		}
		if(w->msg[0] != 0){
			werrstr("wait: %s", w->msg);
			free(w);
			return -1;
		}
		free(w);
		return 0;
	}
}
static int
isokay(char *s)
{
	return s != nil && strncmp(s, "+OK", 3) == 0;
}

static void
pop3cmd(Link *l, char *fmt, ...)
{
	va_list va;
	char buf[128];

	va_start(va, fmt);
	vseprint(buf, buf+sizeof(buf), fmt, va);
	va_end(va);

	Bprint(l->o, "%s\r\n", buf);
	Bflush(l->o);

	if(Debug)
		fprint(2, "<- %s\n", buf);
}

static char*
pop3resp(Link *l)
{
	char *s, *p;

	if((s = Brdline(l->i, '\n')) == nil)
		return nil;

	p = s+ Blinelen(l->i) -1;
	while(p >= s && (*p == '\r' || *p == '\n'))
		*p-- = '\0';

	if(Debug)
		fprint(2, "-> %s\n", s);
	return s;
}

int
pop3login(Link *l, char *host, char *uname, int passonly)
{
	int n;
	char *s, *p, *q;
	UserPasswd *up;
	char user[128], ubuf[128], buf[256];

	if((s = pop3resp(l)) == nil)
		sysfatal("missing pop3 login banner");

	if(uname)
		snprint(ubuf, sizeof ubuf, " user=%s", uname);
	else
		ubuf[0] = '\0';

	if(!passonly && (p=strchr(s, '<')) != 0 && (q=strchr(p+1, '>')) != 0){
		*++q = '\0';
		if((n = auth_respond(p, q-p, user, sizeof user, buf, sizeof buf, auth_getkey,
		    "proto=apop role=client server=%q%s", host, ubuf)) < 0)
			sysfatal("factotum failed %r");

		pop3cmd(l, "APOP %s %.*s", user, n, buf);
		if(!isokay(s = pop3resp(l)))
			sysfatal("%s@%s %.*s: %s", user, host, n, buf, s);
	}
	else {
		if ((up = auth_getuserpasswd(auth_getkey, "proto=pass service=pop dom=%q%s",
		    host, ubuf)) == nil)
			sysfatal("factotum cannot get key %r");

		pop3cmd(l, "USER %s", up->user);
		if(!isokay(s = pop3resp(l)))
			sysfatal("%s@%s: %s", up->user, host, s);
	
		pop3cmd(l, "PASS %s", up->passwd);
		if(!isokay(s = pop3resp(l)))
			sysfatal("%s@%s: %s", up->user, host, s);
	}
	return 0;
}

int
getmsg(Link *l, int num, char *mailto, int delete)
{
	int n, tfd;
	char buf[256];
	char *s, *es, *rp, *wp;
	char template[32] = "/tmp/p3g.XXXXXXXXXXX";
	
	USED(mailto);

	pop3cmd(l, "LIST %d", num);
	if(!isokay(s = pop3resp(l)))
		sysfatal("LIST %d: %s", num, s);

	s = buf + strlen(buf) -1;
	while(s > buf && *s == ' ' || *s == '\t')
		s--;
	while(s >= buf && '0' <= *s && *s <= '9')
		s--;
//	s++;
//	n = atoi(s);

	pop3cmd(l, "RETR %d", num);
	if(!isokay(s = pop3resp(l)))
		sysfatal("RETR %d: %s", num, s);

	mktemp(template);
	if((tfd = create(template, OWRITE, 0600)) < 0)
		sysfatal("cannot create temp file %s: %r\n", template);

	fprint(tfd, "From %s %s", getuser(), ctime(time(nil)));
	while((s = Brdline(l->i, '\n')) != 0) {
		n = Blinelen(l->i);
		if(n == 3 && strncmp(s, ".\r\n", 3) == 0)
			break;
		es = s+n;
		if(*s == '.')
			s++;
		for(wp = rp = s; rp < es; rp++) {
			if(*rp != '\r')
				*wp++ = *rp;
		}
		write(tfd, s, wp - s);	
	}
	close(tfd);

	if(s == 0) {
		fprint(2, "error reading message %d\n", num);
		return -1;
	}

	snprint(buf, sizeof buf, "upas/fs -f %s", template);
	if(system(buf) < 0) {
		fprint(2, "error starting upas/fs %d: %r\n", num);
		remove(template);
		return -1;
	}

	snprint(buf, sizeof buf, "upas/send %s </mail/fs/mbox/1/rawunix", getuser());
	if(system(buf) < 0) {
		fprint(2, "error sending msg %d: %r\n", num);
		remove(template);
		return -1;
	}

	remove(template);

	if(delete) {
		pop3cmd(l, "DELE %d", num);
		if(!isokay(s = pop3resp(l)))
			sysfatal("DELE %d: %s", num, s);
	}
	return 0;	
}

int
nmsg(Link *l)
{
	char *s;

	pop3cmd(l, "STAT");
	if((s = pop3resp(l)) == nil)
		sysfatal("STAT: %s", s);
	return atoi(s +3);
}

int
pop3dial(char *host, int needtls)
{
	int fd;

	fd = dial(netmkaddr(host, "net", needtls ? "pop3s" : "pop3"), nil, nil, nil);
	if(fd < 0)
		return -1;

	if(needtls){
		int tfd;
		TLSconn conn;
/*
		Thumbprint *thumb;
		uchar digest[SHA1dlen];
*/

		memset(&conn, 0, sizeof conn);
		tfd = tlsClient(fd, &conn);
		if(tfd < 0){
/*
	    TLSError:
*/
			close(fd);
			return -1;
		}
/*
		if(conn.cert==nil || conn.certlen <=0)
			goto TLSError;
		thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
		sha1(conn.cert, conn.certlen, digest, nil);
		if(!thumb || !okThumbprint(digest, thumb)){
			close(tfd);
			goto TLSError;
		}
*/
		if(conn.cert)
			free(conn.cert);
		close(fd);
		fd = tfd;
	}
	return fd;
}
	
char *usage = "usage: %s [-dDa] [-u pop3user] [-m mailto] pophost\n";

void
main(int argc, char **argv)
{
	char *user, *mailto, *server;
	int passonly = 0, delete = 0;
	int needtls = 0;
	int i, n, fd;
	Biobuf bi, bo;
	Link l;

	rfork(RFNAMEG);

	user = nil;
	mailto = getuser();

	ARGBEGIN{
	case 'a':		/* use pop not apop, even if offered */
		passonly++;
		break;
	case 'd':		/* delete msgs from server */
		delete++;
		break;
	case 'm':		/* user to forward messages to */
		mailto = ARGF();
		break;
	case 'D':		/* pop3 protocol debug */
		Debug++;
		break;
	case 'u':		/* user to login to server as */
		user = ARGF();
		break;
	case 's':
		needtls++;
		break;
	default:
		fprint(2, usage, argv0);
		exits("usage");
	}ARGEND;

	if(argc != 1){
		fprint(2, usage, argv0);
		exits("usage");
	}

	if(mailto == 0)
		mailto = getuser();
	server = argv[0];
	if((fd = pop3dial(server, needtls)) < 0)
		sysfatal("can't dial %r");

	Binit(&bi, fd, OREAD);
	l.i = &bi;
	Binit(&bo, fd, OWRITE);
	l.o = &bo;

	pop3login(&l, server, user, passonly);

	n = nmsg(&l);

	for(i=0; i < n; i++)
		if(getmsg(&l, i+1, mailto, delete) < 0)
			break;

	pop3cmd(&l, "QUIT");

	Bterm(&bi);
	Bterm(&bo);

	if(i != n)
		sysfatal("error reading msgs: only read 1..%d %r\n", i);

	exits(0);
}




Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].