summaryrefslogtreecommitdiff
path: root/appl/lib/pop3.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/pop3.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/pop3.b')
-rw-r--r--appl/lib/pop3.b298
1 files changed, 298 insertions, 0 deletions
diff --git a/appl/lib/pop3.b b/appl/lib/pop3.b
new file mode 100644
index 00000000..18e90525
--- /dev/null
+++ b/appl/lib/pop3.b
@@ -0,0 +1,298 @@
+implement Pop3;
+
+include "sys.m";
+ sys : Sys;
+include "draw.m";
+include "bufio.m";
+ bufio : Bufio;
+include "pop3.m";
+
+FD, Connection: import sys;
+Iobuf : import bufio;
+
+ibuf, obuf : ref Bufio->Iobuf;
+conn : int = 0;
+inited : int = 0;
+
+rpid : int = -1;
+cread : chan of (int, string);
+
+DEBUG : con 0;
+
+open(user, password, server : string): (int, string)
+{
+ s : string;
+
+ if (!inited) {
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ inited = 1;
+ }
+ if (conn)
+ return (-1, "connection is already open");
+ if (server == nil) {
+ server = defaultserver();
+ if (server == nil)
+ return (-1, "no default mail server");
+ }
+ (ok, c) := sys->dial ("tcp!" + server + "!110", nil);
+ if (ok < 0)
+ return (-1, "dialup failed");
+ ibuf = bufio->fopen(c.dfd, Bufio->OREAD);
+ obuf = bufio->fopen(c.dfd, Bufio->OWRITE);
+ if (ibuf == nil || obuf == nil)
+ return (-1, "failed to open bufio");
+ cread = chan of (int, string);
+ spawn mreader(cread);
+ (rpid, nil) = <- cread;
+ (ok, s) = mread();
+ if (ok < 0)
+ return (-1, s);
+ (ok, s) = mcmd("USER " + user);
+ if (ok < 0)
+ return (-1, s);
+ (ok, s) = mcmd("PASS " + password);
+ if (ok < 0)
+ return (-1, s);
+ conn = 1;
+ return (1, nil);
+}
+
+stat() : (int, string, int, int)
+{
+ if (!conn)
+ return (-1, "not connected", 0, 0);
+ (ok, s) := mcmd("STAT");
+ if (ok < 0)
+ return (-1, s, 0, 0);
+ (n, ls) := sys->tokenize(s, " ");
+ if (n == 3)
+ return (1, nil, int hd tl ls, int hd tl tl ls);
+ return (-1, "stat failed", 0, 0);
+}
+
+msglist() : (int, string, list of (int, int))
+{
+ ls : list of (int, int);
+
+ if (!conn)
+ return (-1, "not connected", nil);
+ (ok, s) := mcmd("LIST");
+ if (ok < 0)
+ return (-1, s, nil);
+ for (;;) {
+ (ok, s) = mread();
+ if (ok < 0)
+ return (-1, s, nil);
+ if (len s < 3) {
+ if (len s > 0 && s[0] == '.')
+ return (1, nil, rev2(ls));
+ else
+ return (-1, s, nil);
+ }
+ else {
+ (n, sl) := sys->tokenize(s, " ");
+ if (n == 2)
+ ls = (int hd sl, int hd tl sl) :: ls;
+ else
+ return (-1, "bad list format", nil);
+ }
+ }
+}
+
+msgnolist() : (int, string, list of int)
+{
+ ls : list of int;
+
+ if (!conn)
+ return (-1, "not connected", nil);
+ (ok, s) := mcmd("LIST");
+ if (ok < 0)
+ return (-1, s, nil);
+ for (;;) {
+ (ok, s) = mread();
+ if (ok < 0)
+ return (-1, s, nil);
+ if (len s < 3) {
+ if (len s > 0 && s[0] == '.')
+ return (1, nil, rev1(ls));
+ else
+ return (-1, s, nil);
+ }
+ else {
+ (n, sl) := sys->tokenize(s, " ");
+ if (n == 2)
+ ls = int hd sl :: ls;
+ else
+ return (-1, "bad list format", nil);
+ }
+ }
+}
+
+top(m : int) : (int, string, string)
+{
+ if (!conn)
+ return (-1, "not connected", nil);
+ (ok, s) := mcmd("TOP " + string m + " 1");
+ if (ok < 0)
+ return (-1, s, nil);
+ return getbdy();
+}
+
+get(m : int) : (int, string, string)
+{
+ if (!conn)
+ return (-1, "not connected", nil);
+ (ok, s) := mcmd("RETR " + string m);
+ if (ok < 0)
+ return (-1, s, nil);
+ return getbdy();
+}
+
+getbdy() : (int, string, string)
+{
+ b : string;
+
+ for (;;) {
+ (ok, s) := mread();
+ if (ok < 0)
+ return (-1, s, nil);
+ if (s == ".")
+ break;
+ if (len s > 1 && s[0] == '.' && s[1] == '.')
+ s = s[1:];
+ b = b + s + "\n";
+ }
+ return (1, nil, b);
+}
+
+delete(m : int) : (int, string)
+{
+ if (!conn)
+ return (-1, "not connected");
+ return mcmd("DELE " + string m);
+}
+
+close(): (int, string)
+{
+ if (!conn)
+ return (-1, "connection not open");
+ ok := mwrite("QUIT");
+ kill(rpid);
+ ibuf.close();
+ obuf.close();
+ conn = 0;
+ if (ok < 0)
+ return (-1, "failed to close connection");
+ return (1, nil);
+}
+
+SLPTIME : con 100;
+MAXSLPTIME : con 10000;
+
+mread() : (int, string)
+{
+ t := 0;
+ while (t < MAXSLPTIME) {
+ alt {
+ (ok, s) := <- cread =>
+ return (ok, s);
+ * =>
+ t += SLPTIME;
+ sys->sleep(SLPTIME);
+ }
+ }
+ kill(rpid);
+ return (-1, "smtp timed out\n");
+}
+
+mreader(c : chan of (int, string))
+{
+ c <- = (sys->pctl(0, nil), nil);
+ for (;;) {
+ line := ibuf.gets('\n');
+ if (DEBUG)
+ sys->print("mread : %s", line);
+ if (line == nil) {
+ c <- = (-1, "could not read response from server");
+ continue;
+ }
+ l := len line;
+ if (line[l-1] == '\n')
+ l--;
+ if (line[l-1] == '\r')
+ l--;
+ c <- = (1, line[0:l]);
+ }
+}
+
+mwrite(s : string): int
+{
+ s += "\r\n";
+ if (DEBUG)
+ sys->print("mwrite : %s", s);
+ b := array of byte s;
+ l := len b;
+ nb := obuf.write(b, l);
+ obuf.flush();
+ if (nb != l)
+ return -1;
+ return 1;
+}
+
+mcmd(s : string) : (int, string)
+{
+ ok : int;
+ r : string;
+
+ ok = mwrite(s);
+ if (ok < 0)
+ return (-1, err(s) + " send failed");
+ (ok, r) = mread();
+ if (ok < 0)
+ return (-1, err(s) + " receive failed (" + r + ")");
+ if (len r > 1 && r[0] == '+')
+ return (1, r);
+ return (-1, r);
+}
+
+defaultserver() : string
+{
+ return "$pop3";
+}
+
+rev1(l1 : list of int) : list of int
+{
+ l2 : list of int;
+
+ for ( ; l1 != nil; l1 = tl l1)
+ l2 = hd l1 :: l2;
+ return l2;
+}
+
+rev2(l1 : list of (int, int)) : list of (int, int)
+{
+ l2 : list of (int, int);
+
+ for ( ; l1 != nil; l1 = tl l1)
+ l2 = hd l1 :: l2;
+ return l2;
+}
+
+err(s : string) : string
+{
+ for (i := 0; i < len s; i++)
+ if (s[i] == ' ' || s[i] == ':')
+ return s[0:i];
+ return s;
+}
+
+kill(pid : int) : int
+{
+ if (pid < 0)
+ return 0;
+ fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);
+ if (fd == nil || sys->fprint(fd, "kill") < 0)
+ return -1;
+ return 0;
+}