Plan 9 from Bell Labs’s /usr/web/sources/contrib/rsc/cmd/pop3get.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 <auth.h>

int debug;
char *user = 0;
char *mailto;
char *secretfile = 0;
int maxsize = 0;
int delete = 0;
char secret[260];
int passwd = 0;	/* allowed to use USER/PASS mechanism? */
int bfd;
char *fromaddr = "upas";
char *host;

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

	switch(pid = 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->pid != pid){
			werrstr("wait got unexpected pid");
			return -1;
		}
		if(w->msg[0]){
			werrstr("wait: %s", w->msg);
			return -1;
		}
		sleep(1000);
		return 0;
	}
}

/*
 * get pop3 response.
 * don't worry about multiline.
 * the commands expecting responses 
 * should know whether or not they are multiline.
 */
int
popresp(Biobuf *b, char *buf, int nbuf)
{
	int rv;
	char *s;
	int n;

	if(debug) fprint(2, "resp...");
	if((s = Brdline(b, '\n')) == 0){
		fprint(2, "brdline error: %r");
		exits("brdline");
	}

	n = Blinelen(b);
	while(n>0 && s[n-1] == '\r' || s[n-1] == '\n')
		s[--n] = '\0';

	if(strncmp(s, "+OK", 3) == 0)
		rv = 0;
	else
		rv = -1;

	strncpy(buf, s, nbuf);
	buf[nbuf-1] = '\0';

	if(debug) fprint(2, "pop response '%s' rv=%d\n", buf, rv);
	return rv;
}

void
xlogin(Biobuf *b, char *xuser, int passwd)
{
	char buf[256];
	char user[256], ubuf[256];
	int n;
	char *p, *q;
	UserPasswd *up;

	if(popresp(b, buf, sizeof buf) < 0)
		sysfatal("bad login banner");

	ubuf[0] = 0;
	if(xuser)
		snprint(ubuf, sizeof ubuf, " user=%q", xuser);

	/* otherwise apop */
	if(!passwd && (p=strchr(buf, '<')) != 0 && (q=strchr(p+1, '>')) != 0){
		*++q = '\0';
		if(debug) fprint(2, "apop...");
		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");
		if(user[0]=='\0')
			sysfatal("factotum did not return a user name");
		buf[n] = 0;
fprint(2, "APOP %s\r\n", buf);
		fprint(bfd, "APOP %s %s\r\n", user, buf);
		if(popresp(b, buf, sizeof buf) == 0)
			return;
		if(debug) fprint(2, "apop failed...");
		sysfatal("cannot apop authenticate");
	}else{
		up = auth_getuserpasswd(auth_getkey, "proto=pass service=pop dom=%q%s",
			host, ubuf);
		if(up == nil)
			sysfatal("factotum failed");
		if(debug) fprint(2, "user...");
		fprint(bfd, "USER %s\r\n", up->user);
		if(popresp(b, buf, sizeof buf) < 0)
			sysfatal("user: %s", buf);
	
		if(debug) fprint(2, "pass...");
		fprint(bfd, "PASS %s\r\n", up->passwd);
		if(popresp(b, buf, sizeof buf) < 0)
			sysfatal("secret: %s", buf);
	}
}

int
getmsg(Biobuf *b, int msg)
{
	char template[32] = "/tmp/p3g.XXXXXXXXXXX";
	char buf[256];
	char *s, *es, *rp, *wp;
	int ofd, n;

	fprint(2, "get msg %d...", msg);
	fprint(bfd, "LIST %d\r\n", msg);
	if(popresp(b, buf, sizeof buf) < 0) {
		fprint(2, "bad stat response: %r\n");
		return -1;
	}

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

	s++;
	n = atoi(s);
	if(maxsize && n > maxsize) {
		fprint(2, "msg %d too big: %d > %d\n", 
			msg, n, maxsize);
		return 0;
	}
	mktemp(template);
	if((ofd = create(template, OWRITE, 0600)) < 0) {
		fprint(2, "cannot open temp file %s: %r\n", template);
		return -1;
	}
	fprint(bfd, "RETR %d\r\n", msg);
	if(popresp(b, buf, sizeof buf) < 0) {
		fprint(2, "bad retr response: %r\n");
		return -1;
	}
	while((s = Brdline(b, '\n')) != 0) {
		n = Blinelen(b);
		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(ofd, s, wp-s);	
	}

	close(ofd);
	if(s == 0) {
		remove(template);
		fprint(2, "error reading message %d\n", msg);
		return -1;
	}

	snprint(buf, sizeof buf, "upas/deliver rsc /dev/user /fd/1 < %s", template);

	if(system(buf) < 0) {
		fprint(2, "error mailing msg %d: %r\n", msg);
		remove(template);
		return -1;
	}

	remove(template);
	if(delete) {
		fprint(bfd, "DELE %d\r\n", msg);
		if(popresp(b, buf, sizeof buf) < 0) {
			fprint(2, "error deleting msg %d: %r\n", msg);
			return -1;
		}
		fprint(bfd, "SYNC\r\n");
		if(popresp(b, buf, sizeof buf) < 0){
			fprint(2, "error deleting msg %d: %r\n", msg);
			return -1;
		}
	}
	return 0;	
}

int
nmsg(Biobuf *b)
{
	char buf[100];

	if(debug) fprint(2, "stat...");
	fprint(bfd, "STAT\r\n");
	if(popresp(b, buf, sizeof buf) < 0)
		sysfatal("can't count messages: %s\n", buf);
fprint(2, "%d messages\n", atoi(buf+3));
	return atoi(buf+3);
}
	
char *usage = "usage: %s [-cdpr] [-m mailto] [-u user] [-N n] pophost";

void
main(int argc, char **argv)
{
	int i, rflag=0, n;
	Biobuf b;
	char *user;

	user = nil;
	ARGBEGIN{
	case 'N':
		maxsize = atoi(ARGF());
		break;
	case 'r':
		rflag++;
		break;
	case 'd':
		delete++;
		break;
	case 'D':
		debug++;
		break;
	case 'p':
		passwd++;
		break;
	case 'u':
		user = ARGF();
		break;
	case 'm':
		mailto = ARGF();
		break;
	default:
		fprint(2, usage, argv0);
		exits("usage");
	}ARGEND;

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

	if(mailto == 0)
		mailto = getuser();

	host = argv[0];
	if((bfd = dial(netmkaddr(host, "net", "pop3"), nil, nil, nil)) < 0)
		sysfatal("dial: %r");
	Binit(&b, bfd, OREAD);

	if(debug) fprint(2, "login...");
	xlogin(&b, user, passwd);

	if(debug) fprint(2, "nmsg...");
	n = nmsg(&b);	

	if(rflag)
		for(i=n-1; i>=0; i--) {
			if(getmsg(&b, i+1) < 0)
				break;
		}
	else 
		for(i=0; i<n; i++) {
			if(getmsg(&b, i+1) < 0)
				break;
		}

	fprint(bfd, "QUIT\r\n");
	if(rflag && i >= 0) {
		fprint(2, "error reading msgs: only read %d..%d", n, i+1);
		exits("readmsg");
	}
	if(!rflag && i != n) {
		fprint(2, "error reading msgs: only read 1..%d\n", i);
		exits("readmsg");
	}
	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 webmaster@9p.io.