Blame


1 5cdb1798 2005-10-29 devnull #include "common.h"
2 5cdb1798 2005-10-29 devnull #include <ctype.h>
3 5cdb1798 2005-10-29 devnull #include <plumb.h>
4 5cdb1798 2005-10-29 devnull #include <libsec.h>
5 5cdb1798 2005-10-29 devnull #include <auth.h>
6 5cdb1798 2005-10-29 devnull #include <thread.h>
7 5cdb1798 2005-10-29 devnull #include "dat.h"
8 5cdb1798 2005-10-29 devnull
9 5cdb1798 2005-10-29 devnull #pragma varargck type "M" uchar*
10 5cdb1798 2005-10-29 devnull #pragma varargck argpos pop3cmd 2
11 5cdb1798 2005-10-29 devnull
12 5cdb1798 2005-10-29 devnull typedef struct Pop Pop;
13 5cdb1798 2005-10-29 devnull struct Pop {
14 5cdb1798 2005-10-29 devnull char *freep; // free this to free the strings below
15 5cdb1798 2005-10-29 devnull
16 5cdb1798 2005-10-29 devnull char *host;
17 5cdb1798 2005-10-29 devnull char *user;
18 5cdb1798 2005-10-29 devnull char *port;
19 5cdb1798 2005-10-29 devnull
20 5cdb1798 2005-10-29 devnull int ppop;
21 5cdb1798 2005-10-29 devnull int refreshtime;
22 5cdb1798 2005-10-29 devnull int debug;
23 5cdb1798 2005-10-29 devnull int pipeline;
24 5cdb1798 2005-10-29 devnull int encrypted;
25 5cdb1798 2005-10-29 devnull int needtls;
26 5cdb1798 2005-10-29 devnull int notls;
27 5cdb1798 2005-10-29 devnull int needssl;
28 5cdb1798 2005-10-29 devnull
29 5cdb1798 2005-10-29 devnull // open network connection
30 5cdb1798 2005-10-29 devnull Biobuf bin;
31 5cdb1798 2005-10-29 devnull Biobuf bout;
32 5cdb1798 2005-10-29 devnull int fd;
33 5cdb1798 2005-10-29 devnull char *lastline; // from Brdstr
34 5cdb1798 2005-10-29 devnull
35 5cdb1798 2005-10-29 devnull Thumbprint *thumb;
36 5cdb1798 2005-10-29 devnull };
37 5cdb1798 2005-10-29 devnull
38 5cdb1798 2005-10-29 devnull char*
39 5cdb1798 2005-10-29 devnull geterrstr(void)
40 5cdb1798 2005-10-29 devnull {
41 5cdb1798 2005-10-29 devnull static char err[64];
42 5cdb1798 2005-10-29 devnull
43 5cdb1798 2005-10-29 devnull err[0] = '\0';
44 5cdb1798 2005-10-29 devnull errstr(err, sizeof(err));
45 5cdb1798 2005-10-29 devnull return err;
46 5cdb1798 2005-10-29 devnull }
47 5cdb1798 2005-10-29 devnull
48 5cdb1798 2005-10-29 devnull //
49 5cdb1798 2005-10-29 devnull // get pop3 response line , without worrying
50 5cdb1798 2005-10-29 devnull // about multiline responses; the clients
51 5cdb1798 2005-10-29 devnull // will deal with that.
52 5cdb1798 2005-10-29 devnull //
53 5cdb1798 2005-10-29 devnull static int
54 5cdb1798 2005-10-29 devnull isokay(char *s)
55 5cdb1798 2005-10-29 devnull {
56 5cdb1798 2005-10-29 devnull return s!=nil && strncmp(s, "+OK", 3)==0;
57 5cdb1798 2005-10-29 devnull }
58 5cdb1798 2005-10-29 devnull
59 5cdb1798 2005-10-29 devnull static void
60 5cdb1798 2005-10-29 devnull pop3cmd(Pop *pop, char *fmt, ...)
61 5cdb1798 2005-10-29 devnull {
62 5cdb1798 2005-10-29 devnull char buf[128], *p;
63 5cdb1798 2005-10-29 devnull va_list va;
64 5cdb1798 2005-10-29 devnull
65 5cdb1798 2005-10-29 devnull va_start(va, fmt);
66 5cdb1798 2005-10-29 devnull vseprint(buf, buf+sizeof(buf), fmt, va);
67 5cdb1798 2005-10-29 devnull va_end(va);
68 5cdb1798 2005-10-29 devnull
69 5cdb1798 2005-10-29 devnull p = buf+strlen(buf);
70 5cdb1798 2005-10-29 devnull if(p > (buf+sizeof(buf)-3))
71 5cdb1798 2005-10-29 devnull sysfatal("pop3 command too long");
72 5cdb1798 2005-10-29 devnull
73 5cdb1798 2005-10-29 devnull if(pop->debug)
74 5cdb1798 2005-10-29 devnull fprint(2, "<- %s\n", buf);
75 5cdb1798 2005-10-29 devnull strcpy(p, "\r\n");
76 5cdb1798 2005-10-29 devnull Bwrite(&pop->bout, buf, strlen(buf));
77 5cdb1798 2005-10-29 devnull Bflush(&pop->bout);
78 5cdb1798 2005-10-29 devnull }
79 5cdb1798 2005-10-29 devnull
80 5cdb1798 2005-10-29 devnull static char*
81 5cdb1798 2005-10-29 devnull pop3resp(Pop *pop)
82 5cdb1798 2005-10-29 devnull {
83 5cdb1798 2005-10-29 devnull char *s;
84 5cdb1798 2005-10-29 devnull char *p;
85 5cdb1798 2005-10-29 devnull
86 5cdb1798 2005-10-29 devnull alarm(60*1000);
87 5cdb1798 2005-10-29 devnull if((s = Brdstr(&pop->bin, '\n', 0)) == nil){
88 5cdb1798 2005-10-29 devnull close(pop->fd);
89 5cdb1798 2005-10-29 devnull pop->fd = -1;
90 5cdb1798 2005-10-29 devnull alarm(0);
91 5cdb1798 2005-10-29 devnull return "unexpected eof";
92 5cdb1798 2005-10-29 devnull }
93 5cdb1798 2005-10-29 devnull alarm(0);
94 5cdb1798 2005-10-29 devnull
95 5cdb1798 2005-10-29 devnull p = s+strlen(s)-1;
96 5cdb1798 2005-10-29 devnull while(p >= s && (*p == '\r' || *p == '\n'))
97 5cdb1798 2005-10-29 devnull *p-- = '\0';
98 5cdb1798 2005-10-29 devnull
99 5cdb1798 2005-10-29 devnull if(pop->debug)
100 5cdb1798 2005-10-29 devnull fprint(2, "-> %s\n", s);
101 5cdb1798 2005-10-29 devnull free(pop->lastline);
102 5cdb1798 2005-10-29 devnull pop->lastline = s;
103 5cdb1798 2005-10-29 devnull return s;
104 5cdb1798 2005-10-29 devnull }
105 5cdb1798 2005-10-29 devnull
106 5cdb1798 2005-10-29 devnull #if 0 /* jpc */
107 5cdb1798 2005-10-29 devnull static int
108 5cdb1798 2005-10-29 devnull pop3log(char *fmt, ...)
109 5cdb1798 2005-10-29 devnull {
110 5cdb1798 2005-10-29 devnull va_list ap;
111 5cdb1798 2005-10-29 devnull
112 5cdb1798 2005-10-29 devnull va_start(ap,fmt);
113 5cdb1798 2005-10-29 devnull syslog(0, "/sys/log/pop3", fmt, ap);
114 5cdb1798 2005-10-29 devnull va_end(ap);
115 5cdb1798 2005-10-29 devnull return 0;
116 5cdb1798 2005-10-29 devnull }
117 5cdb1798 2005-10-29 devnull #endif
118 5cdb1798 2005-10-29 devnull
119 5cdb1798 2005-10-29 devnull static char*
120 5cdb1798 2005-10-29 devnull pop3pushtls(Pop *pop)
121 5cdb1798 2005-10-29 devnull {
122 5cdb1798 2005-10-29 devnull int fd;
123 5cdb1798 2005-10-29 devnull uchar digest[SHA1dlen];
124 5cdb1798 2005-10-29 devnull TLSconn conn;
125 5cdb1798 2005-10-29 devnull
126 5cdb1798 2005-10-29 devnull memset(&conn, 0, sizeof conn);
127 5cdb1798 2005-10-29 devnull // conn.trace = pop3log;
128 5cdb1798 2005-10-29 devnull fd = tlsClient(pop->fd, &conn);
129 5cdb1798 2005-10-29 devnull if(fd < 0)
130 5cdb1798 2005-10-29 devnull return "tls error";
131 5cdb1798 2005-10-29 devnull if(conn.cert==nil || conn.certlen <= 0){
132 5cdb1798 2005-10-29 devnull close(fd);
133 5cdb1798 2005-10-29 devnull return "server did not provide TLS certificate";
134 5cdb1798 2005-10-29 devnull }
135 5cdb1798 2005-10-29 devnull sha1(conn.cert, conn.certlen, digest, nil);
136 5cdb1798 2005-10-29 devnull if(!pop->thumb || !okThumbprint(digest, pop->thumb)){
137 5cdb1798 2005-10-29 devnull fmtinstall('H', encodefmt);
138 5cdb1798 2005-10-29 devnull close(fd);
139 5cdb1798 2005-10-29 devnull free(conn.cert);
140 5cdb1798 2005-10-29 devnull fprint(2, "upas/fs pop3: server certificate %.*H not recognized\n", SHA1dlen, digest);
141 5cdb1798 2005-10-29 devnull return "bad server certificate";
142 5cdb1798 2005-10-29 devnull }
143 5cdb1798 2005-10-29 devnull free(conn.cert);
144 5cdb1798 2005-10-29 devnull close(pop->fd);
145 5cdb1798 2005-10-29 devnull pop->fd = fd;
146 5cdb1798 2005-10-29 devnull pop->encrypted = 1;
147 5cdb1798 2005-10-29 devnull Binit(&pop->bin, pop->fd, OREAD);
148 5cdb1798 2005-10-29 devnull Binit(&pop->bout, pop->fd, OWRITE);
149 5cdb1798 2005-10-29 devnull return nil;
150 5cdb1798 2005-10-29 devnull }
151 5cdb1798 2005-10-29 devnull
152 5cdb1798 2005-10-29 devnull //
153 5cdb1798 2005-10-29 devnull // get capability list, possibly start tls
154 5cdb1798 2005-10-29 devnull //
155 5cdb1798 2005-10-29 devnull static char*
156 5cdb1798 2005-10-29 devnull pop3capa(Pop *pop)
157 5cdb1798 2005-10-29 devnull {
158 5cdb1798 2005-10-29 devnull char *s;
159 5cdb1798 2005-10-29 devnull int hastls;
160 5cdb1798 2005-10-29 devnull
161 5cdb1798 2005-10-29 devnull pop3cmd(pop, "CAPA");
162 5cdb1798 2005-10-29 devnull if(!isokay(pop3resp(pop)))
163 5cdb1798 2005-10-29 devnull return nil;
164 5cdb1798 2005-10-29 devnull
165 5cdb1798 2005-10-29 devnull hastls = 0;
166 5cdb1798 2005-10-29 devnull for(;;){
167 5cdb1798 2005-10-29 devnull s = pop3resp(pop);
168 5cdb1798 2005-10-29 devnull if(strcmp(s, ".") == 0 || strcmp(s, "unexpected eof") == 0)
169 5cdb1798 2005-10-29 devnull break;
170 5cdb1798 2005-10-29 devnull if(strcmp(s, "STLS") == 0)
171 5cdb1798 2005-10-29 devnull hastls = 1;
172 5cdb1798 2005-10-29 devnull if(strcmp(s, "PIPELINING") == 0)
173 5cdb1798 2005-10-29 devnull pop->pipeline = 1;
174 5cdb1798 2005-10-29 devnull }
175 5cdb1798 2005-10-29 devnull
176 5cdb1798 2005-10-29 devnull if(hastls && !pop->notls){
177 5cdb1798 2005-10-29 devnull pop3cmd(pop, "STLS");
178 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop)))
179 5cdb1798 2005-10-29 devnull return s;
180 5cdb1798 2005-10-29 devnull if((s = pop3pushtls(pop)) != nil)
181 5cdb1798 2005-10-29 devnull return s;
182 5cdb1798 2005-10-29 devnull }
183 5cdb1798 2005-10-29 devnull return nil;
184 5cdb1798 2005-10-29 devnull }
185 5cdb1798 2005-10-29 devnull
186 5cdb1798 2005-10-29 devnull //
187 5cdb1798 2005-10-29 devnull // log in using APOP if possible, password if allowed by user
188 5cdb1798 2005-10-29 devnull //
189 5cdb1798 2005-10-29 devnull static char*
190 5cdb1798 2005-10-29 devnull pop3login(Pop *pop)
191 5cdb1798 2005-10-29 devnull {
192 5cdb1798 2005-10-29 devnull int n;
193 5cdb1798 2005-10-29 devnull char *s, *p, *q;
194 5cdb1798 2005-10-29 devnull char ubuf[128], user[128];
195 5cdb1798 2005-10-29 devnull char buf[500];
196 5cdb1798 2005-10-29 devnull UserPasswd *up;
197 5cdb1798 2005-10-29 devnull
198 5cdb1798 2005-10-29 devnull s = pop3resp(pop);
199 5cdb1798 2005-10-29 devnull if(!isokay(s))
200 5cdb1798 2005-10-29 devnull return "error in initial handshake";
201 5cdb1798 2005-10-29 devnull
202 5cdb1798 2005-10-29 devnull if(pop->user)
203 5cdb1798 2005-10-29 devnull snprint(ubuf, sizeof ubuf, " user=%q", pop->user);
204 5cdb1798 2005-10-29 devnull else
205 5cdb1798 2005-10-29 devnull ubuf[0] = '\0';
206 5cdb1798 2005-10-29 devnull
207 5cdb1798 2005-10-29 devnull // look for apop banner
208 5cdb1798 2005-10-29 devnull if(pop->ppop==0 && (p = strchr(s, '<')) && (q = strchr(p+1, '>'))) {
209 5cdb1798 2005-10-29 devnull *++q = '\0';
210 5cdb1798 2005-10-29 devnull if((n=auth_respond(p, q-p, user, sizeof user, buf, sizeof buf, auth_getkey, "proto=apop role=client server=%q%s",
211 5cdb1798 2005-10-29 devnull pop->host, ubuf)) < 0)
212 5cdb1798 2005-10-29 devnull return "factotum failed";
213 5cdb1798 2005-10-29 devnull if(user[0]=='\0')
214 5cdb1798 2005-10-29 devnull return "factotum did not return a user name";
215 5cdb1798 2005-10-29 devnull
216 5cdb1798 2005-10-29 devnull if(s = pop3capa(pop))
217 5cdb1798 2005-10-29 devnull return s;
218 5cdb1798 2005-10-29 devnull
219 5cdb1798 2005-10-29 devnull pop3cmd(pop, "APOP %s %.*s", user, n, buf);
220 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop)))
221 5cdb1798 2005-10-29 devnull return s;
222 5cdb1798 2005-10-29 devnull
223 5cdb1798 2005-10-29 devnull return nil;
224 5cdb1798 2005-10-29 devnull } else {
225 5cdb1798 2005-10-29 devnull if(pop->ppop == 0)
226 5cdb1798 2005-10-29 devnull return "no APOP hdr from server";
227 5cdb1798 2005-10-29 devnull
228 5cdb1798 2005-10-29 devnull if(s = pop3capa(pop))
229 5cdb1798 2005-10-29 devnull return s;
230 5cdb1798 2005-10-29 devnull
231 5cdb1798 2005-10-29 devnull if(pop->needtls && !pop->encrypted)
232 5cdb1798 2005-10-29 devnull return "could not negotiate TLS";
233 5cdb1798 2005-10-29 devnull
234 5cdb1798 2005-10-29 devnull up = auth_getuserpasswd(auth_getkey, "role=client proto=pass service=pop dom=%q%s",
235 5cdb1798 2005-10-29 devnull pop->host, ubuf);
236 5cdb1798 2005-10-29 devnull /* up = auth_getuserpasswd(auth_getkey, "proto=pass service=pop dom=%q%s",
237 5cdb1798 2005-10-29 devnull pop->host, ubuf); jpc */
238 5cdb1798 2005-10-29 devnull if(up == nil)
239 5cdb1798 2005-10-29 devnull return "no usable keys found";
240 5cdb1798 2005-10-29 devnull
241 5cdb1798 2005-10-29 devnull pop3cmd(pop, "USER %s", up->user);
242 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop))){
243 5cdb1798 2005-10-29 devnull free(up);
244 5cdb1798 2005-10-29 devnull return s;
245 5cdb1798 2005-10-29 devnull }
246 5cdb1798 2005-10-29 devnull pop3cmd(pop, "PASS %s", up->passwd);
247 5cdb1798 2005-10-29 devnull free(up);
248 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop)))
249 5cdb1798 2005-10-29 devnull return s;
250 5cdb1798 2005-10-29 devnull
251 5cdb1798 2005-10-29 devnull return nil;
252 5cdb1798 2005-10-29 devnull }
253 5cdb1798 2005-10-29 devnull }
254 5cdb1798 2005-10-29 devnull
255 5cdb1798 2005-10-29 devnull //
256 5cdb1798 2005-10-29 devnull // dial and handshake with pop server
257 5cdb1798 2005-10-29 devnull //
258 5cdb1798 2005-10-29 devnull static char*
259 5cdb1798 2005-10-29 devnull pop3dial(Pop *pop)
260 5cdb1798 2005-10-29 devnull {
261 5cdb1798 2005-10-29 devnull char *err;
262 5cdb1798 2005-10-29 devnull
263 5cdb1798 2005-10-29 devnull if((pop->fd = dial(netmkaddr(pop->host, "net", pop->needssl ? "pop3s" : "pop3"), 0, 0, 0)) < 0)
264 5cdb1798 2005-10-29 devnull return geterrstr();
265 5cdb1798 2005-10-29 devnull
266 5cdb1798 2005-10-29 devnull if(pop->needssl){
267 5cdb1798 2005-10-29 devnull if((err = pop3pushtls(pop)) != nil)
268 5cdb1798 2005-10-29 devnull return err;
269 5cdb1798 2005-10-29 devnull }else{
270 5cdb1798 2005-10-29 devnull Binit(&pop->bin, pop->fd, OREAD);
271 5cdb1798 2005-10-29 devnull Binit(&pop->bout, pop->fd, OWRITE);
272 5cdb1798 2005-10-29 devnull }
273 5cdb1798 2005-10-29 devnull
274 5cdb1798 2005-10-29 devnull if(err = pop3login(pop)) {
275 5cdb1798 2005-10-29 devnull close(pop->fd);
276 5cdb1798 2005-10-29 devnull return err;
277 5cdb1798 2005-10-29 devnull }
278 5cdb1798 2005-10-29 devnull
279 5cdb1798 2005-10-29 devnull return nil;
280 5cdb1798 2005-10-29 devnull }
281 5cdb1798 2005-10-29 devnull
282 5cdb1798 2005-10-29 devnull //
283 5cdb1798 2005-10-29 devnull // close connection
284 5cdb1798 2005-10-29 devnull //
285 5cdb1798 2005-10-29 devnull static void
286 5cdb1798 2005-10-29 devnull pop3hangup(Pop *pop)
287 5cdb1798 2005-10-29 devnull {
288 5cdb1798 2005-10-29 devnull pop3cmd(pop, "QUIT");
289 5cdb1798 2005-10-29 devnull pop3resp(pop);
290 5cdb1798 2005-10-29 devnull close(pop->fd);
291 5cdb1798 2005-10-29 devnull }
292 5cdb1798 2005-10-29 devnull
293 5cdb1798 2005-10-29 devnull //
294 5cdb1798 2005-10-29 devnull // download a single message
295 5cdb1798 2005-10-29 devnull //
296 5cdb1798 2005-10-29 devnull static char*
297 5cdb1798 2005-10-29 devnull pop3download(Pop *pop, Message *m)
298 5cdb1798 2005-10-29 devnull {
299 5cdb1798 2005-10-29 devnull char *s, *f[3], *wp, *ep;
300 5cdb1798 2005-10-29 devnull char sdigest[SHA1dlen*2+1];
301 5cdb1798 2005-10-29 devnull int i, l, sz;
302 5cdb1798 2005-10-29 devnull
303 5cdb1798 2005-10-29 devnull if(!pop->pipeline)
304 5cdb1798 2005-10-29 devnull pop3cmd(pop, "LIST %d", m->mesgno);
305 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop)))
306 5cdb1798 2005-10-29 devnull return s;
307 5cdb1798 2005-10-29 devnull
308 5cdb1798 2005-10-29 devnull if(tokenize(s, f, 3) != 3)
309 5cdb1798 2005-10-29 devnull return "syntax error in LIST response";
310 5cdb1798 2005-10-29 devnull
311 5cdb1798 2005-10-29 devnull if(atoi(f[1]) != m->mesgno)
312 5cdb1798 2005-10-29 devnull return "out of sync with pop3 server";
313 5cdb1798 2005-10-29 devnull
314 5cdb1798 2005-10-29 devnull sz = atoi(f[2])+200; /* 200 because the plan9 pop3 server lies */
315 5cdb1798 2005-10-29 devnull if(sz == 0)
316 5cdb1798 2005-10-29 devnull return "invalid size in LIST response";
317 5cdb1798 2005-10-29 devnull
318 5cdb1798 2005-10-29 devnull m->start = wp = emalloc(sz+1);
319 5cdb1798 2005-10-29 devnull ep = wp+sz;
320 5cdb1798 2005-10-29 devnull
321 5cdb1798 2005-10-29 devnull if(!pop->pipeline)
322 5cdb1798 2005-10-29 devnull pop3cmd(pop, "RETR %d", m->mesgno);
323 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop))) {
324 5cdb1798 2005-10-29 devnull m->start = nil;
325 5cdb1798 2005-10-29 devnull free(wp);
326 5cdb1798 2005-10-29 devnull return s;
327 5cdb1798 2005-10-29 devnull }
328 5cdb1798 2005-10-29 devnull
329 5cdb1798 2005-10-29 devnull s = nil;
330 5cdb1798 2005-10-29 devnull while(wp <= ep) {
331 5cdb1798 2005-10-29 devnull s = pop3resp(pop);
332 5cdb1798 2005-10-29 devnull if(strcmp(s, "unexpected eof") == 0) {
333 5cdb1798 2005-10-29 devnull free(m->start);
334 5cdb1798 2005-10-29 devnull m->start = nil;
335 5cdb1798 2005-10-29 devnull return "unexpected end of conversation";
336 5cdb1798 2005-10-29 devnull }
337 5cdb1798 2005-10-29 devnull if(strcmp(s, ".") == 0)
338 5cdb1798 2005-10-29 devnull break;
339 5cdb1798 2005-10-29 devnull
340 5cdb1798 2005-10-29 devnull l = strlen(s)+1;
341 5cdb1798 2005-10-29 devnull if(s[0] == '.') {
342 5cdb1798 2005-10-29 devnull s++;
343 5cdb1798 2005-10-29 devnull l--;
344 5cdb1798 2005-10-29 devnull }
345 5cdb1798 2005-10-29 devnull /*
346 5cdb1798 2005-10-29 devnull * grow by 10%/200bytes - some servers
347 5cdb1798 2005-10-29 devnull * lie about message sizes
348 5cdb1798 2005-10-29 devnull */
349 5cdb1798 2005-10-29 devnull if(wp+l > ep) {
350 5cdb1798 2005-10-29 devnull int pos = wp - m->start;
351 5cdb1798 2005-10-29 devnull sz += ((sz / 10) < 200)? 200: sz/10;
352 5cdb1798 2005-10-29 devnull m->start = erealloc(m->start, sz+1);
353 5cdb1798 2005-10-29 devnull wp = m->start+pos;
354 5cdb1798 2005-10-29 devnull ep = m->start+sz;
355 5cdb1798 2005-10-29 devnull }
356 5cdb1798 2005-10-29 devnull memmove(wp, s, l-1);
357 5cdb1798 2005-10-29 devnull wp[l-1] = '\n';
358 5cdb1798 2005-10-29 devnull wp += l;
359 5cdb1798 2005-10-29 devnull }
360 5cdb1798 2005-10-29 devnull
361 5cdb1798 2005-10-29 devnull if(s == nil || strcmp(s, ".") != 0)
362 5cdb1798 2005-10-29 devnull return "out of sync with pop3 server";
363 5cdb1798 2005-10-29 devnull
364 5cdb1798 2005-10-29 devnull m->end = wp;
365 5cdb1798 2005-10-29 devnull
366 5cdb1798 2005-10-29 devnull // make sure there's a trailing null
367 5cdb1798 2005-10-29 devnull // (helps in body searches)
368 5cdb1798 2005-10-29 devnull *m->end = 0;
369 5cdb1798 2005-10-29 devnull m->bend = m->rbend = m->end;
370 5cdb1798 2005-10-29 devnull m->header = m->start;
371 5cdb1798 2005-10-29 devnull
372 5cdb1798 2005-10-29 devnull // digest message
373 5cdb1798 2005-10-29 devnull sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
374 5cdb1798 2005-10-29 devnull for(i = 0; i < SHA1dlen; i++)
375 5cdb1798 2005-10-29 devnull sprint(sdigest+2*i, "%2.2ux", m->digest[i]);
376 5cdb1798 2005-10-29 devnull m->sdigest = s_copy(sdigest);
377 5cdb1798 2005-10-29 devnull
378 5cdb1798 2005-10-29 devnull return nil;
379 5cdb1798 2005-10-29 devnull }
380 5cdb1798 2005-10-29 devnull
381 5cdb1798 2005-10-29 devnull //
382 5cdb1798 2005-10-29 devnull // check for new messages on pop server
383 5cdb1798 2005-10-29 devnull // UIDL is not required by RFC 1939, but
384 5cdb1798 2005-10-29 devnull // netscape requires it, so almost every server supports it.
385 5cdb1798 2005-10-29 devnull // we'll use it to make our lives easier.
386 5cdb1798 2005-10-29 devnull //
387 5cdb1798 2005-10-29 devnull static char*
388 5cdb1798 2005-10-29 devnull pop3read(Pop *pop, Mailbox *mb, int doplumb)
389 5cdb1798 2005-10-29 devnull {
390 5cdb1798 2005-10-29 devnull char *s, *p, *uidl, *f[2];
391 5cdb1798 2005-10-29 devnull int mesgno, ignore, nnew;
392 5cdb1798 2005-10-29 devnull Message *m, *next, **l;
393 5cdb1798 2005-10-29 devnull
394 5cdb1798 2005-10-29 devnull // Some POP servers disallow UIDL if the maildrop is empty.
395 5cdb1798 2005-10-29 devnull pop3cmd(pop, "STAT");
396 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop)))
397 5cdb1798 2005-10-29 devnull return s;
398 5cdb1798 2005-10-29 devnull
399 5cdb1798 2005-10-29 devnull // fetch message listing; note messages to grab
400 5cdb1798 2005-10-29 devnull l = &mb->root->part;
401 5cdb1798 2005-10-29 devnull if(strncmp(s, "+OK 0 ", 6) != 0) {
402 5cdb1798 2005-10-29 devnull pop3cmd(pop, "UIDL");
403 5cdb1798 2005-10-29 devnull if(!isokay(s = pop3resp(pop)))
404 5cdb1798 2005-10-29 devnull return s;
405 5cdb1798 2005-10-29 devnull
406 5cdb1798 2005-10-29 devnull for(;;){
407 5cdb1798 2005-10-29 devnull p = pop3resp(pop);
408 5cdb1798 2005-10-29 devnull if(strcmp(p, ".") == 0 || strcmp(p, "unexpected eof") == 0)
409 5cdb1798 2005-10-29 devnull break;
410 5cdb1798 2005-10-29 devnull
411 5cdb1798 2005-10-29 devnull if(tokenize(p, f, 2) != 2)
412 5cdb1798 2005-10-29 devnull continue;
413 5cdb1798 2005-10-29 devnull
414 5cdb1798 2005-10-29 devnull mesgno = atoi(f[0]);
415 5cdb1798 2005-10-29 devnull uidl = f[1];
416 5cdb1798 2005-10-29 devnull if(strlen(uidl) > 75) // RFC 1939 says 70 characters max
417 5cdb1798 2005-10-29 devnull continue;
418 5cdb1798 2005-10-29 devnull
419 5cdb1798 2005-10-29 devnull ignore = 0;
420 5cdb1798 2005-10-29 devnull while(*l != nil) {
421 5cdb1798 2005-10-29 devnull if(strcmp((*l)->uidl, uidl) == 0) {
422 5cdb1798 2005-10-29 devnull // matches mail we already have, note mesgno for deletion
423 5cdb1798 2005-10-29 devnull (*l)->mesgno = mesgno;
424 5cdb1798 2005-10-29 devnull ignore = 1;
425 5cdb1798 2005-10-29 devnull l = &(*l)->next;
426 5cdb1798 2005-10-29 devnull break;
427 5cdb1798 2005-10-29 devnull } else {
428 5cdb1798 2005-10-29 devnull // old mail no longer in box mark deleted
429 5cdb1798 2005-10-29 devnull if(doplumb)
430 5cdb1798 2005-10-29 devnull mailplumb(mb, *l, 1);
431 5cdb1798 2005-10-29 devnull (*l)->inmbox = 0;
432 5cdb1798 2005-10-29 devnull (*l)->deleted = 1;
433 5cdb1798 2005-10-29 devnull l = &(*l)->next;
434 5cdb1798 2005-10-29 devnull }
435 5cdb1798 2005-10-29 devnull }
436 5cdb1798 2005-10-29 devnull if(ignore)
437 5cdb1798 2005-10-29 devnull continue;
438 5cdb1798 2005-10-29 devnull
439 5cdb1798 2005-10-29 devnull m = newmessage(mb->root);
440 5cdb1798 2005-10-29 devnull m->mallocd = 1;
441 5cdb1798 2005-10-29 devnull m->inmbox = 1;
442 5cdb1798 2005-10-29 devnull m->mesgno = mesgno;
443 5cdb1798 2005-10-29 devnull strcpy(m->uidl, uidl);
444 5cdb1798 2005-10-29 devnull
445 5cdb1798 2005-10-29 devnull // chain in; will fill in message later
446 5cdb1798 2005-10-29 devnull *l = m;
447 5cdb1798 2005-10-29 devnull l = &m->next;
448 5cdb1798 2005-10-29 devnull }
449 5cdb1798 2005-10-29 devnull }
450 5cdb1798 2005-10-29 devnull
451 5cdb1798 2005-10-29 devnull // whatever is left has been removed from the mbox, mark as deleted
452 5cdb1798 2005-10-29 devnull while(*l != nil) {
453 5cdb1798 2005-10-29 devnull if(doplumb)
454 5cdb1798 2005-10-29 devnull mailplumb(mb, *l, 1);
455 5cdb1798 2005-10-29 devnull (*l)->inmbox = 0;
456 5cdb1798 2005-10-29 devnull (*l)->deleted = 1;
457 5cdb1798 2005-10-29 devnull l = &(*l)->next;
458 5cdb1798 2005-10-29 devnull }
459 5cdb1798 2005-10-29 devnull
460 5cdb1798 2005-10-29 devnull // download new messages
461 5cdb1798 2005-10-29 devnull nnew = 0;
462 5cdb1798 2005-10-29 devnull if(pop->pipeline){
463 5cdb1798 2005-10-29 devnull switch(rfork(RFPROC|RFMEM)){
464 5cdb1798 2005-10-29 devnull case -1:
465 5cdb1798 2005-10-29 devnull fprint(2, "rfork: %r\n");
466 5cdb1798 2005-10-29 devnull pop->pipeline = 0;
467 5cdb1798 2005-10-29 devnull
468 5cdb1798 2005-10-29 devnull default:
469 5cdb1798 2005-10-29 devnull break;
470 5cdb1798 2005-10-29 devnull
471 5cdb1798 2005-10-29 devnull case 0:
472 5cdb1798 2005-10-29 devnull for(m = mb->root->part; m != nil; m = m->next){
473 5cdb1798 2005-10-29 devnull if(m->start != nil)
474 5cdb1798 2005-10-29 devnull continue;
475 5cdb1798 2005-10-29 devnull Bprint(&pop->bout, "LIST %d\r\nRETR %d\r\n", m->mesgno, m->mesgno);
476 5cdb1798 2005-10-29 devnull }
477 5cdb1798 2005-10-29 devnull Bflush(&pop->bout);
478 5cdb1798 2005-10-29 devnull threadexits(nil);
479 5cdb1798 2005-10-29 devnull /* _exits(nil); jpc */
480 5cdb1798 2005-10-29 devnull }
481 5cdb1798 2005-10-29 devnull }
482 5cdb1798 2005-10-29 devnull
483 5cdb1798 2005-10-29 devnull for(m = mb->root->part; m != nil; m = next) {
484 5cdb1798 2005-10-29 devnull next = m->next;
485 5cdb1798 2005-10-29 devnull
486 5cdb1798 2005-10-29 devnull if(m->start != nil)
487 5cdb1798 2005-10-29 devnull continue;
488 5cdb1798 2005-10-29 devnull
489 5cdb1798 2005-10-29 devnull if(s = pop3download(pop, m)) {
490 5cdb1798 2005-10-29 devnull // message disappeared? unchain
491 5cdb1798 2005-10-29 devnull fprint(2, "download %d: %s\n", m->mesgno, s);
492 5cdb1798 2005-10-29 devnull delmessage(mb, m);
493 5cdb1798 2005-10-29 devnull mb->root->subname--;
494 5cdb1798 2005-10-29 devnull continue;
495 5cdb1798 2005-10-29 devnull }
496 5cdb1798 2005-10-29 devnull nnew++;
497 5cdb1798 2005-10-29 devnull parse(m, 0, mb, 1);
498 5cdb1798 2005-10-29 devnull
499 5cdb1798 2005-10-29 devnull if(doplumb)
500 5cdb1798 2005-10-29 devnull mailplumb(mb, m, 0);
501 5cdb1798 2005-10-29 devnull }
502 5cdb1798 2005-10-29 devnull if(pop->pipeline)
503 5cdb1798 2005-10-29 devnull waitpid();
504 5cdb1798 2005-10-29 devnull
505 5cdb1798 2005-10-29 devnull if(nnew || mb->vers == 0) {
506 5cdb1798 2005-10-29 devnull mb->vers++;
507 5cdb1798 2005-10-29 devnull henter(PATH(0, Qtop), mb->name,
508 5cdb1798 2005-10-29 devnull (Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
509 5cdb1798 2005-10-29 devnull }
510 5cdb1798 2005-10-29 devnull
511 5cdb1798 2005-10-29 devnull return nil;
512 5cdb1798 2005-10-29 devnull }
513 5cdb1798 2005-10-29 devnull
514 5cdb1798 2005-10-29 devnull //
515 5cdb1798 2005-10-29 devnull // delete marked messages
516 5cdb1798 2005-10-29 devnull //
517 5cdb1798 2005-10-29 devnull static void
518 5cdb1798 2005-10-29 devnull pop3purge(Pop *pop, Mailbox *mb)
519 5cdb1798 2005-10-29 devnull {
520 5cdb1798 2005-10-29 devnull Message *m, *next;
521 5cdb1798 2005-10-29 devnull
522 5cdb1798 2005-10-29 devnull if(pop->pipeline){
523 5cdb1798 2005-10-29 devnull switch(rfork(RFPROC|RFMEM)){
524 5cdb1798 2005-10-29 devnull case -1:
525 5cdb1798 2005-10-29 devnull fprint(2, "rfork: %r\n");
526 5cdb1798 2005-10-29 devnull pop->pipeline = 0;
527 5cdb1798 2005-10-29 devnull
528 5cdb1798 2005-10-29 devnull default:
529 5cdb1798 2005-10-29 devnull break;
530 5cdb1798 2005-10-29 devnull
531 5cdb1798 2005-10-29 devnull case 0:
532 5cdb1798 2005-10-29 devnull for(m = mb->root->part; m != nil; m = next){
533 5cdb1798 2005-10-29 devnull next = m->next;
534 5cdb1798 2005-10-29 devnull if(m->deleted && m->refs == 0){
535 5cdb1798 2005-10-29 devnull if(m->inmbox)
536 5cdb1798 2005-10-29 devnull Bprint(&pop->bout, "DELE %d\r\n", m->mesgno);
537 5cdb1798 2005-10-29 devnull }
538 5cdb1798 2005-10-29 devnull }
539 5cdb1798 2005-10-29 devnull Bflush(&pop->bout);
540 5cdb1798 2005-10-29 devnull /* _exits(nil); jpc */
541 5cdb1798 2005-10-29 devnull threadexits(nil);
542 5cdb1798 2005-10-29 devnull }
543 5cdb1798 2005-10-29 devnull }
544 5cdb1798 2005-10-29 devnull for(m = mb->root->part; m != nil; m = next) {
545 5cdb1798 2005-10-29 devnull next = m->next;
546 5cdb1798 2005-10-29 devnull if(m->deleted && m->refs == 0) {
547 5cdb1798 2005-10-29 devnull if(m->inmbox) {
548 5cdb1798 2005-10-29 devnull if(!pop->pipeline)
549 5cdb1798 2005-10-29 devnull pop3cmd(pop, "DELE %d", m->mesgno);
550 5cdb1798 2005-10-29 devnull if(isokay(pop3resp(pop)))
551 5cdb1798 2005-10-29 devnull delmessage(mb, m);
552 5cdb1798 2005-10-29 devnull } else
553 5cdb1798 2005-10-29 devnull delmessage(mb, m);
554 5cdb1798 2005-10-29 devnull }
555 5cdb1798 2005-10-29 devnull }
556 5cdb1798 2005-10-29 devnull }
557 5cdb1798 2005-10-29 devnull
558 5cdb1798 2005-10-29 devnull
559 5cdb1798 2005-10-29 devnull // connect to pop3 server, sync mailbox
560 5cdb1798 2005-10-29 devnull static char*
561 5cdb1798 2005-10-29 devnull pop3sync(Mailbox *mb, int doplumb)
562 5cdb1798 2005-10-29 devnull {
563 5cdb1798 2005-10-29 devnull char *err;
564 5cdb1798 2005-10-29 devnull Pop *pop;
565 5cdb1798 2005-10-29 devnull
566 5cdb1798 2005-10-29 devnull pop = mb->aux;
567 5cdb1798 2005-10-29 devnull
568 5cdb1798 2005-10-29 devnull if(err = pop3dial(pop)) {
569 5cdb1798 2005-10-29 devnull mb->waketime = time(0) + pop->refreshtime;
570 5cdb1798 2005-10-29 devnull return err;
571 5cdb1798 2005-10-29 devnull }
572 5cdb1798 2005-10-29 devnull
573 5cdb1798 2005-10-29 devnull if((err = pop3read(pop, mb, doplumb)) == nil){
574 5cdb1798 2005-10-29 devnull pop3purge(pop, mb);
575 5cdb1798 2005-10-29 devnull mb->d->atime = mb->d->mtime = time(0);
576 5cdb1798 2005-10-29 devnull }
577 5cdb1798 2005-10-29 devnull pop3hangup(pop);
578 5cdb1798 2005-10-29 devnull mb->waketime = time(0) + pop->refreshtime;
579 5cdb1798 2005-10-29 devnull return err;
580 5cdb1798 2005-10-29 devnull }
581 5cdb1798 2005-10-29 devnull
582 5cdb1798 2005-10-29 devnull static char Epop3ctl[] = "bad pop3 control message";
583 5cdb1798 2005-10-29 devnull
584 5cdb1798 2005-10-29 devnull static char*
585 5cdb1798 2005-10-29 devnull pop3ctl(Mailbox *mb, int argc, char **argv)
586 5cdb1798 2005-10-29 devnull {
587 5cdb1798 2005-10-29 devnull int n;
588 5cdb1798 2005-10-29 devnull Pop *pop;
589 5cdb1798 2005-10-29 devnull char *m, *me;
590 5cdb1798 2005-10-29 devnull
591 5cdb1798 2005-10-29 devnull pop = mb->aux;
592 5cdb1798 2005-10-29 devnull if(argc < 1)
593 5cdb1798 2005-10-29 devnull return Epop3ctl;
594 5cdb1798 2005-10-29 devnull
595 5cdb1798 2005-10-29 devnull if(argc==1 && strcmp(argv[0], "debug")==0){
596 5cdb1798 2005-10-29 devnull pop->debug = 1;
597 5cdb1798 2005-10-29 devnull return nil;
598 5cdb1798 2005-10-29 devnull }
599 5cdb1798 2005-10-29 devnull
600 5cdb1798 2005-10-29 devnull if(argc==1 && strcmp(argv[0], "nodebug")==0){
601 5cdb1798 2005-10-29 devnull pop->debug = 0;
602 5cdb1798 2005-10-29 devnull return nil;
603 5cdb1798 2005-10-29 devnull }
604 5cdb1798 2005-10-29 devnull
605 5cdb1798 2005-10-29 devnull if(argc==1 && strcmp(argv[0], "thumbprint")==0){
606 5cdb1798 2005-10-29 devnull if(pop->thumb)
607 5cdb1798 2005-10-29 devnull freeThumbprints(pop->thumb);
608 5cdb1798 2005-10-29 devnull /* pop->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude"); jpc */
609 5cdb1798 2005-10-29 devnull m = unsharp("#9/sys/lib/tls/mail");
610 5cdb1798 2005-10-29 devnull me = unsharp("#9/sys/lib/tls/mail.exclude");
611 5cdb1798 2005-10-29 devnull pop->thumb = initThumbprints(m, me);
612 5cdb1798 2005-10-29 devnull }
613 5cdb1798 2005-10-29 devnull if(strcmp(argv[0], "refresh")==0){
614 5cdb1798 2005-10-29 devnull if(argc==1){
615 5cdb1798 2005-10-29 devnull pop->refreshtime = 60;
616 5cdb1798 2005-10-29 devnull return nil;
617 5cdb1798 2005-10-29 devnull }
618 5cdb1798 2005-10-29 devnull if(argc==2){
619 5cdb1798 2005-10-29 devnull n = atoi(argv[1]);
620 5cdb1798 2005-10-29 devnull if(n < 15)
621 5cdb1798 2005-10-29 devnull return Epop3ctl;
622 5cdb1798 2005-10-29 devnull pop->refreshtime = n;
623 5cdb1798 2005-10-29 devnull return nil;
624 5cdb1798 2005-10-29 devnull }
625 5cdb1798 2005-10-29 devnull }
626 5cdb1798 2005-10-29 devnull
627 5cdb1798 2005-10-29 devnull return Epop3ctl;
628 5cdb1798 2005-10-29 devnull }
629 5cdb1798 2005-10-29 devnull
630 5cdb1798 2005-10-29 devnull // free extra memory associated with mb
631 5cdb1798 2005-10-29 devnull static void
632 5cdb1798 2005-10-29 devnull pop3close(Mailbox *mb)
633 5cdb1798 2005-10-29 devnull {
634 5cdb1798 2005-10-29 devnull Pop *pop;
635 5cdb1798 2005-10-29 devnull
636 5cdb1798 2005-10-29 devnull pop = mb->aux;
637 5cdb1798 2005-10-29 devnull free(pop->freep);
638 5cdb1798 2005-10-29 devnull free(pop);
639 5cdb1798 2005-10-29 devnull }
640 5cdb1798 2005-10-29 devnull
641 5cdb1798 2005-10-29 devnull //
642 5cdb1798 2005-10-29 devnull // open mailboxes of the form /pop/host/user or /apop/host/user
643 5cdb1798 2005-10-29 devnull //
644 5cdb1798 2005-10-29 devnull char*
645 5cdb1798 2005-10-29 devnull pop3mbox(Mailbox *mb, char *path)
646 5cdb1798 2005-10-29 devnull {
647 5cdb1798 2005-10-29 devnull char *f[10];
648 5cdb1798 2005-10-29 devnull int nf, apop, ppop, popssl, apopssl, apoptls, popnotls, apopnotls, poptls;
649 5cdb1798 2005-10-29 devnull Pop *pop;
650 5cdb1798 2005-10-29 devnull char *m, *me;
651 5cdb1798 2005-10-29 devnull
652 5cdb1798 2005-10-29 devnull quotefmtinstall();
653 5cdb1798 2005-10-29 devnull popssl = strncmp(path, "/pops/", 6) == 0;
654 5cdb1798 2005-10-29 devnull apopssl = strncmp(path, "/apops/", 7) == 0;
655 5cdb1798 2005-10-29 devnull poptls = strncmp(path, "/poptls/", 8) == 0;
656 5cdb1798 2005-10-29 devnull popnotls = strncmp(path, "/popnotls/", 10) == 0;
657 5cdb1798 2005-10-29 devnull ppop = popssl || poptls || popnotls || strncmp(path, "/pop/", 5) == 0;
658 5cdb1798 2005-10-29 devnull apoptls = strncmp(path, "/apoptls/", 9) == 0;
659 5cdb1798 2005-10-29 devnull apopnotls = strncmp(path, "/apopnotls/", 11) == 0;
660 5cdb1798 2005-10-29 devnull apop = apopssl || apoptls || apopnotls || strncmp(path, "/apop/", 6) == 0;
661 5cdb1798 2005-10-29 devnull
662 5cdb1798 2005-10-29 devnull if(!ppop && !apop)
663 5cdb1798 2005-10-29 devnull return Enotme;
664 5cdb1798 2005-10-29 devnull
665 5cdb1798 2005-10-29 devnull path = strdup(path);
666 5cdb1798 2005-10-29 devnull if(path == nil)
667 5cdb1798 2005-10-29 devnull return "out of memory";
668 5cdb1798 2005-10-29 devnull
669 5cdb1798 2005-10-29 devnull nf = getfields(path, f, nelem(f), 0, "/");
670 5cdb1798 2005-10-29 devnull if(nf != 3 && nf != 4) {
671 5cdb1798 2005-10-29 devnull free(path);
672 5cdb1798 2005-10-29 devnull return "bad pop3 path syntax /[a]pop[tls|ssl]/system[/user]";
673 5cdb1798 2005-10-29 devnull }
674 5cdb1798 2005-10-29 devnull
675 5cdb1798 2005-10-29 devnull pop = emalloc(sizeof(*pop));
676 5cdb1798 2005-10-29 devnull pop->freep = path;
677 5cdb1798 2005-10-29 devnull pop->host = f[2];
678 5cdb1798 2005-10-29 devnull if(nf < 4)
679 5cdb1798 2005-10-29 devnull pop->user = nil;
680 5cdb1798 2005-10-29 devnull else
681 5cdb1798 2005-10-29 devnull pop->user = f[3];
682 5cdb1798 2005-10-29 devnull pop->ppop = ppop;
683 5cdb1798 2005-10-29 devnull pop->needssl = popssl || apopssl;
684 5cdb1798 2005-10-29 devnull pop->needtls = poptls || apoptls;
685 5cdb1798 2005-10-29 devnull pop->refreshtime = 60;
686 5cdb1798 2005-10-29 devnull pop->notls = popnotls || apopnotls;
687 5cdb1798 2005-10-29 devnull /* pop->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude"); jpc */
688 5cdb1798 2005-10-29 devnull m = unsharp("#9/sys/lib/tls/mail");
689 5cdb1798 2005-10-29 devnull me = unsharp("#9/sys/lib/tls/mail.exclude");
690 5cdb1798 2005-10-29 devnull pop->thumb = initThumbprints(m, me);
691 5cdb1798 2005-10-29 devnull
692 5cdb1798 2005-10-29 devnull mb->aux = pop;
693 5cdb1798 2005-10-29 devnull mb->sync = pop3sync;
694 5cdb1798 2005-10-29 devnull mb->close = pop3close;
695 5cdb1798 2005-10-29 devnull mb->ctl = pop3ctl;
696 5cdb1798 2005-10-29 devnull mb->d = emalloc(sizeof(*mb->d));
697 5cdb1798 2005-10-29 devnull
698 5cdb1798 2005-10-29 devnull return nil;
699 5cdb1798 2005-10-29 devnull }
700 5cdb1798 2005-10-29 devnull