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
40 #ifndef HAVE_AMALGAMATION
50 #define POP3_ANSWER() POP3_XANSWER(return STOP);
51 #define POP3_XANSWER(ACTIONSTOP) \
53 if (pop3_answer(mp) == STOP) {\
58 #define POP3_OUT(X,Y) POP3_XOUT(X, Y, return STOP);
59 #define POP3_XOUT(X,Y,ACTIONSTOP) \
61 if (pop3_finish(mp) == STOP) {\
64 if (options & OPT_VERBOSE)\
65 fprintf(stderr, ">>> %s", X);\
67 if (swrite(&mp->mb_sock, X) == STOP) {\
72 static char *_pop3_buf
;
73 static size_t _pop3_bufsize
;
74 static sigjmp_buf _pop3_jmp
;
75 static sighandler_type _pop3_savealrm
;
76 static int _pop3_keepalive
;
77 static int volatile _pop3_lock
;
79 /* Perform entire login handshake */
80 static enum okay
_pop3_login(struct mailbox
*mp
, char *xuser
, char *pass
,
81 char const *uhp
, char const *xserver
);
83 /* APOP: get greeting credential or NULL */
85 static char * _pop3_lookup_apop_timestamp(char const *bp
);
88 static bool_t
_pop3_use_starttls(char const *uhp
);
90 /* APOP: shall we use it (for *uhp*)? */
91 static bool_t
_pop3_no_apop(char const *uhp
);
93 /* Several authentication methods */
94 static enum okay
_pop3_auth_plain(struct mailbox
*mp
, char *xuser
,
97 static enum okay
_pop3_auth_apop(struct mailbox
*mp
, char *xuser
,
98 char *pass
, char const *ts
);
101 static void pop3_timer_off(void);
102 static enum okay
pop3_answer(struct mailbox
*mp
);
103 static enum okay
pop3_finish(struct mailbox
*mp
);
104 static void pop3catch(int s
);
105 static void _pop3_maincatch(int s
);
106 static enum okay
pop3_noop1(struct mailbox
*mp
);
107 static void pop3alarm(int s
);
108 static enum okay
pop3_stat(struct mailbox
*mp
, off_t
*size
, int *cnt
);
109 static enum okay
pop3_list(struct mailbox
*mp
, int n
, size_t *size
);
110 static void pop3_init(struct mailbox
*mp
, int n
);
111 static void pop3_dates(struct mailbox
*mp
);
112 static void pop3_setptr(struct mailbox
*mp
);
113 static enum okay
pop3_get(struct mailbox
*mp
, struct message
*m
,
115 static enum okay
pop3_exit(struct mailbox
*mp
);
116 static enum okay
pop3_delete(struct mailbox
*mp
, int n
);
117 static enum okay
pop3_update(struct mailbox
*mp
);
120 _pop3_login(struct mailbox
*mp
, char *xuser
, char *pass
, char const *uhp
,
129 /* Get the greeting, check wether APOP is advertised */
130 POP3_XANSWER(goto jleave
);
132 ts
= _pop3_lookup_apop_timestamp(_pop3_buf
);
135 if ((cp
= strchr(xserver
, ':')) != NULL
) { /* TODO GENERIC URI PARSE! */
136 size_t l
= (size_t)(cp
- xserver
);
137 char *x
= salloc(l
+ 1);
138 memcpy(x
, xserver
, l
);
143 /* If not yet secured, can we upgrade to TLS? */
145 if (mp
->mb_sock
.s_use_ssl
== 0 && _pop3_use_starttls(uhp
)) {
146 POP3_XOUT("STLS\r\n", MB_COMD
, goto jleave
);
147 POP3_XANSWER(goto jleave
);
148 if (ssl_open(xserver
, &mp
->mb_sock
, uhp
) != OKAY
)
152 if (_pop3_use_starttls(uhp
)) {
153 fprintf(stderr
, "No SSL support compiled in.\n");
158 /* Use the APOP single roundtrip? */
159 if (! _pop3_no_apop(uhp
)) {
162 rv
= _pop3_auth_apop(mp
, xuser
, pass
, ts
);
164 fprintf(stderr
, tr(276,
165 "POP3 `APOP' authentication failed, "
166 "maybe try setting *pop3-no-apop*\n"));
170 if (options
& OPT_VERBOSE
)
171 fprintf(stderr
, tr(204, "No POP3 `APOP' support "
172 "available, sending password in clear text\n"));
174 rv
= _pop3_auth_plain(mp
, xuser
, pass
);
180 _pop3_lookup_apop_timestamp(char const *bp
)
184 * A POP3 server which implements the APOP command will include
185 * a timestamp in its banner greeting. The syntax of the timestamp
186 * corresponds to the `msg-id' in [RFC822]
188 * msg-id = "<" addr-spec ">"
189 * addr-spec = local-part "@" domain
196 if ((cp
= strchr(bp
, '<')) == NULL
)
199 /* xxx What about malformed APOP timestamp (<@>) here? */
200 for (ep
= cp
; *ep
; ep
++) {
205 else if (*ep
== '>') {
214 tl
= (size_t)(++ep
- cp
);
223 _pop3_use_starttls(char const *uhp
)
227 if (value("pop3-use-starttls"))
229 var
= savecat("pop3-use-starttls-", uhp
);
230 return value(var
) != NULL
;
234 _pop3_no_apop(char const *uhp
)
238 if (! (ret
= boption("pop3-no-apop"))) {
239 #define __S "pop3-no-apop-"
240 #define __SL sizeof(__S)
241 size_t i
= strlen(uhp
);
242 char *var
= ac_alloc(i
+ __SL
);
243 memcpy(var
, __S
, __SL
- 1);
244 memcpy(var
+ __SL
- 1, uhp
, i
+ 1);
255 _pop3_auth_apop(struct mailbox
*mp
, char *xuser
, char *pass
, char const *ts
)
258 unsigned char digest
[16];
259 char hex
[MD5TOHEX_SIZE
];
264 for (tl
= strlen(ts
);;) {
266 if (! getcredentials(&user
, &pass
))
270 md5_update(&ctx
, (unsigned char*)UNCONST(ts
), tl
);
271 md5_update(&ctx
, (unsigned char*)pass
, strlen(pass
));
272 md5_final(digest
, &ctx
);
273 md5tohex(hex
, digest
);
276 cp
= ac_alloc(5 + i
+ 1 + MD5TOHEX_SIZE
+ 3);
278 memcpy(cp
, "APOP ", 5);
279 memcpy(cp
+ 5, user
, i
);
282 memcpy(cp
+ i
, hex
, MD5TOHEX_SIZE
);
284 memcpy(cp
+ i
, "\r\n\0", 3);
285 POP3_XOUT(cp
, MB_COMD
, goto jcont
);
286 POP3_XANSWER(goto jcont
);
296 #endif /* HAVE_MD5 */
299 _pop3_auth_plain(struct mailbox
*mp
, char *xuser
, char *pass
)
305 /* The USER/PASS plain text version */
308 if (! getcredentials(&user
, &pass
))
313 cp
= ac_alloc(MAX(ul
, pl
) + 5 + 2 +1);
315 memcpy(cp
, "USER ", 5);
316 memcpy(cp
+ 5, user
, ul
);
317 memcpy(cp
+ 5 + ul
, "\r\n\0", 3);
318 POP3_XOUT(cp
, MB_COMD
, goto jcont
);
319 POP3_XANSWER(goto jcont
);
321 memcpy(cp
, "PASS ", 5);
322 memcpy(cp
+ 5, pass
, pl
);
323 memcpy(cp
+ 5 + pl
, "\r\n\0", 3);
324 POP3_XOUT(cp
, MB_COMD
, goto jcont
);
325 POP3_XANSWER(goto jcont
);
339 if (_pop3_keepalive
> 0) {
341 safe_signal(SIGALRM
, _pop3_savealrm
);
346 pop3_answer(struct mailbox
*mp
)
352 if ((sz
= sgetline(&_pop3_buf
, &_pop3_bufsize
, NULL
, &mp
->mb_sock
))
354 if ((mp
->mb_active
& (MB_COMD
|MB_MULT
)) == MB_MULT
)
356 if (options
& OPT_VERBOSE
)
357 fputs(_pop3_buf
, stderr
);
358 switch (*_pop3_buf
) {
361 mp
->mb_active
&= ~MB_COMD
;
365 mp
->mb_active
= MB_NONE
;
366 fprintf(stderr
, tr(218, "POP3 error: %s"), _pop3_buf
);
370 * If the answer starts neither with '+' nor with
371 * '-', it must be part of a multiline response,
372 * e. g. because the user interrupted a file
373 * download. Get lines until a single dot appears.
376 while (_pop3_buf
[0] != '.' || _pop3_buf
[1] != '\r' ||
377 _pop3_buf
[2] != '\n' ||
378 _pop3_buf
[3] != '\0') {
379 sz
= sgetline(&_pop3_buf
, &_pop3_bufsize
,
384 mp
->mb_active
&= ~MB_MULT
;
385 if (mp
->mb_active
!= MB_NONE
)
390 mp
->mb_active
= MB_NONE
;
396 pop3_finish(struct mailbox
*mp
)
398 while (mp
->mb_sock
.s_fd
> 0 && mp
->mb_active
!= MB_NONE
)
399 (void)pop3_answer(mp
);
406 termios_state_reset();
409 fprintf(stderr
, tr(102, "Interrupt\n"));
410 siglongjmp(_pop3_jmp
, 1);
413 fprintf(stderr
, "Received SIGPIPE during POP3 operation\n");
419 _pop3_maincatch(int s
)
422 if (interrupts
++ == 0) {
423 fprintf(stderr
, tr(102, "Interrupt\n"));
430 pop3_noop1(struct mailbox
*mp
)
432 POP3_OUT("NOOP\r\n", MB_COMD
)
440 sighandler_type
volatile saveint
, savepipe
;
444 if ((saveint
= safe_signal(SIGINT
, SIG_IGN
)) != SIG_IGN
)
445 safe_signal(SIGINT
, &_pop3_maincatch
);
446 savepipe
= safe_signal(SIGPIPE
, SIG_IGN
);
447 if (sigsetjmp(_pop3_jmp
, 1) == 0) {
448 if (savepipe
!= SIG_IGN
)
449 safe_signal(SIGPIPE
, pop3catch
);
450 ok
= pop3_noop1(&mb
);
452 safe_signal(SIGINT
, saveint
);
453 safe_signal(SIGPIPE
, savepipe
);
462 sighandler_type
volatile saveint
, savepipe
;
465 if (_pop3_lock
++ == 0) {
466 if ((saveint
= safe_signal(SIGINT
, SIG_IGN
)) != SIG_IGN
)
467 safe_signal(SIGINT
, &_pop3_maincatch
);
468 savepipe
= safe_signal(SIGPIPE
, SIG_IGN
);
469 if (sigsetjmp(_pop3_jmp
, 1)) {
470 safe_signal(SIGINT
, saveint
);
471 safe_signal(SIGPIPE
, savepipe
);
474 if (savepipe
!= SIG_IGN
)
475 safe_signal(SIGPIPE
, pop3catch
);
476 if (pop3_noop1(&mb
) != OKAY
) {
477 safe_signal(SIGINT
, saveint
);
478 safe_signal(SIGPIPE
, savepipe
);
481 safe_signal(SIGINT
, saveint
);
482 safe_signal(SIGPIPE
, savepipe
);
485 alarm(_pop3_keepalive
);
491 pop3_stat(struct mailbox
*mp
, off_t
*size
, int *cnt
)
496 POP3_OUT("STAT\r\n", MB_COMD
)
498 for (cp
= _pop3_buf
; *cp
!= '\0' && !spacechar(*cp
); ++cp
)
500 while (*cp
!= '\0' && spacechar(*cp
))
504 *cnt
= (int)strtol(cp
, NULL
, 10);
505 while (*cp
!= '\0' && !spacechar(*cp
))
507 while (*cp
!= '\0' && spacechar(*cp
))
510 *size
= (int)strtol(cp
, NULL
, 10);
517 fprintf(stderr
, tr(260, "invalid POP3 STAT response: %s\n"),
523 pop3_list(struct mailbox
*mp
, int n
, size_t *size
)
525 char o
[LINESIZE
], *cp
;
527 snprintf(o
, sizeof o
, "LIST %u\r\n", n
);
530 for (cp
= _pop3_buf
; *cp
!= '\0' && !spacechar(*cp
); ++cp
)
532 while (*cp
!= '\0' && spacechar(*cp
))
534 while (*cp
!= '\0' && !spacechar(*cp
))
536 while (*cp
!= '\0' && spacechar(*cp
))
539 *size
= (size_t)strtol(cp
, NULL
, 10);
546 pop3_init(struct mailbox
*mp
, int n
)
548 struct message
*m
= &message
[n
];
551 m
->m_flag
= MUSED
|MNEW
|MNOFROM
|MNEWEST
;
554 pop3_list(mp
, m
- message
+ 1, &m
->m_xsize
);
555 if ((cp
= hfield1("status", m
)) != NULL
) {
556 while (*cp
!= '\0') {
568 pop3_dates(struct mailbox
*mp
)
573 for (i
= 0; i
< msgCount
; i
++)
574 substdate(&message
[i
]);
578 pop3_setptr(struct mailbox
*mp
)
582 message
= scalloc(msgCount
+ 1, sizeof *message
);
583 for (i
= 0; i
< msgCount
; i
++)
586 message
[msgCount
].m_size
= 0;
587 message
[msgCount
].m_lines
= 0;
592 pop3_setfile(const char *server
, int nmail
, int isedit
)
595 sighandler_type saveint
;
596 sighandler_type savepipe
;
597 char * volatile user
, * volatile pass
;
598 const char *cp
, *uhp
, * volatile sp
= server
;
603 if (strncmp(sp
, "pop3://", 7) == 0) {
607 } else if (strncmp(sp
, "pop3s://", 8) == 0) {
613 pass
= lookup_password_for_token(uhp
);
614 if ((cp
= last_at_before_slash(sp
)) != NULL
) {
615 user
= salloc(cp
- sp
+ 1);
616 memcpy(user
, sp
, cp
- sp
);
617 user
[cp
- sp
] = '\0';
619 user
= urlxdec(user
);
622 if (sopen(sp
, &so
, use_ssl
, uhp
, use_ssl
? "pop3s" : "pop3",
623 (options
& OPT_VERBOSE
) != 0) != OKAY
) {
627 edit
= (isedit
!= 0);
628 if (mb
.mb_sock
.s_fd
>= 0)
639 mb
.mb_type
= MB_VOID
;
642 saveint
= safe_signal(SIGINT
, SIG_IGN
);
643 savepipe
= safe_signal(SIGPIPE
, SIG_IGN
);
644 if (sigsetjmp(_pop3_jmp
, 1)) {
646 safe_signal(SIGINT
, saveint
);
647 safe_signal(SIGPIPE
, savepipe
);
651 if (saveint
!= SIG_IGN
)
652 safe_signal(SIGINT
, pop3catch
);
653 if (savepipe
!= SIG_IGN
)
654 safe_signal(SIGPIPE
, pop3catch
);
655 if ((cp
= value("pop3-keepalive")) != NULL
) {
656 if ((_pop3_keepalive
= (int)strtol(cp
, NULL
, 10)) > 0) {
657 _pop3_savealrm
= safe_signal(SIGALRM
, pop3alarm
);
658 alarm(_pop3_keepalive
);
661 mb
.mb_sock
.s_desc
= "POP3";
662 mb
.mb_sock
.s_onclose
= pop3_timer_off
;
663 if (_pop3_login(&mb
, user
, pass
, uhp
, sp
) != OKAY
||
664 pop3_stat(&mb
, &mailsize
, &msgCount
) != OKAY
) {
667 safe_signal(SIGINT
, saveint
);
668 safe_signal(SIGPIPE
, savepipe
);
672 mb
.mb_type
= MB_POP3
;
673 mb
.mb_perm
= (options
& OPT_R_FLAG
) ? 0 : MB_DELE
;
677 safe_signal(SIGINT
, saveint
);
678 safe_signal(SIGPIPE
, savepipe
);
680 if (!edit
&& msgCount
== 0) {
681 if (mb
.mb_type
== MB_POP3
&& value("emptystart") == NULL
)
682 fprintf(stderr
, tr(258, "No mail at %s\n"), server
);
689 pop3_get(struct mailbox
*mp
, struct message
*m
, enum needspec
volatile need
)
691 sighandler_type
volatile saveint
= SIG_IGN
, savepipe
= SIG_IGN
;
693 char o
[LINESIZE
], *line
= NULL
, *lp
;
694 size_t linesize
= 0, linelen
, size
;
695 int number
= m
- message
+ 1, emptyline
= 0, lines
;
697 if (mp
->mb_sock
.s_fd
< 0) {
698 fprintf(stderr
, tr(219, "POP3 connection already closed.\n"));
701 if (_pop3_lock
++ == 0) {
702 if ((saveint
= safe_signal(SIGINT
, SIG_IGN
)) != SIG_IGN
)
703 safe_signal(SIGINT
, &_pop3_maincatch
);
704 savepipe
= safe_signal(SIGPIPE
, SIG_IGN
);
705 if (sigsetjmp(_pop3_jmp
, 1)) {
706 safe_signal(SIGINT
, saveint
);
707 safe_signal(SIGPIPE
, savepipe
);
711 if (savepipe
!= SIG_IGN
)
712 safe_signal(SIGPIPE
, pop3catch
);
714 fseek(mp
->mb_otf
, 0L, SEEK_END
);
715 offset
= ftell(mp
->mb_otf
);
716 retry
: switch (need
) {
718 snprintf(o
, sizeof o
, "TOP %u 0\r\n", number
);
721 snprintf(o
, sizeof o
, "RETR %u\r\n", number
);
726 POP3_OUT(o
, MB_COMD
|MB_MULT
)
727 if (pop3_answer(mp
) == STOP
) {
728 if (need
== NEED_HEADER
) {
730 * The TOP POP3 command is optional, so retry
731 * with the entire message.
742 while (sgetline(&line
, &linesize
, &linelen
, &mp
->mb_sock
) > 0) {
743 if (line
[0] == '.' && line
[1] == '\r' && line
[2] == '\n' &&
745 mp
->mb_active
&= ~MB_MULT
;
748 if (line
[0] == '.') {
754 * Need to mask 'From ' lines. This cannot be done properly
755 * since some servers pass them as 'From ' and others as
756 * '>From '. Although one could identify the first kind of
757 * server in principle, it is not possible to identify the
758 * second as '>From ' may also come from a server of the
759 * first type as actual data. So do what is absolutely
760 * necessary only - mask 'From '.
762 * If the line is the first line of the message header, it
763 * is likely a real 'From ' line. In this case, it is just
764 * ignored since it violates all standards.
765 * TODO i have *never* seen the latter?!?!?
769 * Since we simply copy over data without doing any transfer
770 * encoding reclassification/adjustment we *have* to perform
771 * RFC 4155 compliant From_ quoting here
773 if (is_head(lp
, linelen
)) {
776 fputc('>', mp
->mb_otf
);
780 if (lp
[linelen
-1] == '\n' && (linelen
== 1 ||
781 lp
[linelen
-2] == '\r')) {
782 emptyline
= linelen
<= 2;
784 fwrite(lp
, 1, linelen
- 2, mp
->mb_otf
);
785 fputc('\n', mp
->mb_otf
);
789 fwrite(lp
, 1, linelen
, mp
->mb_otf
);
795 * This is very ugly; but some POP3 daemons don't end a
796 * message with \r\n\r\n, and we need \n\n for mbox format.
798 fputc('\n', mp
->mb_otf
);
804 m
->m_block
= mailx_blockof(offset
);
805 m
->m_offset
= mailx_offsetof(offset
);
809 m
->m_have
|= HAVE_HEADER
;
812 m
->m_have
|= HAVE_HEADER
|HAVE_BODY
;
813 m
->m_xlines
= m
->m_lines
;
814 m
->m_xsize
= m
->m_size
;
821 if (saveint
!= SIG_IGN
)
822 safe_signal(SIGINT
, saveint
);
823 if (savepipe
!= SIG_IGN
)
824 safe_signal(SIGPIPE
, savepipe
);
832 pop3_header(struct message
*m
)
834 return pop3_get(&mb
, m
,
835 boption("pop3-bulk-load") ? NEED_BODY
: NEED_HEADER
);
839 pop3_body(struct message
*m
)
841 return pop3_get(&mb
, m
, NEED_BODY
);
845 pop3_exit(struct mailbox
*mp
)
847 POP3_OUT("QUIT\r\n", MB_COMD
)
853 pop3_delete(struct mailbox
*mp
, int n
)
857 snprintf(o
, sizeof o
, "DELE %u\r\n", n
);
864 pop3_update(struct mailbox
*mp
)
867 int dodel
, c
, gotcha
, held
;
871 for (m
= &message
[0], c
= 0; m
< &message
[msgCount
]; m
++) {
872 if (m
->m_flag
& MBOX
)
878 for (m
= &message
[0], gotcha
=0, held
=0; m
< &message
[msgCount
]; m
++) {
880 dodel
= m
->m_flag
& MDELETED
;
882 dodel
= !((m
->m_flag
&MPRESERVE
) ||
883 (m
->m_flag
&MTOUCH
) == 0);
886 pop3_delete(mp
, m
- message
+ 1);
891 if (gotcha
&& edit
) {
892 printf(tr(168, "\"%s\" "), displayname
);
893 printf((value("bsdcompat") || value("bsdmsgs"))
894 ? tr(170, "complete\n") : tr(212, "updated.\n"));
895 } else if (held
&& !edit
) {
897 printf(tr(155, "Held 1 message in %s\n"), displayname
);
899 printf(tr(156, "Held %d messages in %s\n"), held
,
909 sighandler_type
volatile saveint
, savepipe
;
911 if (mb
.mb_sock
.s_fd
< 0) {
912 fprintf(stderr
, tr(219,
913 "POP3 connection already closed.\n"));
917 saveint
= safe_signal(SIGINT
, SIG_IGN
);
918 savepipe
= safe_signal(SIGPIPE
, SIG_IGN
);
919 if (sigsetjmp(_pop3_jmp
, 1)) {
920 safe_signal(SIGINT
, saveint
);
921 safe_signal(SIGPIPE
, saveint
);
925 if (saveint
!= SIG_IGN
)
926 safe_signal(SIGINT
, pop3catch
);
927 if (savepipe
!= SIG_IGN
)
928 safe_signal(SIGPIPE
, pop3catch
);
932 safe_signal(SIGINT
, saveint
);
933 safe_signal(SIGPIPE
, savepipe
);
936 #endif /* HAVE_POP3 */