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>.
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
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
43 typedef int avoid_empty_file_compiler_warning
;
57 #define POP3_ANSWER() POP3_XANSWER(return STOP);
58 #define POP3_XANSWER(ACTIONSTOP) \
60 if (pop3_answer(mp) == STOP) {\
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) {\
71 if (options & OPT_VERBOSE)\
72 fprintf(stderr, ">>> %s", X);\
74 if (swrite(&mp->mb_sock, X) == STOP) {\
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 */
92 static char * _pop3_lookup_apop_timestamp(char const *bp
);
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
,
104 static enum okay
_pop3_auth_apop(struct mailbox
*mp
, char *xuser
,
105 char *pass
, char const *ts
);
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
,
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
);
127 _pop3_login(struct mailbox
*mp
, char *xuser
, char *pass
, char const *uhp
,
136 /* Get the greeting, check wether APOP is advertised */
137 POP3_XANSWER(goto jleave
);
139 ts
= _pop3_lookup_apop_timestamp(pop3buf
);
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
);
150 /* If not yet secured, can we upgrade to TLS? */
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
)
159 if (_pop3_use_starttls(uhp
)) {
160 fprintf(stderr
, "No SSL support compiled in.\n");
165 /* Use the APOP single roundtrip? */
166 if (! _pop3_no_apop(uhp
)) {
169 rv
= _pop3_auth_apop(mp
, xuser
, pass
, ts
);
171 fprintf(stderr
, tr(276,
172 "POP3 `APOP' authentication failed, "
173 "maybe try setting *pop3-no-apop*\n"));
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
);
187 _pop3_lookup_apop_timestamp(char const *bp
)
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]
195 * msg-id = "<" addr-spec ">"
196 * addr-spec = local-part "@" domain
203 if ((cp
= strchr(bp
, '<')) == NULL
)
206 /* xxx What about malformed APOP timestamp (<@>) here? */
207 for (ep
= cp
; *ep
; ep
++) {
212 else if (*ep
== '>') {
221 tl
= (size_t)(++ep
- cp
);
230 _pop3_use_starttls(char const *uhp
)
234 if (value("pop3-use-starttls"))
236 var
= savecat("pop3-use-starttls-", uhp
);
237 return value(var
) != NULL
;
241 _pop3_no_apop(char const *uhp
)
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);
262 _pop3_auth_apop(struct mailbox
*mp
, char *xuser
, char *pass
, char const *ts
)
265 unsigned char digest
[16];
266 char hex
[MD5TOHEX_SIZE
];
271 for (tl
= strlen(ts
);;) {
273 if (! getcredentials(&user
, &pass
))
277 MD5Update(&ctx
, (unsigned char*)UNCONST(ts
), tl
);
278 MD5Update(&ctx
, (unsigned char*)pass
, strlen(pass
));
279 MD5Final(digest
, &ctx
);
280 md5tohex(hex
, digest
);
283 cp
= ac_alloc(5 + i
+ 1 + MD5TOHEX_SIZE
+ 3);
285 memcpy(cp
, "APOP ", 5);
286 memcpy(cp
+ 5, user
, i
);
289 memcpy(cp
+ i
, hex
, MD5TOHEX_SIZE
);
291 memcpy(cp
+ i
, "\r\n\0", 3);
292 POP3_XOUT(cp
, MB_COMD
, goto jcont
);
293 POP3_XANSWER(goto jcont
);
303 #endif /* HAVE_MD5 */
306 _pop3_auth_plain(struct mailbox
*mp
, char *xuser
, char *pass
)
312 /* The USER/PASS plain text version */
315 if (! getcredentials(&user
, &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
);
346 if (pop3keepalive
> 0) {
348 safe_signal(SIGALRM
, savealrm
);
353 pop3_answer(struct mailbox
*mp
)
358 retry
: if ((sz
= sgetline(&pop3buf
, &pop3bufsize
, NULL
, &mp
->mb_sock
)) > 0) {
359 if ((mp
->mb_active
& (MB_COMD
|MB_MULT
)) == MB_MULT
)
361 if (options
& OPT_VERBOSE
)
362 fputs(pop3buf
, stderr
);
366 mp
->mb_active
&= ~MB_COMD
;
370 mp
->mb_active
= MB_NONE
;
371 fprintf(stderr
, catgets(catd
, CATSET
, 218,
372 "POP3 error: %s"), pop3buf
);
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
,
389 mp
->mb_active
&= ~MB_MULT
;
390 if (mp
->mb_active
!= MB_NONE
)
395 mp
->mb_active
= MB_NONE
;
401 pop3_finish(struct mailbox
*mp
)
403 while (mp
->mb_sock
.s_fd
> 0 && mp
->mb_active
!= MB_NONE
)
404 (void)pop3_answer(mp
);
411 termios_state_reset();
414 fprintf(stderr
, catgets(catd
, CATSET
, 102, "Interrupt\n"));
415 siglongjmp(pop3jmp
, 1);
418 fprintf(stderr
, "Received SIGPIPE during POP3 operation\n");
427 if (interrupts
++ == 0) {
428 fprintf(stderr
, catgets(catd
, CATSET
, 102, "Interrupt\n"));
435 pop3_noop1(struct mailbox
*mp
)
437 POP3_OUT("NOOP\r\n", MB_COMD
)
446 sighandler_type saveint
, savepipe
;
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
);
470 sighandler_type saveint
;
471 sighandler_type savepipe
;
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
);
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
);
490 safe_signal(SIGINT
, saveint
);
491 safe_signal(SIGPIPE
, savepipe
);
493 brk
: alarm(pop3keepalive
);
498 pop3_stat(struct mailbox
*mp
, off_t
*size
, int *cnt
)
503 POP3_OUT("STAT\r\n", MB_COMD
)
505 for (cp
= pop3buf
; *cp
&& !spacechar(*cp
& 0377); cp
++);
506 while (*cp
&& spacechar(*cp
& 0377))
509 *cnt
= (int)strtol(cp
, NULL
, 10);
510 while (*cp
&& !spacechar(*cp
& 0377))
512 while (*cp
&& spacechar(*cp
& 0377))
515 *size
= (int)strtol(cp
, NULL
, 10);
521 fprintf(stderr
, catgets(catd
, CATSET
, 260,
522 "invalid POP3 STAT response: %s\n"), pop3buf
);
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
);
534 for (cp
= pop3buf
; *cp
&& !spacechar(*cp
& 0377); cp
++);
535 while (*cp
&& spacechar(*cp
& 0377))
537 while (*cp
&& !spacechar(*cp
& 0377))
539 while (*cp
&& spacechar(*cp
& 0377))
542 *size
= (size_t)strtol(cp
, NULL
, 10);
549 pop3_init(struct mailbox
*mp
, int n
)
551 struct message
*m
= &message
[n
];
554 m
->m_flag
= MUSED
|MNEW
|MNOFROM
|MNEWEST
;
557 pop3_list(mp
, m
- message
+ 1, &m
->m_xsize
);
558 if ((cp
= hfield1("status", m
)) != NULL
) {
559 while (*cp
!= '\0') {
571 pop3_dates(struct mailbox
*mp
)
576 for (i
= 0; i
< msgCount
; i
++)
577 substdate(&message
[i
]);
581 pop3_setptr(struct mailbox
*mp
)
585 message
= scalloc(msgCount
+ 1, sizeof *message
);
586 for (i
= 0; i
< msgCount
; i
++)
589 message
[msgCount
].m_size
= 0;
590 message
[msgCount
].m_lines
= 0;
595 pop3_setfile(const char *server
, int nmail
, int isedit
)
598 sighandler_type saveint
;
599 sighandler_type savepipe
;
600 char *volatile user
, *pass
;
601 const char *cp
, *uhp
, *volatile sp
= server
;
606 if (strncmp(sp
, "pop3://", 7) == 0) {
610 } else if (strncmp(sp
, "pop3s://", 8) == 0) {
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';
622 user
= urlxdec(user
);
625 if (sopen(sp
, &so
, use_ssl
, uhp
, use_ssl
? "pop3s" : "pop3",
626 (options
& OPT_VERBOSE
) != 0) != OKAY
) {
630 edit
= (isedit
!= 0);
631 if (mb
.mb_sock
.s_fd
>= 0)
642 mb
.mb_type
= MB_VOID
;
645 saveint
= safe_signal(SIGINT
, SIG_IGN
);
646 savepipe
= safe_signal(SIGPIPE
, SIG_IGN
);
647 if (sigsetjmp(pop3jmp
, 1)) {
649 safe_signal(SIGINT
, saveint
);
650 safe_signal(SIGPIPE
, savepipe
);
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
) {
670 safe_signal(SIGINT
, saveint
);
671 safe_signal(SIGPIPE
, savepipe
);
675 mb
.mb_type
= MB_POP3
;
676 mb
.mb_perm
= (options
& OPT_R_FLAG
) ? 0 : MB_DELE
;
680 safe_signal(SIGINT
, saveint
);
681 safe_signal(SIGPIPE
, savepipe
);
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
);
693 pop3_get(struct mailbox
*mp
, struct message
*m
, enum needspec
volatile need
)
695 sighandler_type
volatile saveint
= SIG_IGN
, savepipe
= SIG_IGN
;
697 char o
[LINESIZE
], *line
= NULL
, *lp
;
698 size_t linesize
= 0, linelen
, size
;
699 int number
= m
- message
+ 1, emptyline
= 0, lines
;
706 if (mp
->mb_sock
.s_fd
< 0) {
707 fprintf(stderr
, catgets(catd
, CATSET
, 219,
708 "POP3 connection already closed.\n"));
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
);
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
) {
728 snprintf(o
, sizeof o
, "TOP %u 0\r\n", number
);
731 snprintf(o
, sizeof o
, "RETR %u\r\n", number
);
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.
752 while (sgetline(&line
, &linesize
, &linelen
, &mp
->mb_sock
) > 0) {
753 if (line
[0] == '.' && line
[1] == '\r' && line
[2] == '\n' &&
755 mp
->mb_active
&= ~MB_MULT
;
758 if (line
[0] == '.') {
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?!?!?
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
)) {
786 fputc('>', mp
->mb_otf
);
790 if (lp
[linelen
-1] == '\n' && (linelen
== 1 ||
791 lp
[linelen
-2] == '\r')) {
792 emptyline
= linelen
<= 2;
794 fwrite(lp
, 1, linelen
- 2, mp
->mb_otf
);
795 fputc('\n', mp
->mb_otf
);
799 fwrite(lp
, 1, linelen
, mp
->mb_otf
);
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
);
814 m
->m_block
= mailx_blockof(offset
);
815 m
->m_offset
= mailx_offsetof(offset
);
819 m
->m_have
|= HAVE_HEADER
;
822 m
->m_have
|= HAVE_HEADER
|HAVE_BODY
;
823 m
->m_xlines
= m
->m_lines
;
824 m
->m_xsize
= m
->m_size
;
831 if (saveint
!= SIG_IGN
)
832 safe_signal(SIGINT
, saveint
);
833 if (savepipe
!= SIG_IGN
)
834 safe_signal(SIGPIPE
, savepipe
);
842 pop3_header(struct message
*m
)
844 return pop3_get(&mb
, m
,
845 boption("pop3-bulk-load") ? NEED_BODY
: NEED_HEADER
);
849 pop3_body(struct message
*m
)
851 return pop3_get(&mb
, m
, NEED_BODY
);
855 pop3_exit(struct mailbox
*mp
)
857 POP3_OUT("QUIT\r\n", MB_COMD
)
863 pop3_delete(struct mailbox
*mp
, int n
)
867 snprintf(o
, sizeof o
, "DELE %u\r\n", n
);
874 pop3_update(struct mailbox
*mp
)
877 int dodel
, c
, gotcha
, held
;
881 for (m
= &message
[0], c
= 0; m
< &message
[msgCount
]; m
++) {
882 if (m
->m_flag
& MBOX
)
888 for (m
= &message
[0], gotcha
=0, held
=0; m
< &message
[msgCount
]; m
++) {
890 dodel
= m
->m_flag
& MDELETED
;
892 dodel
= !((m
->m_flag
&MPRESERVE
) ||
893 (m
->m_flag
&MTOUCH
) == 0);
896 pop3_delete(mp
, m
- message
+ 1);
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
) {
908 printf(tr(155, "Held 1 message in %s\n"), displayname
);
910 printf(tr(156, "Held %d messages in %s\n"), held
,
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"));
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
);
937 if (saveint
!= SIG_IGN
)
938 safe_signal(SIGINT
, pop3catch
);
939 if (savepipe
!= SIG_IGN
)
940 safe_signal(SIGPIPE
, pop3catch
);
944 safe_signal(SIGINT
, saveint
);
945 safe_signal(SIGPIPE
, savepipe
);
948 #endif /* HAVE_POP3 */