1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
3 *
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * Copyright (c) 2002
8 * Gunnar Ritter. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Gunnar Ritter
21 * and his contributors.
22 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 #ifdef DOSCCS
41 static char sccsid[] = "@(#)pop3.c 2.43 (gritter) 3/4/06";
42 #endif
43 #endif /* not lint */
44
45 #include "config.h"
46
47 #include "rcv.h"
48 #include "extern.h"
49 #include <errno.h>
50 #include <sys/stat.h>
51 #include <unistd.h>
52 #include <time.h>
53
54 #include "md5.h"
55
56 /*
57 * Mail -- a mail program
58 *
59 * POP3 client.
60 */
61
62 #ifdef HAVE_SOCKETS
63 static int verbose;
64
65 #define POP3_ANSWER() if (pop3_answer(mp) == STOP) \
66 return STOP;
67 #define POP3_OUT(x, y) if (pop3_finish(mp) == STOP) \
68 return STOP; \
69 if (verbose) \
70 fprintf(stderr, ">>> %s", x); \
71 mp->mb_active |= (y); \
72 if (swrite(&mp->mb_sock, x) == STOP) \
73 return STOP;
74
75 static char *pop3buf;
76 static size_t pop3bufsize;
77 static sigjmp_buf pop3jmp;
78 static sighandler_type savealrm;
79 static int reset_tio;
80 static struct termios otio;
81 static int pop3keepalive;
82 static volatile int pop3lock;
83
84 static void pop3_timer_off(void);
85 static enum okay pop3_answer(struct mailbox *mp);
86 static enum okay pop3_finish(struct mailbox *mp);
87 static void pop3catch(int s);
88 static void maincatch(int s);
89 static enum okay pop3_noop1(struct mailbox *mp);
90 static void pop3alarm(int s);
91 static enum okay pop3_pass(struct mailbox *mp, const char *pass);
92 static char *pop3_find_timestamp(const char *bp);
93 static enum okay pop3_apop(struct mailbox *mp, char *xuser, const char *pass,
94 const char *ts);
95 static enum okay pop3_apop1(struct mailbox *mp,
96 const char *user, const char *xp);
97 static int pop3_use_starttls(const char *uhp);
98 static int pop3_use_apop(const char *uhp);
99 static enum okay pop3_user(struct mailbox *mp, char *xuser, const char *pass,
100 const char *uhp, const char *xserver);
101 static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *count);
102 static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
103 static void pop3_init(struct mailbox *mp, int n);
104 static void pop3_dates(struct mailbox *mp);
105 static void pop3_setptr(struct mailbox *mp);
106 static char *pop3_have_password(const char *server);
107 static enum okay pop3_get(struct mailbox *mp, struct message *m,
108 enum needspec need);
109 static enum okay pop3_exit(struct mailbox *mp);
110 static enum okay pop3_delete(struct mailbox *mp, int n);
111 static enum okay pop3_update(struct mailbox *mp);
112
113 static void
pop3_timer_off(void)114 pop3_timer_off(void)
115 {
116 if (pop3keepalive > 0) {
117 alarm(0);
118 safe_signal(SIGALRM, savealrm);
119 }
120 }
121
122 static enum okay
pop3_answer(struct mailbox * mp)123 pop3_answer(struct mailbox *mp)
124 {
125 int sz;
126 enum okay ok = STOP;
127
128 retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
129 if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
130 goto multiline;
131 if (verbose)
132 fputs(pop3buf, stderr);
133 switch (*pop3buf) {
134 case '+':
135 ok = OKAY;
136 mp->mb_active &= ~MB_COMD;
137 break;
138 case '-':
139 ok = STOP;
140 mp->mb_active = MB_NONE;
141 fprintf(stderr, catgets(catd, CATSET, 218,
142 "POP3 error: %s"), pop3buf);
143 break;
144 default:
145 /*
146 * If the answer starts neither with '+' nor with
147 * '-', it must be part of a multiline response,
148 * e. g. because the user interrupted a file
149 * download. Get lines until a single dot appears.
150 */
151 multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
152 pop3buf[2] != '\n' ||
153 pop3buf[3] != '\0') {
154 sz = sgetline(&pop3buf, &pop3bufsize,
155 NULL, &mp->mb_sock);
156 if (sz <= 0)
157 goto eof;
158 }
159 mp->mb_active &= ~MB_MULT;
160 if (mp->mb_active != MB_NONE)
161 goto retry;
162 }
163 } else {
164 eof: ok = STOP;
165 mp->mb_active = MB_NONE;
166 }
167 return ok;
168 }
169
170 static enum okay
pop3_finish(struct mailbox * mp)171 pop3_finish(struct mailbox *mp)
172 {
173 while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
174 pop3_answer(mp);
175 return OKAY;
176 }
177
178 static void
pop3catch(int s)179 pop3catch(int s)
180 {
181 if (reset_tio)
182 tcsetattr(0, TCSADRAIN, &otio);
183 switch (s) {
184 case SIGINT:
185 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
186 siglongjmp(pop3jmp, 1);
187 break;
188 case SIGPIPE:
189 fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
190 break;
191 }
192 }
193
194 static void
maincatch(int s)195 maincatch(int s)
196 {
197 if (interrupts++ == 0) {
198 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
199 return;
200 }
201 onintr(0);
202 }
203
204 static enum okay
pop3_noop1(struct mailbox * mp)205 pop3_noop1(struct mailbox *mp)
206 {
207 POP3_OUT("NOOP\r\n", MB_COMD)
208 POP3_ANSWER()
209 return OKAY;
210 }
211
212 enum okay
pop3_noop(void)213 pop3_noop(void)
214 {
215 enum okay ok = STOP;
216 sighandler_type saveint, savepipe;
217
218 (void)&saveint;
219 (void)&savepipe;
220 (void)&ok;
221 verbose = value("verbose") != NULL;
222 pop3lock = 1;
223 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
224 safe_signal(SIGINT, maincatch);
225 savepipe = safe_signal(SIGPIPE, SIG_IGN);
226 if (sigsetjmp(pop3jmp, 1) == 0) {
227 if (savepipe != SIG_IGN)
228 safe_signal(SIGPIPE, pop3catch);
229 ok = pop3_noop1(&mb);
230 }
231 safe_signal(SIGINT, saveint);
232 safe_signal(SIGPIPE, savepipe);
233 pop3lock = 0;
234 return ok;
235 }
236
237 /*ARGSUSED*/
238 static void
pop3alarm(int s)239 pop3alarm(int s)
240 {
241 sighandler_type saveint;
242 sighandler_type savepipe;
243
244 if (pop3lock++ == 0) {
245 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
246 safe_signal(SIGINT, maincatch);
247 savepipe = safe_signal(SIGPIPE, SIG_IGN);
248 if (sigsetjmp(pop3jmp, 1)) {
249 safe_signal(SIGINT, saveint);
250 safe_signal(SIGPIPE, savepipe);
251 goto brk;
252 }
253 if (savepipe != SIG_IGN)
254 safe_signal(SIGPIPE, pop3catch);
255 if (pop3_noop1(&mb) != OKAY) {
256 safe_signal(SIGINT, saveint);
257 safe_signal(SIGPIPE, savepipe);
258 goto out;
259 }
260 safe_signal(SIGINT, saveint);
261 safe_signal(SIGPIPE, savepipe);
262 }
263 brk: alarm(pop3keepalive);
264 out: pop3lock--;
265 }
266
267 static enum okay
pop3_pass(struct mailbox * mp,const char * pass)268 pop3_pass(struct mailbox *mp, const char *pass)
269 {
270 char o[LINESIZE];
271
272 snprintf(o, sizeof o, "PASS %s\r\n", pass);
273 POP3_OUT(o, MB_COMD)
274 POP3_ANSWER()
275 return OKAY;
276 }
277
278 static char *
pop3_find_timestamp(const char * bp)279 pop3_find_timestamp(const char *bp)
280 {
281 const char *cp, *ep;
282 char *rp;
283 int hadat = 0;
284
285 if ((cp = strchr(bp, '<')) == NULL)
286 return NULL;
287 for (ep = cp; *ep; ep++) {
288 if (spacechar(*ep&0377))
289 return NULL;
290 else if (*ep == '@')
291 hadat = 1;
292 else if (*ep == '>') {
293 if (hadat != 1)
294 return NULL;
295 break;
296 }
297 }
298 if (*ep != '>')
299 return NULL;
300 rp = salloc(ep - cp + 2);
301 memcpy(rp, cp, ep - cp + 1);
302 rp[ep - cp + 1] = '\0';
303 return rp;
304 }
305
306 static enum okay
pop3_apop(struct mailbox * mp,char * xuser,const char * pass,const char * ts)307 pop3_apop(struct mailbox *mp, char *xuser, const char *pass, const char *ts)
308 {
309 char *user, *catp, *xp;
310 unsigned char digest[16];
311 MD5_CTX ctx;
312
313 retry: if (xuser == NULL) {
314 if ((user = getuser()) == NULL)
315 return STOP;
316 } else
317 user = xuser;
318 if (pass == NULL) {
319 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
320 return STOP;
321 }
322 catp = savecat(ts, pass);
323 MD5Init(&ctx);
324 MD5Update(&ctx, (unsigned char *)catp, strlen(catp));
325 MD5Final(digest, &ctx);
326 xp = md5tohex(digest);
327 if (pop3_apop1(mp, user, xp) == STOP) {
328 pass = NULL;
329 goto retry;
330 }
331 return OKAY;
332 }
333
334 static enum okay
pop3_apop1(struct mailbox * mp,const char * user,const char * xp)335 pop3_apop1(struct mailbox *mp, const char *user, const char *xp)
336 {
337 char o[LINESIZE];
338
339 snprintf(o, sizeof o, "APOP %s %s\r\n", user, xp);
340 POP3_OUT(o, MB_COMD)
341 POP3_ANSWER()
342 return OKAY;
343 }
344
345 static int
pop3_use_starttls(const char * uhp)346 pop3_use_starttls(const char *uhp)
347 {
348 char *var;
349
350 if (value("pop3-use-starttls"))
351 return 1;
352 var = savecat("pop3-use-starttls-", uhp);
353 return value(var) != NULL;
354 }
355
356 static int
pop3_use_apop(const char * uhp)357 pop3_use_apop(const char *uhp)
358 {
359 char *var;
360
361 if (value("pop3-use-apop"))
362 return 1;
363 var = savecat("pop3-use-apop-", uhp);
364 return value(var) != NULL;
365 }
366
367 static enum okay
pop3_user(struct mailbox * mp,char * xuser,const char * pass,const char * uhp,const char * xserver)368 pop3_user(struct mailbox *mp, char *xuser, const char *pass,
369 const char *uhp, const char *xserver)
370 {
371 char o[LINESIZE], *user, *ts = NULL, *server, *cp;
372
373 POP3_ANSWER()
374 if (pop3_use_apop(uhp)) {
375 if ((ts = pop3_find_timestamp(pop3buf)) == NULL) {
376 fprintf(stderr, "Could not determine timestamp from "
377 "server greeting. Impossible to use APOP.\n");
378 return STOP;
379 }
380 }
381 if ((cp = strchr(xserver, ':')) != NULL) {
382 server = salloc(cp - xserver + 1);
383 memcpy(server, xserver, cp - xserver);
384 server[cp - xserver] = '\0';
385 } else
386 server = (char *)xserver;
387 #ifdef USE_SSL
388 if (mp->mb_sock.s_use_ssl == 0 && pop3_use_starttls(uhp)) {
389 POP3_OUT("STLS\r\n", MB_COMD)
390 POP3_ANSWER()
391 if (ssl_open(server, &mp->mb_sock, uhp) != OKAY)
392 return STOP;
393 }
394 #else /* !USE_SSL */
395 if (pop3_use_starttls(uhp)) {
396 fprintf(stderr, "No SSL support compiled in.\n");
397 return STOP;
398 }
399 #endif /* !USE_SSL */
400 if (ts != NULL)
401 return pop3_apop(mp, xuser, pass, ts);
402 retry: if (xuser == NULL) {
403 if ((user = getuser()) == NULL)
404 return STOP;
405 } else
406 user = xuser;
407 snprintf(o, sizeof o, "USER %s\r\n", user);
408 POP3_OUT(o, MB_COMD)
409 POP3_ANSWER()
410 if (pass == NULL) {
411 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
412 return STOP;
413 }
414 if (pop3_pass(mp, pass) == STOP) {
415 pass = NULL;
416 goto retry;
417 }
418 return OKAY;
419 }
420
421 static enum okay
pop3_stat(struct mailbox * mp,off_t * size,int * count)422 pop3_stat(struct mailbox *mp, off_t *size, int *count)
423 {
424 char *cp;
425 enum okay ok = OKAY;
426
427 POP3_OUT("STAT\r\n", MB_COMD);
428 POP3_ANSWER()
429 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
430 while (*cp && spacechar(*cp & 0377))
431 cp++;
432 if (*cp) {
433 *count = (int)strtol(cp, NULL, 10);
434 while (*cp && !spacechar(*cp & 0377))
435 cp++;
436 while (*cp && spacechar(*cp & 0377))
437 cp++;
438 if (*cp)
439 *size = (int)strtol(cp, NULL, 10);
440 else
441 ok = STOP;
442 } else
443 ok = STOP;
444 if (ok == STOP)
445 fprintf(stderr, catgets(catd, CATSET, 260,
446 "invalid POP3 STAT response: %s\n"), pop3buf);
447 return ok;
448 }
449
450 static enum okay
pop3_list(struct mailbox * mp,int n,size_t * size)451 pop3_list(struct mailbox *mp, int n, size_t *size)
452 {
453 char o[LINESIZE], *cp;
454
455 snprintf(o, sizeof o, "LIST %u\r\n", n);
456 POP3_OUT(o, MB_COMD)
457 POP3_ANSWER()
458 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
459 while (*cp && spacechar(*cp & 0377))
460 cp++;
461 while (*cp && !spacechar(*cp & 0377))
462 cp++;
463 while (*cp && spacechar(*cp & 0377))
464 cp++;
465 if (*cp)
466 *size = (size_t)strtol(cp, NULL, 10);
467 else
468 *size = 0;
469 return OKAY;
470 }
471
472 static void
pop3_init(struct mailbox * mp,int n)473 pop3_init(struct mailbox *mp, int n)
474 {
475 struct message *m = &message[n];
476 char *cp;
477
478 m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
479 m->m_block = 0;
480 m->m_offset = 0;
481 pop3_list(mp, m - message + 1, &m->m_xsize);
482 if ((cp = hfield("status", m)) != NULL) {
483 while (*cp != '\0') {
484 if (*cp == 'R')
485 m->m_flag |= MREAD;
486 else if (*cp == 'O')
487 m->m_flag &= ~MNEW;
488 cp++;
489 }
490 }
491 }
492
493 /*ARGSUSED*/
494 static void
pop3_dates(struct mailbox * mp)495 pop3_dates(struct mailbox *mp)
496 {
497 int i;
498
499 for (i = 0; i < msgCount; i++)
500 substdate(&message[i]);
501 }
502
503 static void
pop3_setptr(struct mailbox * mp)504 pop3_setptr(struct mailbox *mp)
505 {
506 int i;
507
508 message = scalloc(msgCount + 1, sizeof *message);
509 for (i = 0; i < msgCount; i++)
510 pop3_init(mp, i);
511 setdot(message);
512 message[msgCount].m_size = 0;
513 message[msgCount].m_lines = 0;
514 pop3_dates(mp);
515 }
516
517 static char *
pop3_have_password(const char * server)518 pop3_have_password(const char *server)
519 {
520 char *var, *cp;
521
522 var = ac_alloc(strlen(server) + 10);
523 strcpy(var, "password-");
524 strcpy(&var[9], server);
525 if ((cp = value(var)) != NULL)
526 cp = savestr(cp);
527 ac_free(var);
528 return cp;
529 }
530
531 int
pop3_setfile(const char * server,int newmail,int isedit)532 pop3_setfile(const char *server, int newmail, int isedit)
533 {
534 struct sock so;
535 sighandler_type saveint;
536 sighandler_type savepipe;
537 char *user;
538 const char *cp, *sp = server, *pass, *uhp;
539 int use_ssl = 0;
540
541 (void)&sp;
542 (void)&use_ssl;
543 (void)&user;
544 if (newmail)
545 return 1;
546 if (strncmp(sp, "pop3://", 7) == 0) {
547 sp = &sp[7];
548 use_ssl = 0;
549 #ifdef USE_SSL
550 } else if (strncmp(sp, "pop3s://", 8) == 0) {
551 sp = &sp[8];
552 use_ssl = 1;
553 #endif /* USE_SSL */
554 }
555 uhp = sp;
556 pass = pop3_have_password(uhp);
557 if ((cp = last_at_before_slash(sp)) != NULL) {
558 user = salloc(cp - sp + 1);
559 memcpy(user, sp, cp - sp);
560 user[cp - sp] = '\0';
561 sp = &cp[1];
562 user = strdec(user);
563 } else
564 user = NULL;
565 verbose = value("verbose") != NULL;
566 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
567 verbose) != OKAY) {
568 return -1;
569 }
570 quit();
571 edit = isedit;
572 if (mb.mb_sock.s_fd >= 0)
573 sclose(&mb.mb_sock);
574 if (mb.mb_itf) {
575 fclose(mb.mb_itf);
576 mb.mb_itf = NULL;
577 }
578 if (mb.mb_otf) {
579 fclose(mb.mb_otf);
580 mb.mb_otf = NULL;
581 }
582 initbox(server);
583 mb.mb_type = MB_VOID;
584 pop3lock = 1;
585 mb.mb_sock = so;
586 saveint = safe_signal(SIGINT, SIG_IGN);
587 savepipe = safe_signal(SIGPIPE, SIG_IGN);
588 if (sigsetjmp(pop3jmp, 1)) {
589 sclose(&mb.mb_sock);
590 safe_signal(SIGINT, saveint);
591 safe_signal(SIGPIPE, savepipe);
592 pop3lock = 0;
593 return 1;
594 }
595 if (saveint != SIG_IGN)
596 safe_signal(SIGINT, pop3catch);
597 if (savepipe != SIG_IGN)
598 safe_signal(SIGPIPE, pop3catch);
599 if ((cp = value("pop3-keepalive")) != NULL) {
600 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
601 savealrm = safe_signal(SIGALRM, pop3alarm);
602 alarm(pop3keepalive);
603 }
604 }
605 mb.mb_sock.s_desc = "POP3";
606 mb.mb_sock.s_onclose = pop3_timer_off;
607 if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
608 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
609 sclose(&mb.mb_sock);
610 pop3_timer_off();
611 safe_signal(SIGINT, saveint);
612 safe_signal(SIGPIPE, savepipe);
613 pop3lock = 0;
614 return 1;
615 }
616 mb.mb_type = MB_POP3;
617 mb.mb_perm = Rflag ? 0 : MB_DELE;
618 pop3_setptr(&mb);
619 setmsize(msgCount);
620 sawcom = 0;
621 safe_signal(SIGINT, saveint);
622 safe_signal(SIGPIPE, savepipe);
623 pop3lock = 0;
624 if (!edit && msgCount == 0) {
625 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
626 fprintf(stderr, catgets(catd, CATSET, 258,
627 "No mail at %s\n"), server);
628 return 1;
629 }
630 return 0;
631 }
632
633 static enum okay
pop3_get(struct mailbox * mp,struct message * m,enum needspec need)634 pop3_get(struct mailbox *mp, struct message *m, enum needspec need)
635 {
636 sighandler_type saveint = SIG_IGN;
637 sighandler_type savepipe = SIG_IGN;
638 off_t offset;
639 char o[LINESIZE], *line = NULL, *lp;
640 size_t linesize = 0, linelen, size;
641 int number = m - message + 1;
642 int emptyline = 0, lines;
643
644 (void)&saveint;
645 (void)&savepipe;
646 (void)&number;
647 (void)&emptyline;
648 (void)&need;
649 verbose = value("verbose") != NULL;
650 if (mp->mb_sock.s_fd < 0) {
651 fprintf(stderr, catgets(catd, CATSET, 219,
652 "POP3 connection already closed.\n"));
653 return STOP;
654 }
655 if (pop3lock++ == 0) {
656 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
657 safe_signal(SIGINT, maincatch);
658 savepipe = safe_signal(SIGPIPE, SIG_IGN);
659 if (sigsetjmp(pop3jmp, 1)) {
660 safe_signal(SIGINT, saveint);
661 safe_signal(SIGPIPE, savepipe);
662 pop3lock--;
663 return STOP;
664 }
665 if (savepipe != SIG_IGN)
666 safe_signal(SIGPIPE, pop3catch);
667 }
668 fseek(mp->mb_otf, 0L, SEEK_END);
669 offset = ftell(mp->mb_otf);
670 retry: switch (need) {
671 case NEED_HEADER:
672 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
673 break;
674 case NEED_BODY:
675 snprintf(o, sizeof o, "RETR %u\r\n", number);
676 break;
677 case NEED_UNSPEC:
678 abort();
679 }
680 POP3_OUT(o, MB_COMD|MB_MULT)
681 if (pop3_answer(mp) == STOP) {
682 if (need == NEED_HEADER) {
683 /*
684 * The TOP POP3 command is optional, so retry
685 * with the entire message.
686 */
687 need = NEED_BODY;
688 goto retry;
689 }
690 if (interrupts)
691 onintr(0);
692 return STOP;
693 }
694 size = 0;
695 lines = 0;
696 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
697 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
698 line[3] == '\0') {
699 mp->mb_active &= ~MB_MULT;
700 break;
701 }
702 if (line[0] == '.') {
703 lp = &line[1];
704 linelen--;
705 } else
706 lp = line;
707 /*
708 * Need to mask 'From ' lines. This cannot be done properly
709 * since some servers pass them as 'From ' and others as
710 * '>From '. Although one could identify the first kind of
711 * server in principle, it is not possible to identify the
712 * second as '>From ' may also come from a server of the
713 * first type as actual data. So do what is absolutely
714 * necessary only - mask 'From '.
715 *
716 * If the line is the first line of the message header, it
717 * is likely a real 'From ' line. In this case, it is just
718 * ignored since it violates all standards.
719 */
720 if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
721 lp[3] == 'm' && lp[4] == ' ') {
722 if (lines != 0) {
723 fputc('>', mp->mb_otf);
724 size++;
725 } else
726 continue;
727 }
728 lines++;
729 if (lp[linelen-1] == '\n' && (linelen == 1 ||
730 lp[linelen-2] == '\r')) {
731 emptyline = linelen <= 2;
732 if (linelen > 2)
733 fwrite(lp, 1, linelen - 2, mp->mb_otf);
734 fputc('\n', mp->mb_otf);
735 size += linelen - 1;
736 } else {
737 emptyline = 0;
738 fwrite(lp, 1, linelen, mp->mb_otf);
739 size += linelen;
740 }
741 }
742 if (!emptyline) {
743 /*
744 * This is very ugly; but some POP3 daemons don't end a
745 * message with \r\n\r\n, and we need \n\n for mbox format.
746 */
747 fputc('\n', mp->mb_otf);
748 lines++;
749 size++;
750 }
751 m->m_size = size;
752 m->m_lines = lines;
753 m->m_block = mailx_blockof(offset);
754 m->m_offset = mailx_offsetof(offset);
755 fflush(mp->mb_otf);
756 switch (need) {
757 case NEED_HEADER:
758 m->m_have |= HAVE_HEADER;
759 break;
760 case NEED_BODY:
761 m->m_have |= HAVE_HEADER|HAVE_BODY;
762 m->m_xlines = m->m_lines;
763 m->m_xsize = m->m_size;
764 break;
765 case NEED_UNSPEC:
766 break;
767 }
768 if (line)
769 free(line);
770 if (saveint != SIG_IGN)
771 safe_signal(SIGINT, saveint);
772 if (savepipe != SIG_IGN)
773 safe_signal(SIGPIPE, savepipe);
774 pop3lock--;
775 if (interrupts)
776 onintr(0);
777 return OKAY;
778 }
779
780 enum okay
pop3_header(struct message * m)781 pop3_header(struct message *m)
782 {
783 return pop3_get(&mb, m, NEED_HEADER);
784 }
785
786
787 enum okay
pop3_body(struct message * m)788 pop3_body(struct message *m)
789 {
790 return pop3_get(&mb, m, NEED_BODY);
791 }
792
793 static enum okay
pop3_exit(struct mailbox * mp)794 pop3_exit(struct mailbox *mp)
795 {
796 POP3_OUT("QUIT\r\n", MB_COMD)
797 POP3_ANSWER()
798 return OKAY;
799 }
800
801 static enum okay
pop3_delete(struct mailbox * mp,int n)802 pop3_delete(struct mailbox *mp, int n)
803 {
804 char o[LINESIZE];
805
806 snprintf(o, sizeof o, "DELE %u\r\n", n);
807 POP3_OUT(o, MB_COMD)
808 POP3_ANSWER()
809 return OKAY;
810 }
811
812 static enum okay
pop3_update(struct mailbox * mp)813 pop3_update(struct mailbox *mp)
814 {
815 FILE *readstat = NULL;
816 struct message *m;
817 int dodel, c, gotcha, held;
818
819 if (Tflag != NULL) {
820 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
821 Tflag = NULL;
822 }
823 if (!edit) {
824 holdbits();
825 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
826 if (m->m_flag & MBOX)
827 c++;
828 }
829 if (c > 0)
830 makembox();
831 }
832 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
833 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
834 char *id;
835
836 if ((id = hfield("message-id", m)) != NULL ||
837 (id = hfield("article-id", m)) != NULL)
838 fprintf(readstat, "%s\n", id);
839 }
840 if (edit) {
841 dodel = m->m_flag & MDELETED;
842 } else {
843 dodel = !((m->m_flag&MPRESERVE) ||
844 (m->m_flag&MTOUCH) == 0);
845 }
846 if (dodel) {
847 pop3_delete(mp, m - message + 1);
848 gotcha++;
849 } else
850 held++;
851 }
852 if (readstat != NULL)
853 Fclose(readstat);
854 if (gotcha && edit) {
855 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
856 printf(value("bsdcompat") || value("bsdmsgs") ?
857 catgets(catd, CATSET, 170, "complete\n") :
858 catgets(catd, CATSET, 212, "updated.\n"));
859 } else if (held && !edit) {
860 if (held == 1)
861 printf(catgets(catd, CATSET, 155,
862 "Held 1 message in %s\n"), mailname);
863 else if (held > 1)
864 printf(catgets(catd, CATSET, 156,
865 "Held %d messages in %s\n"), held, mailname);
866 }
867 fflush(stdout);
868 return OKAY;
869 }
870
871 void
pop3_quit(void)872 pop3_quit(void)
873 {
874 sighandler_type saveint;
875 sighandler_type savepipe;
876
877 verbose = value("verbose") != NULL;
878 if (mb.mb_sock.s_fd < 0) {
879 fprintf(stderr, catgets(catd, CATSET, 219,
880 "POP3 connection already closed.\n"));
881 return;
882 }
883 pop3lock = 1;
884 saveint = safe_signal(SIGINT, SIG_IGN);
885 savepipe = safe_signal(SIGPIPE, SIG_IGN);
886 if (sigsetjmp(pop3jmp, 1)) {
887 safe_signal(SIGINT, saveint);
888 safe_signal(SIGPIPE, saveint);
889 pop3lock = 0;
890 return;
891 }
892 if (saveint != SIG_IGN)
893 safe_signal(SIGINT, pop3catch);
894 if (savepipe != SIG_IGN)
895 safe_signal(SIGPIPE, pop3catch);
896 pop3_update(&mb);
897 pop3_exit(&mb);
898 sclose(&mb.mb_sock);
899 safe_signal(SIGINT, saveint);
900 safe_signal(SIGPIPE, savepipe);
901 pop3lock = 0;
902 }
903 #else /* !HAVE_SOCKETS */
904 static void
nopop3(void)905 nopop3(void)
906 {
907 fprintf(stderr, catgets(catd, CATSET, 216,
908 "No POP3 support compiled in.\n"));
909 }
910
911 int
pop3_setfile(const char * server,int newmail,int isedit)912 pop3_setfile(const char *server, int newmail, int isedit)
913 {
914 nopop3();
915 return -1;
916 }
917
918 enum okay
pop3_header(struct message * mp)919 pop3_header(struct message *mp)
920 {
921 nopop3();
922 return STOP;
923 }
924
925 enum okay
pop3_body(struct message * mp)926 pop3_body(struct message *mp)
927 {
928 nopop3();
929 return STOP;
930 }
931
932 void
pop3_quit(void)933 pop3_quit(void)
934 {
935 nopop3();
936 }
937
938 enum okay
pop3_noop(void)939 pop3_noop(void)
940 {
941 nopop3();
942 return STOP;
943 }
944 #endif /* HAVE_SOCKETS */
945