/*
* 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);
}
|