nail.1, mk-mk.in: include the VERSION in the manual
[s-mailx.git] / pop3.c
blobbee5490d6a5b30496b67eb8cf89e2ef9c144df88
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ POP3 (RFCs 1939, 2595) client.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 2002
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #include "config.h"
42 #ifndef HAVE_POP3
43 typedef int avoid_empty_file_compiler_warning;
44 #else
45 #include "rcv.h"
47 #include <sys/stat.h>
48 #include <errno.h>
49 #include <time.h>
50 #include <unistd.h>
52 #include "extern.h"
53 #ifdef HAVE_MD5
54 # include "md5.h"
55 #endif
57 #define POP3_ANSWER() POP3_XANSWER(return STOP);
58 #define POP3_XANSWER(ACTIONSTOP) \
60 if (pop3_answer(mp) == STOP) {\
61 ACTIONSTOP;\
65 #define POP3_OUT(X,Y) POP3_XOUT(X, Y, return STOP);
66 #define POP3_XOUT(X,Y,ACTIONSTOP) \
68 if (pop3_finish(mp) == STOP) {\
69 ACTIONSTOP;\
71 if (options & OPT_VERBOSE)\
72 fprintf(stderr, ">>> %s", X);\
73 mp->mb_active |= Y;\
74 if (swrite(&mp->mb_sock, X) == STOP) {\
75 ACTIONSTOP;\
79 static char *pop3buf;
80 static size_t pop3bufsize;
81 static sigjmp_buf pop3jmp;
82 static sighandler_type savealrm;
83 static int pop3keepalive;
84 static volatile int pop3lock;
86 /* Perform entire login handshake */
87 static enum okay _pop3_login(struct mailbox *mp, char *xuser, char *pass,
88 char const *uhp, char const *xserver);
90 /* APOP: get greeting credential or NULL */
91 #ifdef HAVE_MD5
92 static char * _pop3_lookup_apop_timestamp(char const *bp);
93 #endif
95 static bool_t _pop3_use_starttls(char const *uhp);
97 /* APOP: shall we use it (for *uhp*)? */
98 static bool_t _pop3_no_apop(char const *uhp);
100 /* Several authentication methods */
101 static enum okay _pop3_auth_plain(struct mailbox *mp, char *xuser,
102 char *pass);
103 #ifdef HAVE_MD5
104 static enum okay _pop3_auth_apop(struct mailbox *mp, char *xuser,
105 char *pass, char const *ts);
106 #endif
108 static void pop3_timer_off(void);
109 static enum okay pop3_answer(struct mailbox *mp);
110 static enum okay pop3_finish(struct mailbox *mp);
111 static void pop3catch(int s);
112 static void maincatch(int s);
113 static enum okay pop3_noop1(struct mailbox *mp);
114 static void pop3alarm(int s);
115 static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *cnt);
116 static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
117 static void pop3_init(struct mailbox *mp, int n);
118 static void pop3_dates(struct mailbox *mp);
119 static void pop3_setptr(struct mailbox *mp);
120 static enum okay pop3_get(struct mailbox *mp, struct message *m,
121 enum needspec need);
122 static enum okay pop3_exit(struct mailbox *mp);
123 static enum okay pop3_delete(struct mailbox *mp, int n);
124 static enum okay pop3_update(struct mailbox *mp);
126 static enum okay
127 _pop3_login(struct mailbox *mp, char *xuser, char *pass, char const *uhp,
128 char const *xserver)
130 #ifdef HAVE_MD5
131 char *ts;
132 #endif
133 char *cp;
134 enum okay rv = STOP;
136 /* Get the greeting, check wether APOP is advertised */
137 POP3_XANSWER(goto jleave);
138 #ifdef HAVE_MD5
139 ts = _pop3_lookup_apop_timestamp(pop3buf);
140 #endif
142 if ((cp = strchr(xserver, ':')) != NULL) { /* TODO GENERIC URI PARSE! */
143 size_t l = (size_t)(cp - xserver);
144 char *x = salloc(l + 1);
145 memcpy(x, xserver, l);
146 x[l] = '\0';
147 xserver = x;
150 /* If not yet secured, can we upgrade to TLS? */
151 #ifdef HAVE_SSL
152 if (mp->mb_sock.s_use_ssl == 0 && _pop3_use_starttls(uhp)) {
153 POP3_XOUT("STLS\r\n", MB_COMD, goto jleave);
154 POP3_XANSWER(goto jleave);
155 if (ssl_open(xserver, &mp->mb_sock, uhp) != OKAY)
156 goto jleave;
158 #else
159 if (_pop3_use_starttls(uhp)) {
160 fprintf(stderr, "No SSL support compiled in.\n");
161 goto jleave;
163 #endif
165 /* Use the APOP single roundtrip? */
166 if (! _pop3_no_apop(uhp)) {
167 #ifdef HAVE_MD5
168 if (ts != NULL) {
169 rv = _pop3_auth_apop(mp, xuser, pass, ts);
170 if (rv != OKAY)
171 fprintf(stderr, tr(276,
172 "POP3 `APOP' authentication failed, "
173 "maybe try setting *pop3-no-apop*\n"));
174 goto jleave;
175 } else
176 #endif
177 if (options & OPT_VERBOSE)
178 fprintf(stderr, tr(204, "No POP3 `APOP' support "
179 "available, sending password in clear text\n"));
181 rv = _pop3_auth_plain(mp, xuser, pass);
182 jleave:
183 return rv;
186 static char *
187 _pop3_lookup_apop_timestamp(char const *bp)
190 * RFC 1939:
191 * A POP3 server which implements the APOP command will include
192 * a timestamp in its banner greeting. The syntax of the timestamp
193 * corresponds to the `msg-id' in [RFC822]
194 * RFC 822:
195 * msg-id = "<" addr-spec ">"
196 * addr-spec = local-part "@" domain
198 char const *cp, *ep;
199 size_t tl;
200 char *rp = NULL;
201 bool_t hadat = FAL0;
203 if ((cp = strchr(bp, '<')) == NULL)
204 goto jleave;
206 /* xxx What about malformed APOP timestamp (<@>) here? */
207 for (ep = cp; *ep; ep++) {
208 if (spacechar(*ep))
209 goto jleave;
210 else if (*ep == '@')
211 hadat = TRU1;
212 else if (*ep == '>') {
213 if (! hadat)
214 goto jleave;
215 break;
218 if (*ep != '>')
219 goto jleave;
221 tl = (size_t)(++ep - cp);
222 rp = salloc(tl + 1);
223 memcpy(rp, cp, tl);
224 rp[tl] = '\0';
225 jleave:
226 return rp;
229 static bool_t
230 _pop3_use_starttls(char const *uhp)
232 char *var;
234 if (value("pop3-use-starttls"))
235 return TRU1;
236 var = savecat("pop3-use-starttls-", uhp);
237 return value(var) != NULL;
240 static bool_t
241 _pop3_no_apop(char const *uhp)
243 bool_t ret;
245 if (! (ret = boption("pop3-no-apop"))) {
246 #define __S "pop3-no-apop-"
247 #define __SL sizeof(__S)
248 size_t i = strlen(uhp);
249 char *var = ac_alloc(i + __SL);
250 memcpy(var, __S, __SL - 1);
251 memcpy(var + __SL - 1, uhp, i + 1);
252 ret = boption(var);
253 ac_free(var);
254 #undef __SL
255 #undef __S
257 return ret;
260 #ifdef HAVE_MD5
261 static enum okay
262 _pop3_auth_apop(struct mailbox *mp, char *xuser, char *pass, char const *ts)
264 enum okay rv = STOP;
265 unsigned char digest[16];
266 char hex[MD5TOHEX_SIZE];
267 MD5_CTX ctx;
268 size_t tl, i;
269 char *user, *cp;
271 for (tl = strlen(ts);;) {
272 user = xuser;
273 if (! getcredentials(&user, &pass))
274 break;
276 MD5Init(&ctx);
277 MD5Update(&ctx, (unsigned char*)UNCONST(ts), tl);
278 MD5Update(&ctx, (unsigned char*)pass, strlen(pass));
279 MD5Final(digest, &ctx);
280 md5tohex(hex, digest);
282 i = strlen(user);
283 cp = ac_alloc(5 + i + 1 + MD5TOHEX_SIZE + 3);
285 memcpy(cp, "APOP ", 5);
286 memcpy(cp + 5, user, i);
287 i += 5;
288 cp[i++] = ' ';
289 memcpy(cp + i, hex, MD5TOHEX_SIZE);
290 i += MD5TOHEX_SIZE;
291 memcpy(cp + i, "\r\n\0", 3);
292 POP3_XOUT(cp, MB_COMD, goto jcont);
293 POP3_XANSWER(goto jcont);
294 rv = OKAY;
295 jcont:
296 ac_free(cp);
297 if (rv == OKAY)
298 break;
299 pass = NULL;
301 return rv;
303 #endif /* HAVE_MD5 */
305 static enum okay
306 _pop3_auth_plain(struct mailbox *mp, char *xuser, char *pass)
308 enum okay rv = STOP;
309 char *user, *cp;
310 size_t ul, pl;
312 /* The USER/PASS plain text version */
313 for (;;) {
314 user = xuser;
315 if (! getcredentials(&user, &pass))
316 break;
318 ul = strlen(user);
319 pl = strlen(pass);
320 cp = ac_alloc(MAX(ul, pl) + 5 + 2 +1);
322 memcpy(cp, "USER ", 5);
323 memcpy(cp + 5, user, ul);
324 memcpy(cp + 5 + ul, "\r\n\0", 3);
325 POP3_XOUT(cp, MB_COMD, goto jcont);
326 POP3_XANSWER(goto jcont);
328 memcpy(cp, "PASS ", 5);
329 memcpy(cp + 5, pass, pl);
330 memcpy(cp + 5 + pl, "\r\n\0", 3);
331 POP3_XOUT(cp, MB_COMD, goto jcont);
332 POP3_XANSWER(goto jcont);
333 rv = OKAY;
334 jcont:
335 ac_free(cp);
336 if (rv == OKAY)
337 break;
338 pass = NULL;
340 return rv;
343 static void
344 pop3_timer_off(void)
346 if (pop3keepalive > 0) {
347 alarm(0);
348 safe_signal(SIGALRM, savealrm);
352 static enum okay
353 pop3_answer(struct mailbox *mp)
355 int sz;
356 enum okay ok = STOP;
358 retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
359 if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
360 goto multiline;
361 if (options & OPT_VERBOSE)
362 fputs(pop3buf, stderr);
363 switch (*pop3buf) {
364 case '+':
365 ok = OKAY;
366 mp->mb_active &= ~MB_COMD;
367 break;
368 case '-':
369 ok = STOP;
370 mp->mb_active = MB_NONE;
371 fprintf(stderr, catgets(catd, CATSET, 218,
372 "POP3 error: %s"), pop3buf);
373 break;
374 default:
376 * If the answer starts neither with '+' nor with
377 * '-', it must be part of a multiline response,
378 * e. g. because the user interrupted a file
379 * download. Get lines until a single dot appears.
381 multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
382 pop3buf[2] != '\n' ||
383 pop3buf[3] != '\0') {
384 sz = sgetline(&pop3buf, &pop3bufsize,
385 NULL, &mp->mb_sock);
386 if (sz <= 0)
387 goto eof;
389 mp->mb_active &= ~MB_MULT;
390 if (mp->mb_active != MB_NONE)
391 goto retry;
393 } else {
394 eof: ok = STOP;
395 mp->mb_active = MB_NONE;
397 return ok;
400 static enum okay
401 pop3_finish(struct mailbox *mp)
403 while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
404 (void)pop3_answer(mp);
405 return OKAY;
408 static void
409 pop3catch(int s)
411 termios_state_reset();
412 switch (s) {
413 case SIGINT:
414 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
415 siglongjmp(pop3jmp, 1);
416 break;
417 case SIGPIPE:
418 fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
419 break;
423 static void
424 maincatch(int s)
426 (void)s;
427 if (interrupts++ == 0) {
428 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
429 return;
431 onintr(0);
434 static enum okay
435 pop3_noop1(struct mailbox *mp)
437 POP3_OUT("NOOP\r\n", MB_COMD)
438 POP3_ANSWER()
439 return OKAY;
442 enum okay
443 pop3_noop(void)
445 enum okay ok = STOP;
446 sighandler_type saveint, savepipe;
448 (void)&saveint;
449 (void)&savepipe;
450 (void)&ok;
451 pop3lock = 1;
452 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
453 safe_signal(SIGINT, maincatch);
454 savepipe = safe_signal(SIGPIPE, SIG_IGN);
455 if (sigsetjmp(pop3jmp, 1) == 0) {
456 if (savepipe != SIG_IGN)
457 safe_signal(SIGPIPE, pop3catch);
458 ok = pop3_noop1(&mb);
460 safe_signal(SIGINT, saveint);
461 safe_signal(SIGPIPE, savepipe);
462 pop3lock = 0;
463 return ok;
466 /*ARGSUSED*/
467 static void
468 pop3alarm(int s)
470 sighandler_type saveint;
471 sighandler_type savepipe;
472 (void)s;
474 if (pop3lock++ == 0) {
475 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
476 safe_signal(SIGINT, maincatch);
477 savepipe = safe_signal(SIGPIPE, SIG_IGN);
478 if (sigsetjmp(pop3jmp, 1)) {
479 safe_signal(SIGINT, saveint);
480 safe_signal(SIGPIPE, savepipe);
481 goto brk;
483 if (savepipe != SIG_IGN)
484 safe_signal(SIGPIPE, pop3catch);
485 if (pop3_noop1(&mb) != OKAY) {
486 safe_signal(SIGINT, saveint);
487 safe_signal(SIGPIPE, savepipe);
488 goto out;
490 safe_signal(SIGINT, saveint);
491 safe_signal(SIGPIPE, savepipe);
493 brk: alarm(pop3keepalive);
494 out: pop3lock--;
497 static enum okay
498 pop3_stat(struct mailbox *mp, off_t *size, int *cnt)
500 char *cp;
501 enum okay ok = OKAY;
503 POP3_OUT("STAT\r\n", MB_COMD)
504 POP3_ANSWER()
505 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
506 while (*cp && spacechar(*cp & 0377))
507 cp++;
508 if (*cp) {
509 *cnt = (int)strtol(cp, NULL, 10);
510 while (*cp && !spacechar(*cp & 0377))
511 cp++;
512 while (*cp && spacechar(*cp & 0377))
513 cp++;
514 if (*cp)
515 *size = (int)strtol(cp, NULL, 10);
516 else
517 ok = STOP;
518 } else
519 ok = STOP;
520 if (ok == STOP)
521 fprintf(stderr, catgets(catd, CATSET, 260,
522 "invalid POP3 STAT response: %s\n"), pop3buf);
523 return ok;
526 static enum okay
527 pop3_list(struct mailbox *mp, int n, size_t *size)
529 char o[LINESIZE], *cp;
531 snprintf(o, sizeof o, "LIST %u\r\n", n);
532 POP3_OUT(o, MB_COMD)
533 POP3_ANSWER()
534 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
535 while (*cp && spacechar(*cp & 0377))
536 cp++;
537 while (*cp && !spacechar(*cp & 0377))
538 cp++;
539 while (*cp && spacechar(*cp & 0377))
540 cp++;
541 if (*cp)
542 *size = (size_t)strtol(cp, NULL, 10);
543 else
544 *size = 0;
545 return OKAY;
548 static void
549 pop3_init(struct mailbox *mp, int n)
551 struct message *m = &message[n];
552 char *cp;
554 m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
555 m->m_block = 0;
556 m->m_offset = 0;
557 pop3_list(mp, m - message + 1, &m->m_xsize);
558 if ((cp = hfield1("status", m)) != NULL) {
559 while (*cp != '\0') {
560 if (*cp == 'R')
561 m->m_flag |= MREAD;
562 else if (*cp == 'O')
563 m->m_flag &= ~MNEW;
564 cp++;
569 /*ARGSUSED*/
570 static void
571 pop3_dates(struct mailbox *mp)
573 int i;
574 (void)mp;
576 for (i = 0; i < msgCount; i++)
577 substdate(&message[i]);
580 static void
581 pop3_setptr(struct mailbox *mp)
583 int i;
585 message = scalloc(msgCount + 1, sizeof *message);
586 for (i = 0; i < msgCount; i++)
587 pop3_init(mp, i);
588 setdot(message);
589 message[msgCount].m_size = 0;
590 message[msgCount].m_lines = 0;
591 pop3_dates(mp);
595 pop3_setfile(const char *server, int nmail, int isedit)
597 struct sock so;
598 sighandler_type saveint;
599 sighandler_type savepipe;
600 char *volatile user, *pass;
601 const char *cp, *uhp, *volatile sp = server;
602 int use_ssl = 0;
604 if (nmail)
605 return 1;
606 if (strncmp(sp, "pop3://", 7) == 0) {
607 sp = &sp[7];
608 use_ssl = 0;
609 #ifdef HAVE_SSL
610 } else if (strncmp(sp, "pop3s://", 8) == 0) {
611 sp = &sp[8];
612 use_ssl = 1;
613 #endif
615 uhp = sp;
616 pass = lookup_password_for_token(uhp);
617 if ((cp = last_at_before_slash(sp)) != NULL) {
618 user = salloc(cp - sp + 1);
619 memcpy(user, sp, cp - sp);
620 user[cp - sp] = '\0';
621 sp = &cp[1];
622 user = urlxdec(user);
623 } else
624 user = NULL;
625 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
626 (options & OPT_VERBOSE) != 0) != OKAY) {
627 return -1;
629 quit();
630 edit = (isedit != 0);
631 if (mb.mb_sock.s_fd >= 0)
632 sclose(&mb.mb_sock);
633 if (mb.mb_itf) {
634 fclose(mb.mb_itf);
635 mb.mb_itf = NULL;
637 if (mb.mb_otf) {
638 fclose(mb.mb_otf);
639 mb.mb_otf = NULL;
641 initbox(server);
642 mb.mb_type = MB_VOID;
643 pop3lock = 1;
644 mb.mb_sock = so;
645 saveint = safe_signal(SIGINT, SIG_IGN);
646 savepipe = safe_signal(SIGPIPE, SIG_IGN);
647 if (sigsetjmp(pop3jmp, 1)) {
648 sclose(&mb.mb_sock);
649 safe_signal(SIGINT, saveint);
650 safe_signal(SIGPIPE, savepipe);
651 pop3lock = 0;
652 return 1;
654 if (saveint != SIG_IGN)
655 safe_signal(SIGINT, pop3catch);
656 if (savepipe != SIG_IGN)
657 safe_signal(SIGPIPE, pop3catch);
658 if ((cp = value("pop3-keepalive")) != NULL) {
659 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
660 savealrm = safe_signal(SIGALRM, pop3alarm);
661 alarm(pop3keepalive);
664 mb.mb_sock.s_desc = "POP3";
665 mb.mb_sock.s_onclose = pop3_timer_off;
666 if (_pop3_login(&mb, user, pass, uhp, sp) != OKAY ||
667 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
668 sclose(&mb.mb_sock);
669 pop3_timer_off();
670 safe_signal(SIGINT, saveint);
671 safe_signal(SIGPIPE, savepipe);
672 pop3lock = 0;
673 return 1;
675 mb.mb_type = MB_POP3;
676 mb.mb_perm = (options & OPT_R_FLAG) ? 0 : MB_DELE;
677 pop3_setptr(&mb);
678 setmsize(msgCount);
679 sawcom = FAL0;
680 safe_signal(SIGINT, saveint);
681 safe_signal(SIGPIPE, savepipe);
682 pop3lock = 0;
683 if (!edit && msgCount == 0) {
684 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
685 fprintf(stderr, catgets(catd, CATSET, 258,
686 "No mail at %s\n"), server);
687 return 1;
689 return 0;
692 static enum okay
693 pop3_get(struct mailbox *mp, struct message *m, enum needspec volatile need)
695 sighandler_type volatile saveint = SIG_IGN, savepipe = SIG_IGN;
696 off_t offset;
697 char o[LINESIZE], *line = NULL, *lp;
698 size_t linesize = 0, linelen, size;
699 int number = m - message + 1, emptyline = 0, lines;
701 (void)&saveint;
702 (void)&savepipe;
703 (void)&number;
704 (void)&emptyline;
705 (void)&need;
706 if (mp->mb_sock.s_fd < 0) {
707 fprintf(stderr, catgets(catd, CATSET, 219,
708 "POP3 connection already closed.\n"));
709 return STOP;
711 if (pop3lock++ == 0) {
712 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
713 safe_signal(SIGINT, maincatch);
714 savepipe = safe_signal(SIGPIPE, SIG_IGN);
715 if (sigsetjmp(pop3jmp, 1)) {
716 safe_signal(SIGINT, saveint);
717 safe_signal(SIGPIPE, savepipe);
718 pop3lock--;
719 return STOP;
721 if (savepipe != SIG_IGN)
722 safe_signal(SIGPIPE, pop3catch);
724 fseek(mp->mb_otf, 0L, SEEK_END);
725 offset = ftell(mp->mb_otf);
726 retry: switch (need) {
727 case NEED_HEADER:
728 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
729 break;
730 case NEED_BODY:
731 snprintf(o, sizeof o, "RETR %u\r\n", number);
732 break;
733 case NEED_UNSPEC:
734 abort();
736 POP3_OUT(o, MB_COMD|MB_MULT)
737 if (pop3_answer(mp) == STOP) {
738 if (need == NEED_HEADER) {
740 * The TOP POP3 command is optional, so retry
741 * with the entire message.
743 need = NEED_BODY;
744 goto retry;
746 if (interrupts)
747 onintr(0);
748 return STOP;
750 size = 0;
751 lines = 0;
752 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
753 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
754 line[3] == '\0') {
755 mp->mb_active &= ~MB_MULT;
756 break;
758 if (line[0] == '.') {
759 lp = &line[1];
760 linelen--;
761 } else
762 lp = line;
763 /* TODO >>
764 * Need to mask 'From ' lines. This cannot be done properly
765 * since some servers pass them as 'From ' and others as
766 * '>From '. Although one could identify the first kind of
767 * server in principle, it is not possible to identify the
768 * second as '>From ' may also come from a server of the
769 * first type as actual data. So do what is absolutely
770 * necessary only - mask 'From '.
772 * If the line is the first line of the message header, it
773 * is likely a real 'From ' line. In this case, it is just
774 * ignored since it violates all standards.
775 * TODO i have *never* seen the latter?!?!?
776 * TODO <<
779 * Since we simply copy over data without doing any transfer
780 * encoding reclassification/adjustment we *have* to perform
781 * RFC 4155 compliant From_ quoting here
783 if (is_head(lp, linelen)) {
784 if (lines == 0)
785 continue;
786 fputc('>', mp->mb_otf);
787 ++size;
789 lines++;
790 if (lp[linelen-1] == '\n' && (linelen == 1 ||
791 lp[linelen-2] == '\r')) {
792 emptyline = linelen <= 2;
793 if (linelen > 2)
794 fwrite(lp, 1, linelen - 2, mp->mb_otf);
795 fputc('\n', mp->mb_otf);
796 size += linelen - 1;
797 } else {
798 emptyline = 0;
799 fwrite(lp, 1, linelen, mp->mb_otf);
800 size += linelen;
803 if (!emptyline) {
805 * This is very ugly; but some POP3 daemons don't end a
806 * message with \r\n\r\n, and we need \n\n for mbox format.
808 fputc('\n', mp->mb_otf);
809 lines++;
810 size++;
812 m->m_size = size;
813 m->m_lines = lines;
814 m->m_block = mailx_blockof(offset);
815 m->m_offset = mailx_offsetof(offset);
816 fflush(mp->mb_otf);
817 switch (need) {
818 case NEED_HEADER:
819 m->m_have |= HAVE_HEADER;
820 break;
821 case NEED_BODY:
822 m->m_have |= HAVE_HEADER|HAVE_BODY;
823 m->m_xlines = m->m_lines;
824 m->m_xsize = m->m_size;
825 break;
826 case NEED_UNSPEC:
827 break;
829 if (line)
830 free(line);
831 if (saveint != SIG_IGN)
832 safe_signal(SIGINT, saveint);
833 if (savepipe != SIG_IGN)
834 safe_signal(SIGPIPE, savepipe);
835 pop3lock--;
836 if (interrupts)
837 onintr(0);
838 return OKAY;
841 enum okay
842 pop3_header(struct message *m)
844 return pop3_get(&mb, m,
845 boption("pop3-bulk-load") ? NEED_BODY : NEED_HEADER);
848 enum okay
849 pop3_body(struct message *m)
851 return pop3_get(&mb, m, NEED_BODY);
854 static enum okay
855 pop3_exit(struct mailbox *mp)
857 POP3_OUT("QUIT\r\n", MB_COMD)
858 POP3_ANSWER()
859 return OKAY;
862 static enum okay
863 pop3_delete(struct mailbox *mp, int n)
865 char o[LINESIZE];
867 snprintf(o, sizeof o, "DELE %u\r\n", n);
868 POP3_OUT(o, MB_COMD)
869 POP3_ANSWER()
870 return OKAY;
873 static enum okay
874 pop3_update(struct mailbox *mp)
876 struct message *m;
877 int dodel, c, gotcha, held;
879 if (!edit) {
880 holdbits();
881 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
882 if (m->m_flag & MBOX)
883 c++;
885 if (c > 0)
886 makembox();
888 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
889 if (edit) {
890 dodel = m->m_flag & MDELETED;
891 } else {
892 dodel = !((m->m_flag&MPRESERVE) ||
893 (m->m_flag&MTOUCH) == 0);
895 if (dodel) {
896 pop3_delete(mp, m - message + 1);
897 gotcha++;
898 } else
899 held++;
901 if (gotcha && edit) {
902 printf(tr(168, "\"%s\" "), displayname);
903 printf(value("bsdcompat") || value("bsdmsgs") ?
904 catgets(catd, CATSET, 170, "complete\n") :
905 catgets(catd, CATSET, 212, "updated.\n"));
906 } else if (held && !edit) {
907 if (held == 1)
908 printf(tr(155, "Held 1 message in %s\n"), displayname);
909 else if (held > 1)
910 printf(tr(156, "Held %d messages in %s\n"), held,
911 displayname);
913 fflush(stdout);
914 return OKAY;
917 void
918 pop3_quit(void)
920 sighandler_type saveint;
921 sighandler_type savepipe;
923 if (mb.mb_sock.s_fd < 0) {
924 fprintf(stderr, catgets(catd, CATSET, 219,
925 "POP3 connection already closed.\n"));
926 return;
928 pop3lock = 1;
929 saveint = safe_signal(SIGINT, SIG_IGN);
930 savepipe = safe_signal(SIGPIPE, SIG_IGN);
931 if (sigsetjmp(pop3jmp, 1)) {
932 safe_signal(SIGINT, saveint);
933 safe_signal(SIGPIPE, saveint);
934 pop3lock = 0;
935 return;
937 if (saveint != SIG_IGN)
938 safe_signal(SIGINT, pop3catch);
939 if (savepipe != SIG_IGN)
940 safe_signal(SIGPIPE, pop3catch);
941 pop3_update(&mb);
942 pop3_exit(&mb);
943 sclose(&mb.mb_sock);
944 safe_signal(SIGINT, saveint);
945 safe_signal(SIGPIPE, savepipe);
946 pop3lock = 0;
948 #endif /* HAVE_POP3 */