SMTP: add some missing translation hooks
[s-mailx.git] / pop3.c
blob12f35557001bb228d0d3f1f51918a02702b624e3
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
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 #ifndef lint
41 #ifdef DOSCCS
42 static char sccsid[] = "@(#)pop3.c 2.43 (gritter) 3/4/06";
43 #endif
44 #endif /* not lint */
46 #include "config.h"
48 #include "rcv.h"
49 #include "extern.h"
50 #include <errno.h>
51 #include <sys/stat.h>
52 #include <unistd.h>
53 #include <time.h>
55 #include "md5.h"
58 * Mail -- a mail program
60 * POP3 client.
63 /* TODO longjmp() globbering as in cmd1.c and cmd3.c (see there)
64 * TODO Problem: Popen doesn't encapsulate all cases of open failures,
65 * TODO may leave child running if fdopen() fails! */
67 #ifdef USE_POP3
68 static int verbose;
70 #define POP3_ANSWER() if (pop3_answer(mp) == STOP) \
71 return STOP;
72 #define POP3_OUT(x, y) if (pop3_finish(mp) == STOP) \
73 return STOP; \
74 if (verbose) \
75 fprintf(stderr, ">>> %s", x); \
76 mp->mb_active |= (y); \
77 if (swrite(&mp->mb_sock, x) == STOP) \
78 return STOP;
80 static char *pop3buf;
81 static size_t pop3bufsize;
82 static sigjmp_buf pop3jmp;
83 static sighandler_type savealrm;
84 static int reset_tio;
85 static struct termios otio;
86 static int pop3keepalive;
87 static volatile int pop3lock;
89 static void pop3_timer_off(void);
90 static enum okay pop3_answer(struct mailbox *mp);
91 static enum okay pop3_finish(struct mailbox *mp);
92 static void pop3catch(int s);
93 static void maincatch(int s);
94 static enum okay pop3_noop1(struct mailbox *mp);
95 static void pop3alarm(int s);
96 static enum okay pop3_pass(struct mailbox *mp, const char *pass);
97 static char *pop3_find_timestamp(const char *bp);
98 static enum okay pop3_apop(struct mailbox *mp, char *xuser, const char *pass,
99 const char *ts);
100 static enum okay pop3_apop1(struct mailbox *mp,
101 const char *user, const char *xp);
102 static int pop3_use_starttls(const char *uhp);
103 static int pop3_use_apop(const char *uhp);
104 static enum okay pop3_user(struct mailbox *mp, char *xuser, const char *pass,
105 const char *uhp, const char *xserver);
106 static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *count);
107 static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
108 static void pop3_init(struct mailbox *mp, int n);
109 static void pop3_dates(struct mailbox *mp);
110 static void pop3_setptr(struct mailbox *mp);
111 static char *pop3_have_password(const char *server);
112 static enum okay pop3_get(struct mailbox *mp, struct message *m,
113 enum needspec need);
114 static enum okay pop3_exit(struct mailbox *mp);
115 static enum okay pop3_delete(struct mailbox *mp, int n);
116 static enum okay pop3_update(struct mailbox *mp);
118 static void
119 pop3_timer_off(void)
121 if (pop3keepalive > 0) {
122 alarm(0);
123 safe_signal(SIGALRM, savealrm);
127 static enum okay
128 pop3_answer(struct mailbox *mp)
130 int sz;
131 enum okay ok = STOP;
133 retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
134 if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
135 goto multiline;
136 if (verbose)
137 fputs(pop3buf, stderr);
138 switch (*pop3buf) {
139 case '+':
140 ok = OKAY;
141 mp->mb_active &= ~MB_COMD;
142 break;
143 case '-':
144 ok = STOP;
145 mp->mb_active = MB_NONE;
146 fprintf(stderr, catgets(catd, CATSET, 218,
147 "POP3 error: %s"), pop3buf);
148 break;
149 default:
151 * If the answer starts neither with '+' nor with
152 * '-', it must be part of a multiline response,
153 * e. g. because the user interrupted a file
154 * download. Get lines until a single dot appears.
156 multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
157 pop3buf[2] != '\n' ||
158 pop3buf[3] != '\0') {
159 sz = sgetline(&pop3buf, &pop3bufsize,
160 NULL, &mp->mb_sock);
161 if (sz <= 0)
162 goto eof;
164 mp->mb_active &= ~MB_MULT;
165 if (mp->mb_active != MB_NONE)
166 goto retry;
168 } else {
169 eof: ok = STOP;
170 mp->mb_active = MB_NONE;
172 return ok;
175 static enum okay
176 pop3_finish(struct mailbox *mp)
178 while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
179 pop3_answer(mp);
180 return OKAY;
183 static void
184 pop3catch(int s)
186 if (reset_tio)
187 tcsetattr(0, TCSADRAIN, &otio);
188 switch (s) {
189 case SIGINT:
190 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
191 siglongjmp(pop3jmp, 1);
192 break;
193 case SIGPIPE:
194 fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
195 break;
199 static void
200 maincatch(int s)
202 (void)s;
203 if (interrupts++ == 0) {
204 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
205 return;
207 onintr(0);
210 static enum okay
211 pop3_noop1(struct mailbox *mp)
213 POP3_OUT("NOOP\r\n", MB_COMD)
214 POP3_ANSWER()
215 return OKAY;
218 enum okay
219 pop3_noop(void)
221 enum okay ok = STOP;
222 sighandler_type saveint, savepipe;
224 (void)&saveint;
225 (void)&savepipe;
226 (void)&ok;
227 verbose = value("verbose") != NULL;
228 pop3lock = 1;
229 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
230 safe_signal(SIGINT, maincatch);
231 savepipe = safe_signal(SIGPIPE, SIG_IGN);
232 if (sigsetjmp(pop3jmp, 1) == 0) {
233 if (savepipe != SIG_IGN)
234 safe_signal(SIGPIPE, pop3catch);
235 ok = pop3_noop1(&mb);
237 safe_signal(SIGINT, saveint);
238 safe_signal(SIGPIPE, savepipe);
239 pop3lock = 0;
240 return ok;
243 /*ARGSUSED*/
244 static void
245 pop3alarm(int s)
247 sighandler_type saveint;
248 sighandler_type savepipe;
249 (void)s;
251 if (pop3lock++ == 0) {
252 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
253 safe_signal(SIGINT, maincatch);
254 savepipe = safe_signal(SIGPIPE, SIG_IGN);
255 if (sigsetjmp(pop3jmp, 1)) {
256 safe_signal(SIGINT, saveint);
257 safe_signal(SIGPIPE, savepipe);
258 goto brk;
260 if (savepipe != SIG_IGN)
261 safe_signal(SIGPIPE, pop3catch);
262 if (pop3_noop1(&mb) != OKAY) {
263 safe_signal(SIGINT, saveint);
264 safe_signal(SIGPIPE, savepipe);
265 goto out;
267 safe_signal(SIGINT, saveint);
268 safe_signal(SIGPIPE, savepipe);
270 brk: alarm(pop3keepalive);
271 out: pop3lock--;
274 static enum okay
275 pop3_pass(struct mailbox *mp, const char *pass)
277 char o[LINESIZE];
279 snprintf(o, sizeof o, "PASS %s\r\n", pass);
280 POP3_OUT(o, MB_COMD)
281 POP3_ANSWER()
282 return OKAY;
285 static char *
286 pop3_find_timestamp(const char *bp)
288 const char *cp, *ep;
289 char *rp;
290 int hadat = 0;
292 if ((cp = strchr(bp, '<')) == NULL)
293 return NULL;
294 for (ep = cp; *ep; ep++) {
295 if (spacechar(*ep&0377))
296 return NULL;
297 else if (*ep == '@')
298 hadat = 1;
299 else if (*ep == '>') {
300 if (hadat != 1)
301 return NULL;
302 break;
305 if (*ep != '>')
306 return NULL;
307 rp = salloc(ep - cp + 2);
308 memcpy(rp, cp, ep - cp + 1);
309 rp[ep - cp + 1] = '\0';
310 return rp;
313 static enum okay
314 pop3_apop(struct mailbox *mp, char *xuser, const char *pass, const char *ts)
316 char *user, *catp, *xp;
317 unsigned char digest[16];
318 MD5_CTX ctx;
320 retry: if (xuser == NULL) {
321 if ((user = getuser()) == NULL)
322 return STOP;
323 } else
324 user = xuser;
325 if (pass == NULL) {
326 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
327 return STOP;
329 catp = savecat(ts, pass);
330 MD5Init(&ctx);
331 MD5Update(&ctx, (unsigned char *)catp, strlen(catp));
332 MD5Final(digest, &ctx);
333 xp = md5tohex(digest);
334 if (pop3_apop1(mp, user, xp) == STOP) {
335 pass = NULL;
336 goto retry;
338 return OKAY;
341 static enum okay
342 pop3_apop1(struct mailbox *mp, const char *user, const char *xp)
344 char o[LINESIZE];
346 snprintf(o, sizeof o, "APOP %s %s\r\n", user, xp);
347 POP3_OUT(o, MB_COMD)
348 POP3_ANSWER()
349 return OKAY;
352 static int
353 pop3_use_starttls(const char *uhp)
355 char *var;
357 if (value("pop3-use-starttls"))
358 return 1;
359 var = savecat("pop3-use-starttls-", uhp);
360 return value(var) != NULL;
363 static int
364 pop3_use_apop(const char *uhp)
366 char *var;
368 if (value("pop3-use-apop"))
369 return 1;
370 var = savecat("pop3-use-apop-", uhp);
371 return value(var) != NULL;
374 static enum okay
375 pop3_user(struct mailbox *mp, char *xuser, const char *pass,
376 const char *uhp, const char *xserver)
378 char o[LINESIZE], *user, *ts = NULL, *server, *cp;
380 POP3_ANSWER()
381 if (pop3_use_apop(uhp)) {
382 if ((ts = pop3_find_timestamp(pop3buf)) == NULL) {
383 fprintf(stderr, "Could not determine timestamp from "
384 "server greeting. Impossible to use APOP.\n");
385 return STOP;
388 if ((cp = strchr(xserver, ':')) != NULL) {
389 server = salloc(cp - xserver + 1);
390 memcpy(server, xserver, cp - xserver);
391 server[cp - xserver] = '\0';
392 } else
393 server = (char *)xserver;
394 #ifdef USE_SSL
395 if (mp->mb_sock.s_use_ssl == 0 && pop3_use_starttls(uhp)) {
396 POP3_OUT("STLS\r\n", MB_COMD)
397 POP3_ANSWER()
398 if (ssl_open(server, &mp->mb_sock, uhp) != OKAY)
399 return STOP;
401 #else /* !USE_SSL */
402 if (pop3_use_starttls(uhp)) {
403 fprintf(stderr, "No SSL support compiled in.\n");
404 return STOP;
406 #endif /* !USE_SSL */
407 if (ts != NULL)
408 return pop3_apop(mp, xuser, pass, ts);
409 retry: if (xuser == NULL) {
410 if ((user = getuser()) == NULL)
411 return STOP;
412 } else
413 user = xuser;
414 snprintf(o, sizeof o, "USER %s\r\n", user);
415 POP3_OUT(o, MB_COMD)
416 POP3_ANSWER()
417 if (pass == NULL) {
418 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
419 return STOP;
421 if (pop3_pass(mp, pass) == STOP) {
422 pass = NULL;
423 goto retry;
425 return OKAY;
428 static enum okay
429 pop3_stat(struct mailbox *mp, off_t *size, int *count)
431 char *cp;
432 enum okay ok = OKAY;
434 POP3_OUT("STAT\r\n", MB_COMD);
435 POP3_ANSWER()
436 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
437 while (*cp && spacechar(*cp & 0377))
438 cp++;
439 if (*cp) {
440 *count = (int)strtol(cp, NULL, 10);
441 while (*cp && !spacechar(*cp & 0377))
442 cp++;
443 while (*cp && spacechar(*cp & 0377))
444 cp++;
445 if (*cp)
446 *size = (int)strtol(cp, NULL, 10);
447 else
448 ok = STOP;
449 } else
450 ok = STOP;
451 if (ok == STOP)
452 fprintf(stderr, catgets(catd, CATSET, 260,
453 "invalid POP3 STAT response: %s\n"), pop3buf);
454 return ok;
457 static enum okay
458 pop3_list(struct mailbox *mp, int n, size_t *size)
460 char o[LINESIZE], *cp;
462 snprintf(o, sizeof o, "LIST %u\r\n", n);
463 POP3_OUT(o, MB_COMD)
464 POP3_ANSWER()
465 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
466 while (*cp && spacechar(*cp & 0377))
467 cp++;
468 while (*cp && !spacechar(*cp & 0377))
469 cp++;
470 while (*cp && spacechar(*cp & 0377))
471 cp++;
472 if (*cp)
473 *size = (size_t)strtol(cp, NULL, 10);
474 else
475 *size = 0;
476 return OKAY;
479 static void
480 pop3_init(struct mailbox *mp, int n)
482 struct message *m = &message[n];
483 char *cp;
485 m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
486 m->m_block = 0;
487 m->m_offset = 0;
488 pop3_list(mp, m - message + 1, &m->m_xsize);
489 if ((cp = hfield("status", m)) != NULL) {
490 while (*cp != '\0') {
491 if (*cp == 'R')
492 m->m_flag |= MREAD;
493 else if (*cp == 'O')
494 m->m_flag &= ~MNEW;
495 cp++;
500 /*ARGSUSED*/
501 static void
502 pop3_dates(struct mailbox *mp)
504 int i;
505 (void)mp;
507 for (i = 0; i < msgCount; i++)
508 substdate(&message[i]);
511 static void
512 pop3_setptr(struct mailbox *mp)
514 int i;
516 message = scalloc(msgCount + 1, sizeof *message);
517 for (i = 0; i < msgCount; i++)
518 pop3_init(mp, i);
519 setdot(message);
520 message[msgCount].m_size = 0;
521 message[msgCount].m_lines = 0;
522 pop3_dates(mp);
525 static char *
526 pop3_have_password(const char *server)
528 char *var, *cp;
530 var = ac_alloc(strlen(server) + 10);
531 strcpy(var, "password-");
532 strcpy(&var[9], server);
533 if ((cp = value(var)) != NULL)
534 cp = savestr(cp);
535 ac_free(var);
536 return cp;
539 int
540 pop3_setfile(const char *server, int newmail, int isedit)
542 struct sock so;
543 sighandler_type saveint;
544 sighandler_type savepipe;
545 char *user;
546 const char *cp, *sp = server, *pass, *uhp;
547 int use_ssl = 0;
549 (void)&sp;
550 (void)&use_ssl;
551 (void)&user;
552 if (newmail)
553 return 1;
554 if (strncmp(sp, "pop3://", 7) == 0) {
555 sp = &sp[7];
556 use_ssl = 0;
557 #ifdef USE_SSL
558 } else if (strncmp(sp, "pop3s://", 8) == 0) {
559 sp = &sp[8];
560 use_ssl = 1;
561 #endif /* USE_SSL */
563 uhp = sp;
564 pass = pop3_have_password(uhp);
565 if ((cp = last_at_before_slash(sp)) != NULL) {
566 user = salloc(cp - sp + 1);
567 memcpy(user, sp, cp - sp);
568 user[cp - sp] = '\0';
569 sp = &cp[1];
570 user = strdec(user);
571 } else
572 user = NULL;
573 verbose = value("verbose") != NULL;
574 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
575 verbose) != OKAY) {
576 return -1;
578 quit();
579 edit = isedit;
580 if (mb.mb_sock.s_fd >= 0)
581 sclose(&mb.mb_sock);
582 if (mb.mb_itf) {
583 fclose(mb.mb_itf);
584 mb.mb_itf = NULL;
586 if (mb.mb_otf) {
587 fclose(mb.mb_otf);
588 mb.mb_otf = NULL;
590 initbox(server);
591 mb.mb_type = MB_VOID;
592 pop3lock = 1;
593 mb.mb_sock = so;
594 saveint = safe_signal(SIGINT, SIG_IGN);
595 savepipe = safe_signal(SIGPIPE, SIG_IGN);
596 if (sigsetjmp(pop3jmp, 1)) {
597 sclose(&mb.mb_sock);
598 safe_signal(SIGINT, saveint);
599 safe_signal(SIGPIPE, savepipe);
600 pop3lock = 0;
601 return 1;
603 if (saveint != SIG_IGN)
604 safe_signal(SIGINT, pop3catch);
605 if (savepipe != SIG_IGN)
606 safe_signal(SIGPIPE, pop3catch);
607 if ((cp = value("pop3-keepalive")) != NULL) {
608 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
609 savealrm = safe_signal(SIGALRM, pop3alarm);
610 alarm(pop3keepalive);
613 mb.mb_sock.s_desc = "POP3";
614 mb.mb_sock.s_onclose = pop3_timer_off;
615 if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
616 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
617 sclose(&mb.mb_sock);
618 pop3_timer_off();
619 safe_signal(SIGINT, saveint);
620 safe_signal(SIGPIPE, savepipe);
621 pop3lock = 0;
622 return 1;
624 mb.mb_type = MB_POP3;
625 mb.mb_perm = Rflag ? 0 : MB_DELE;
626 pop3_setptr(&mb);
627 setmsize(msgCount);
628 sawcom = 0;
629 safe_signal(SIGINT, saveint);
630 safe_signal(SIGPIPE, savepipe);
631 pop3lock = 0;
632 if (!edit && msgCount == 0) {
633 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
634 fprintf(stderr, catgets(catd, CATSET, 258,
635 "No mail at %s\n"), server);
636 return 1;
638 return 0;
641 static enum okay
642 pop3_get(struct mailbox *mp, struct message *m, enum needspec need)
644 sighandler_type saveint = SIG_IGN;
645 sighandler_type savepipe = SIG_IGN;
646 off_t offset;
647 char o[LINESIZE], *line = NULL, *lp;
648 size_t linesize = 0, linelen, size;
649 int number = m - message + 1;
650 int emptyline = 0, lines;
652 (void)&saveint;
653 (void)&savepipe;
654 (void)&number;
655 (void)&emptyline;
656 (void)&need;
657 verbose = value("verbose") != NULL;
658 if (mp->mb_sock.s_fd < 0) {
659 fprintf(stderr, catgets(catd, CATSET, 219,
660 "POP3 connection already closed.\n"));
661 return STOP;
663 if (pop3lock++ == 0) {
664 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
665 safe_signal(SIGINT, maincatch);
666 savepipe = safe_signal(SIGPIPE, SIG_IGN);
667 if (sigsetjmp(pop3jmp, 1)) {
668 safe_signal(SIGINT, saveint);
669 safe_signal(SIGPIPE, savepipe);
670 pop3lock--;
671 return STOP;
673 if (savepipe != SIG_IGN)
674 safe_signal(SIGPIPE, pop3catch);
676 fseek(mp->mb_otf, 0L, SEEK_END);
677 offset = ftell(mp->mb_otf);
678 retry: switch (need) {
679 case NEED_HEADER:
680 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
681 break;
682 case NEED_BODY:
683 snprintf(o, sizeof o, "RETR %u\r\n", number);
684 break;
685 case NEED_UNSPEC:
686 abort();
688 POP3_OUT(o, MB_COMD|MB_MULT)
689 if (pop3_answer(mp) == STOP) {
690 if (need == NEED_HEADER) {
692 * The TOP POP3 command is optional, so retry
693 * with the entire message.
695 need = NEED_BODY;
696 goto retry;
698 if (interrupts)
699 onintr(0);
700 return STOP;
702 size = 0;
703 lines = 0;
704 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
705 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
706 line[3] == '\0') {
707 mp->mb_active &= ~MB_MULT;
708 break;
710 if (line[0] == '.') {
711 lp = &line[1];
712 linelen--;
713 } else
714 lp = line;
716 * Need to mask 'From ' lines. This cannot be done properly
717 * since some servers pass them as 'From ' and others as
718 * '>From '. Although one could identify the first kind of
719 * server in principle, it is not possible to identify the
720 * second as '>From ' may also come from a server of the
721 * first type as actual data. So do what is absolutely
722 * necessary only - mask 'From '.
724 * If the line is the first line of the message header, it
725 * is likely a real 'From ' line. In this case, it is just
726 * ignored since it violates all standards.
728 if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
729 lp[3] == 'm' && lp[4] == ' ') {
730 if (lines != 0) {
731 fputc('>', mp->mb_otf);
732 size++;
733 } else
734 continue;
736 lines++;
737 if (lp[linelen-1] == '\n' && (linelen == 1 ||
738 lp[linelen-2] == '\r')) {
739 emptyline = linelen <= 2;
740 if (linelen > 2)
741 fwrite(lp, 1, linelen - 2, mp->mb_otf);
742 fputc('\n', mp->mb_otf);
743 size += linelen - 1;
744 } else {
745 emptyline = 0;
746 fwrite(lp, 1, linelen, mp->mb_otf);
747 size += linelen;
750 if (!emptyline) {
752 * This is very ugly; but some POP3 daemons don't end a
753 * message with \r\n\r\n, and we need \n\n for mbox format.
755 fputc('\n', mp->mb_otf);
756 lines++;
757 size++;
759 m->m_size = size;
760 m->m_lines = lines;
761 m->m_block = mailx_blockof(offset);
762 m->m_offset = mailx_offsetof(offset);
763 fflush(mp->mb_otf);
764 switch (need) {
765 case NEED_HEADER:
766 m->m_have |= HAVE_HEADER;
767 break;
768 case NEED_BODY:
769 m->m_have |= HAVE_HEADER|HAVE_BODY;
770 m->m_xlines = m->m_lines;
771 m->m_xsize = m->m_size;
772 break;
773 case NEED_UNSPEC:
774 break;
776 if (line)
777 free(line);
778 if (saveint != SIG_IGN)
779 safe_signal(SIGINT, saveint);
780 if (savepipe != SIG_IGN)
781 safe_signal(SIGPIPE, savepipe);
782 pop3lock--;
783 if (interrupts)
784 onintr(0);
785 return OKAY;
788 enum okay
789 pop3_header(struct message *m)
791 return pop3_get(&mb, m, NEED_HEADER);
795 enum okay
796 pop3_body(struct message *m)
798 return pop3_get(&mb, m, NEED_BODY);
801 static enum okay
802 pop3_exit(struct mailbox *mp)
804 POP3_OUT("QUIT\r\n", MB_COMD)
805 POP3_ANSWER()
806 return OKAY;
809 static enum okay
810 pop3_delete(struct mailbox *mp, int n)
812 char o[LINESIZE];
814 snprintf(o, sizeof o, "DELE %u\r\n", n);
815 POP3_OUT(o, MB_COMD)
816 POP3_ANSWER()
817 return OKAY;
820 static enum okay
821 pop3_update(struct mailbox *mp)
823 FILE *readstat = NULL;
824 struct message *m;
825 int dodel, c, gotcha, held;
827 if (Tflag != NULL) {
828 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
829 Tflag = NULL;
831 if (!edit) {
832 holdbits();
833 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
834 if (m->m_flag & MBOX)
835 c++;
837 if (c > 0)
838 makembox();
840 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
841 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
842 char *id;
844 if ((id = hfield("message-id", m)) != NULL ||
845 (id = hfield("article-id", m)) != NULL)
846 fprintf(readstat, "%s\n", id);
848 if (edit) {
849 dodel = m->m_flag & MDELETED;
850 } else {
851 dodel = !((m->m_flag&MPRESERVE) ||
852 (m->m_flag&MTOUCH) == 0);
854 if (dodel) {
855 pop3_delete(mp, m - message + 1);
856 gotcha++;
857 } else
858 held++;
860 if (readstat != NULL)
861 Fclose(readstat);
862 if (gotcha && edit) {
863 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
864 printf(value("bsdcompat") || value("bsdmsgs") ?
865 catgets(catd, CATSET, 170, "complete\n") :
866 catgets(catd, CATSET, 212, "updated.\n"));
867 } else if (held && !edit) {
868 if (held == 1)
869 printf(catgets(catd, CATSET, 155,
870 "Held 1 message in %s\n"), mailname);
871 else if (held > 1)
872 printf(catgets(catd, CATSET, 156,
873 "Held %d messages in %s\n"), held, mailname);
875 fflush(stdout);
876 return OKAY;
879 void
880 pop3_quit(void)
882 sighandler_type saveint;
883 sighandler_type savepipe;
885 verbose = value("verbose") != NULL;
886 if (mb.mb_sock.s_fd < 0) {
887 fprintf(stderr, catgets(catd, CATSET, 219,
888 "POP3 connection already closed.\n"));
889 return;
891 pop3lock = 1;
892 saveint = safe_signal(SIGINT, SIG_IGN);
893 savepipe = safe_signal(SIGPIPE, SIG_IGN);
894 if (sigsetjmp(pop3jmp, 1)) {
895 safe_signal(SIGINT, saveint);
896 safe_signal(SIGPIPE, saveint);
897 pop3lock = 0;
898 return;
900 if (saveint != SIG_IGN)
901 safe_signal(SIGINT, pop3catch);
902 if (savepipe != SIG_IGN)
903 safe_signal(SIGPIPE, pop3catch);
904 pop3_update(&mb);
905 pop3_exit(&mb);
906 sclose(&mb.mb_sock);
907 safe_signal(SIGINT, saveint);
908 safe_signal(SIGPIPE, savepipe);
909 pop3lock = 0;
911 #else /* !USE_POP3 */
912 static void
913 nopop3(void)
915 fprintf(stderr, catgets(catd, CATSET, 216,
916 "No POP3 support compiled in.\n"));
919 int
920 pop3_setfile(const char *server, int newmail, int isedit)
922 (void)server;
923 (void)newmail;
924 (void)isedit;
925 nopop3();
926 return -1;
929 enum okay
930 pop3_header(struct message *mp)
932 (void)mp;
933 nopop3();
934 return STOP;
937 enum okay
938 pop3_body(struct message *mp)
940 (void)mp;
941 nopop3();
942 return STOP;
945 void
946 pop3_quit(void)
948 nopop3();
951 enum okay
952 pop3_noop(void)
954 nopop3();
955 return STOP;
957 #endif /* USE_POP3 */