prefixwrite(), TODO: change file tracking..
[s-mailx.git] / pop3.c
blob4a2eb3cd01e811692356cb36d130888d4b2b585e
1 /*
2 * S-nail - 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 #include "config.h"
42 #include "rcv.h"
43 #include "extern.h"
44 #include <errno.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <time.h>
49 #ifdef USE_MD5
50 # include "md5.h"
51 #endif
54 * Mail -- a mail program
56 * POP3 client.
59 /* TODO longjmp() globbering as in cmd1.c and cmd3.c (see there)
60 * TODO Problem: Popen doesn't encapsulate all cases of open failures,
61 * TODO may leave child running if fdopen() fails! */
63 #ifdef USE_POP3
64 static int verbose;
66 #define POP3_ANSWER() if (pop3_answer(mp) == STOP) \
67 return STOP;
68 #define POP3_OUT(x, y) if (pop3_finish(mp) == STOP) \
69 return STOP; \
70 if (verbose) \
71 fprintf(stderr, ">>> %s", x); \
72 mp->mb_active |= (y); \
73 if (swrite(&mp->mb_sock, x) == STOP) \
74 return STOP;
76 static char *pop3buf;
77 static size_t pop3bufsize;
78 static sigjmp_buf pop3jmp;
79 static sighandler_type savealrm;
80 static int reset_tio;
81 static struct termios otio;
82 static int pop3keepalive;
83 static volatile int pop3lock;
85 static void pop3_timer_off(void);
86 static enum okay pop3_answer(struct mailbox *mp);
87 static enum okay pop3_finish(struct mailbox *mp);
88 static void pop3catch(int s);
89 static void maincatch(int s);
90 static enum okay pop3_noop1(struct mailbox *mp);
91 static void pop3alarm(int s);
92 static enum okay pop3_pass(struct mailbox *mp, const char *pass);
93 #ifdef USE_MD5
94 static char *pop3_find_timestamp(const char *bp);
95 static enum okay pop3_apop(struct mailbox *mp, char *xuser, const char *pass,
96 const char *ts);
97 static enum okay pop3_apop1(struct mailbox *mp,
98 const char *user, const char *xp);
99 static int pop3_use_apop(const char *uhp);
100 #endif
101 static int pop3_use_starttls(const char *uhp);
102 static enum okay pop3_user(struct mailbox *mp, char *xuser, const char *pass,
103 const char *uhp, const char *xserver);
104 static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *count);
105 static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
106 static void pop3_init(struct mailbox *mp, int n);
107 static void pop3_dates(struct mailbox *mp);
108 static void pop3_setptr(struct mailbox *mp);
109 static char *pop3_have_password(const char *server);
110 static enum okay pop3_get(struct mailbox *mp, struct message *m,
111 enum needspec need);
112 static enum okay pop3_exit(struct mailbox *mp);
113 static enum okay pop3_delete(struct mailbox *mp, int n);
114 static enum okay pop3_update(struct mailbox *mp);
116 static void
117 pop3_timer_off(void)
119 if (pop3keepalive > 0) {
120 alarm(0);
121 safe_signal(SIGALRM, savealrm);
125 static enum okay
126 pop3_answer(struct mailbox *mp)
128 int sz;
129 enum okay ok = STOP;
131 retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
132 if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
133 goto multiline;
134 if (verbose)
135 fputs(pop3buf, stderr);
136 switch (*pop3buf) {
137 case '+':
138 ok = OKAY;
139 mp->mb_active &= ~MB_COMD;
140 break;
141 case '-':
142 ok = STOP;
143 mp->mb_active = MB_NONE;
144 fprintf(stderr, catgets(catd, CATSET, 218,
145 "POP3 error: %s"), pop3buf);
146 break;
147 default:
149 * If the answer starts neither with '+' nor with
150 * '-', it must be part of a multiline response,
151 * e. g. because the user interrupted a file
152 * download. Get lines until a single dot appears.
154 multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
155 pop3buf[2] != '\n' ||
156 pop3buf[3] != '\0') {
157 sz = sgetline(&pop3buf, &pop3bufsize,
158 NULL, &mp->mb_sock);
159 if (sz <= 0)
160 goto eof;
162 mp->mb_active &= ~MB_MULT;
163 if (mp->mb_active != MB_NONE)
164 goto retry;
166 } else {
167 eof: ok = STOP;
168 mp->mb_active = MB_NONE;
170 return ok;
173 static enum okay
174 pop3_finish(struct mailbox *mp)
176 while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
177 pop3_answer(mp);
178 return OKAY;
181 static void
182 pop3catch(int s)
184 if (reset_tio)
185 tcsetattr(0, TCSADRAIN, &otio);
186 switch (s) {
187 case SIGINT:
188 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
189 siglongjmp(pop3jmp, 1);
190 break;
191 case SIGPIPE:
192 fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
193 break;
197 static void
198 maincatch(int s)
200 (void)s;
201 if (interrupts++ == 0) {
202 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
203 return;
205 onintr(0);
208 static enum okay
209 pop3_noop1(struct mailbox *mp)
211 POP3_OUT("NOOP\r\n", MB_COMD)
212 POP3_ANSWER()
213 return OKAY;
216 enum okay
217 pop3_noop(void)
219 enum okay ok = STOP;
220 sighandler_type saveint, savepipe;
222 (void)&saveint;
223 (void)&savepipe;
224 (void)&ok;
225 verbose = value("verbose") != NULL;
226 pop3lock = 1;
227 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
228 safe_signal(SIGINT, maincatch);
229 savepipe = safe_signal(SIGPIPE, SIG_IGN);
230 if (sigsetjmp(pop3jmp, 1) == 0) {
231 if (savepipe != SIG_IGN)
232 safe_signal(SIGPIPE, pop3catch);
233 ok = pop3_noop1(&mb);
235 safe_signal(SIGINT, saveint);
236 safe_signal(SIGPIPE, savepipe);
237 pop3lock = 0;
238 return ok;
241 /*ARGSUSED*/
242 static void
243 pop3alarm(int s)
245 sighandler_type saveint;
246 sighandler_type savepipe;
247 (void)s;
249 if (pop3lock++ == 0) {
250 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
251 safe_signal(SIGINT, maincatch);
252 savepipe = safe_signal(SIGPIPE, SIG_IGN);
253 if (sigsetjmp(pop3jmp, 1)) {
254 safe_signal(SIGINT, saveint);
255 safe_signal(SIGPIPE, savepipe);
256 goto brk;
258 if (savepipe != SIG_IGN)
259 safe_signal(SIGPIPE, pop3catch);
260 if (pop3_noop1(&mb) != OKAY) {
261 safe_signal(SIGINT, saveint);
262 safe_signal(SIGPIPE, savepipe);
263 goto out;
265 safe_signal(SIGINT, saveint);
266 safe_signal(SIGPIPE, savepipe);
268 brk: alarm(pop3keepalive);
269 out: pop3lock--;
272 static enum okay
273 pop3_pass(struct mailbox *mp, const char *pass)
275 char o[LINESIZE];
277 snprintf(o, sizeof o, "PASS %s\r\n", pass);
278 POP3_OUT(o, MB_COMD)
279 POP3_ANSWER()
280 return OKAY;
283 #ifdef USE_MD5
284 static char *
285 pop3_find_timestamp(const char *bp)
287 const char *cp, *ep;
288 char *rp;
289 int hadat = 0;
291 if ((cp = strchr(bp, '<')) == NULL)
292 return NULL;
293 for (ep = cp; *ep; ep++) {
294 if (spacechar(*ep&0377))
295 return NULL;
296 else if (*ep == '@')
297 hadat = 1;
298 else if (*ep == '>') {
299 if (hadat != 1)
300 return NULL;
301 break;
304 if (*ep != '>')
305 return NULL;
306 rp = salloc(ep - cp + 2);
307 memcpy(rp, cp, ep - cp + 1);
308 rp[ep - cp + 1] = '\0';
309 return rp;
312 static enum okay
313 pop3_apop(struct mailbox *mp, char *xuser, const char *pass, const char *ts)
315 char *user, *catp, *xp;
316 unsigned char digest[16];
317 MD5_CTX ctx;
319 retry: if (xuser == NULL) {
320 if ((user = getuser()) == NULL)
321 return STOP;
322 } else
323 user = xuser;
324 if (pass == NULL) {
325 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
326 return STOP;
328 catp = savecat(ts, pass);
329 MD5Init(&ctx);
330 MD5Update(&ctx, (unsigned char *)catp, strlen(catp));
331 MD5Final(digest, &ctx);
332 xp = md5tohex(digest);
333 if (pop3_apop1(mp, user, xp) == STOP) {
334 pass = NULL;
335 goto retry;
337 return OKAY;
340 static enum okay
341 pop3_apop1(struct mailbox *mp, const char *user, const char *xp)
343 char o[LINESIZE];
345 snprintf(o, sizeof o, "APOP %s %s\r\n", user, xp);
346 POP3_OUT(o, MB_COMD)
347 POP3_ANSWER()
348 return OKAY;
351 static int
352 pop3_use_apop(const char *uhp)
354 char *var;
356 if (value("pop3-use-apop"))
357 return 1;
358 var = savecat("pop3-use-apop-", uhp);
359 return value(var) != NULL;
361 #endif /* USE_MD5 */
363 static int
364 pop3_use_starttls(const char *uhp)
366 char *var;
368 if (value("pop3-use-starttls"))
369 return 1;
370 var = savecat("pop3-use-starttls-", 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, *server, *cp;
379 #ifdef USE_MD5
380 char *ts = NULL;
381 #endif
383 POP3_ANSWER()
384 #ifdef USE_MD5
385 if (pop3_use_apop(uhp)) {
386 if ((ts = pop3_find_timestamp(pop3buf)) == NULL) {
387 fprintf(stderr, tr(276,
388 "Could not determine timestamp from "
389 "server greeting. Can't use APOP.\n"));
390 return STOP;
393 #endif
394 if ((cp = strchr(xserver, ':')) != NULL) {
395 server = salloc(cp - xserver + 1);
396 memcpy(server, xserver, cp - xserver);
397 server[cp - xserver] = '\0';
398 } else
399 server = (char *)xserver;
400 #ifdef USE_SSL
401 if (mp->mb_sock.s_use_ssl == 0 && pop3_use_starttls(uhp)) {
402 POP3_OUT("STLS\r\n", MB_COMD)
403 POP3_ANSWER()
404 if (ssl_open(server, &mp->mb_sock, uhp) != OKAY)
405 return STOP;
407 #else /* !USE_SSL */
408 if (pop3_use_starttls(uhp)) {
409 fprintf(stderr, "No SSL support compiled in.\n");
410 return STOP;
412 #endif /* !USE_SSL */
413 #ifdef USE_MD5
414 if (ts != NULL)
415 return pop3_apop(mp, xuser, pass, ts);
416 #endif
417 retry: if (xuser == NULL) {
418 if ((user = getuser()) == NULL)
419 return STOP;
420 } else
421 user = xuser;
422 snprintf(o, sizeof o, "USER %s\r\n", user);
423 POP3_OUT(o, MB_COMD)
424 POP3_ANSWER()
425 if (pass == NULL) {
426 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
427 return STOP;
429 if (pop3_pass(mp, pass) == STOP) {
430 pass = NULL;
431 goto retry;
433 return OKAY;
436 static enum okay
437 pop3_stat(struct mailbox *mp, off_t *size, int *count)
439 char *cp;
440 enum okay ok = OKAY;
442 POP3_OUT("STAT\r\n", MB_COMD);
443 POP3_ANSWER()
444 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
445 while (*cp && spacechar(*cp & 0377))
446 cp++;
447 if (*cp) {
448 *count = (int)strtol(cp, NULL, 10);
449 while (*cp && !spacechar(*cp & 0377))
450 cp++;
451 while (*cp && spacechar(*cp & 0377))
452 cp++;
453 if (*cp)
454 *size = (int)strtol(cp, NULL, 10);
455 else
456 ok = STOP;
457 } else
458 ok = STOP;
459 if (ok == STOP)
460 fprintf(stderr, catgets(catd, CATSET, 260,
461 "invalid POP3 STAT response: %s\n"), pop3buf);
462 return ok;
465 static enum okay
466 pop3_list(struct mailbox *mp, int n, size_t *size)
468 char o[LINESIZE], *cp;
470 snprintf(o, sizeof o, "LIST %u\r\n", n);
471 POP3_OUT(o, MB_COMD)
472 POP3_ANSWER()
473 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
474 while (*cp && spacechar(*cp & 0377))
475 cp++;
476 while (*cp && !spacechar(*cp & 0377))
477 cp++;
478 while (*cp && spacechar(*cp & 0377))
479 cp++;
480 if (*cp)
481 *size = (size_t)strtol(cp, NULL, 10);
482 else
483 *size = 0;
484 return OKAY;
487 static void
488 pop3_init(struct mailbox *mp, int n)
490 struct message *m = &message[n];
491 char *cp;
493 m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
494 m->m_block = 0;
495 m->m_offset = 0;
496 pop3_list(mp, m - message + 1, &m->m_xsize);
497 if ((cp = hfield1("status", m)) != NULL) {
498 while (*cp != '\0') {
499 if (*cp == 'R')
500 m->m_flag |= MREAD;
501 else if (*cp == 'O')
502 m->m_flag &= ~MNEW;
503 cp++;
508 /*ARGSUSED*/
509 static void
510 pop3_dates(struct mailbox *mp)
512 int i;
513 (void)mp;
515 for (i = 0; i < msgCount; i++)
516 substdate(&message[i]);
519 static void
520 pop3_setptr(struct mailbox *mp)
522 int i;
524 message = scalloc(msgCount + 1, sizeof *message);
525 for (i = 0; i < msgCount; i++)
526 pop3_init(mp, i);
527 setdot(message);
528 message[msgCount].m_size = 0;
529 message[msgCount].m_lines = 0;
530 pop3_dates(mp);
533 static char *
534 pop3_have_password(const char *server)
536 char *var, *cp;
538 var = ac_alloc(strlen(server) + 10);
539 strcpy(var, "password-");
540 strcpy(&var[9], server);
541 if ((cp = value(var)) != NULL)
542 cp = savestr(cp);
543 ac_free(var);
544 return cp;
547 int
548 pop3_setfile(const char *server, int newmail, int isedit)
550 struct sock so;
551 sighandler_type saveint;
552 sighandler_type savepipe;
553 char *user;
554 const char *cp, *sp = server, *pass, *uhp;
555 int use_ssl = 0;
557 (void)&sp;
558 (void)&use_ssl;
559 (void)&user;
560 if (newmail)
561 return 1;
562 if (strncmp(sp, "pop3://", 7) == 0) {
563 sp = &sp[7];
564 use_ssl = 0;
565 #ifdef USE_SSL
566 } else if (strncmp(sp, "pop3s://", 8) == 0) {
567 sp = &sp[8];
568 use_ssl = 1;
569 #endif /* USE_SSL */
571 uhp = sp;
572 pass = pop3_have_password(uhp);
573 if ((cp = last_at_before_slash(sp)) != NULL) {
574 user = salloc(cp - sp + 1);
575 memcpy(user, sp, cp - sp);
576 user[cp - sp] = '\0';
577 sp = &cp[1];
578 user = strdec(user);
579 } else
580 user = NULL;
581 verbose = value("verbose") != NULL;
582 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
583 verbose) != OKAY) {
584 return -1;
586 quit();
587 edit = isedit;
588 if (mb.mb_sock.s_fd >= 0)
589 sclose(&mb.mb_sock);
590 if (mb.mb_itf) {
591 fclose(mb.mb_itf);
592 mb.mb_itf = NULL;
594 if (mb.mb_otf) {
595 fclose(mb.mb_otf);
596 mb.mb_otf = NULL;
598 initbox(server);
599 mb.mb_type = MB_VOID;
600 pop3lock = 1;
601 mb.mb_sock = so;
602 saveint = safe_signal(SIGINT, SIG_IGN);
603 savepipe = safe_signal(SIGPIPE, SIG_IGN);
604 if (sigsetjmp(pop3jmp, 1)) {
605 sclose(&mb.mb_sock);
606 safe_signal(SIGINT, saveint);
607 safe_signal(SIGPIPE, savepipe);
608 pop3lock = 0;
609 return 1;
611 if (saveint != SIG_IGN)
612 safe_signal(SIGINT, pop3catch);
613 if (savepipe != SIG_IGN)
614 safe_signal(SIGPIPE, pop3catch);
615 if ((cp = value("pop3-keepalive")) != NULL) {
616 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
617 savealrm = safe_signal(SIGALRM, pop3alarm);
618 alarm(pop3keepalive);
621 mb.mb_sock.s_desc = "POP3";
622 mb.mb_sock.s_onclose = pop3_timer_off;
623 if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
624 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
625 sclose(&mb.mb_sock);
626 pop3_timer_off();
627 safe_signal(SIGINT, saveint);
628 safe_signal(SIGPIPE, savepipe);
629 pop3lock = 0;
630 return 1;
632 mb.mb_type = MB_POP3;
633 mb.mb_perm = Rflag ? 0 : MB_DELE;
634 pop3_setptr(&mb);
635 setmsize(msgCount);
636 sawcom = 0;
637 safe_signal(SIGINT, saveint);
638 safe_signal(SIGPIPE, savepipe);
639 pop3lock = 0;
640 if (!edit && msgCount == 0) {
641 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
642 fprintf(stderr, catgets(catd, CATSET, 258,
643 "No mail at %s\n"), server);
644 return 1;
646 return 0;
649 static enum okay
650 pop3_get(struct mailbox *mp, struct message *m, enum needspec need)
652 sighandler_type saveint = SIG_IGN;
653 sighandler_type savepipe = SIG_IGN;
654 off_t offset;
655 char o[LINESIZE], *line = NULL, *lp;
656 size_t linesize = 0, linelen, size;
657 int number = m - message + 1;
658 int emptyline = 0, lines;
660 (void)&saveint;
661 (void)&savepipe;
662 (void)&number;
663 (void)&emptyline;
664 (void)&need;
665 verbose = value("verbose") != NULL;
666 if (mp->mb_sock.s_fd < 0) {
667 fprintf(stderr, catgets(catd, CATSET, 219,
668 "POP3 connection already closed.\n"));
669 return STOP;
671 if (pop3lock++ == 0) {
672 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
673 safe_signal(SIGINT, maincatch);
674 savepipe = safe_signal(SIGPIPE, SIG_IGN);
675 if (sigsetjmp(pop3jmp, 1)) {
676 safe_signal(SIGINT, saveint);
677 safe_signal(SIGPIPE, savepipe);
678 pop3lock--;
679 return STOP;
681 if (savepipe != SIG_IGN)
682 safe_signal(SIGPIPE, pop3catch);
684 fseek(mp->mb_otf, 0L, SEEK_END);
685 offset = ftell(mp->mb_otf);
686 retry: switch (need) {
687 case NEED_HEADER:
688 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
689 break;
690 case NEED_BODY:
691 snprintf(o, sizeof o, "RETR %u\r\n", number);
692 break;
693 case NEED_UNSPEC:
694 abort();
696 POP3_OUT(o, MB_COMD|MB_MULT)
697 if (pop3_answer(mp) == STOP) {
698 if (need == NEED_HEADER) {
700 * The TOP POP3 command is optional, so retry
701 * with the entire message.
703 need = NEED_BODY;
704 goto retry;
706 if (interrupts)
707 onintr(0);
708 return STOP;
710 size = 0;
711 lines = 0;
712 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
713 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
714 line[3] == '\0') {
715 mp->mb_active &= ~MB_MULT;
716 break;
718 if (line[0] == '.') {
719 lp = &line[1];
720 linelen--;
721 } else
722 lp = line;
724 * Need to mask 'From ' lines. This cannot be done properly
725 * since some servers pass them as 'From ' and others as
726 * '>From '. Although one could identify the first kind of
727 * server in principle, it is not possible to identify the
728 * second as '>From ' may also come from a server of the
729 * first type as actual data. So do what is absolutely
730 * necessary only - mask 'From '.
732 * If the line is the first line of the message header, it
733 * is likely a real 'From ' line. In this case, it is just
734 * ignored since it violates all standards.
736 if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
737 lp[3] == 'm' && lp[4] == ' ') {
738 if (lines != 0) {
739 fputc('>', mp->mb_otf);
740 size++;
741 } else
742 continue;
744 lines++;
745 if (lp[linelen-1] == '\n' && (linelen == 1 ||
746 lp[linelen-2] == '\r')) {
747 emptyline = linelen <= 2;
748 if (linelen > 2)
749 fwrite(lp, 1, linelen - 2, mp->mb_otf);
750 fputc('\n', mp->mb_otf);
751 size += linelen - 1;
752 } else {
753 emptyline = 0;
754 fwrite(lp, 1, linelen, mp->mb_otf);
755 size += linelen;
758 if (!emptyline) {
760 * This is very ugly; but some POP3 daemons don't end a
761 * message with \r\n\r\n, and we need \n\n for mbox format.
763 fputc('\n', mp->mb_otf);
764 lines++;
765 size++;
767 m->m_size = size;
768 m->m_lines = lines;
769 m->m_block = mailx_blockof(offset);
770 m->m_offset = mailx_offsetof(offset);
771 fflush(mp->mb_otf);
772 switch (need) {
773 case NEED_HEADER:
774 m->m_have |= HAVE_HEADER;
775 break;
776 case NEED_BODY:
777 m->m_have |= HAVE_HEADER|HAVE_BODY;
778 m->m_xlines = m->m_lines;
779 m->m_xsize = m->m_size;
780 break;
781 case NEED_UNSPEC:
782 break;
784 if (line)
785 free(line);
786 if (saveint != SIG_IGN)
787 safe_signal(SIGINT, saveint);
788 if (savepipe != SIG_IGN)
789 safe_signal(SIGPIPE, savepipe);
790 pop3lock--;
791 if (interrupts)
792 onintr(0);
793 return OKAY;
796 enum okay
797 pop3_header(struct message *m)
799 return pop3_get(&mb, m, NEED_HEADER);
803 enum okay
804 pop3_body(struct message *m)
806 return pop3_get(&mb, m, NEED_BODY);
809 static enum okay
810 pop3_exit(struct mailbox *mp)
812 POP3_OUT("QUIT\r\n", MB_COMD)
813 POP3_ANSWER()
814 return OKAY;
817 static enum okay
818 pop3_delete(struct mailbox *mp, int n)
820 char o[LINESIZE];
822 snprintf(o, sizeof o, "DELE %u\r\n", n);
823 POP3_OUT(o, MB_COMD)
824 POP3_ANSWER()
825 return OKAY;
828 static enum okay
829 pop3_update(struct mailbox *mp)
831 FILE *readstat = NULL;
832 struct message *m;
833 int dodel, c, gotcha, held;
835 if (Tflag != NULL) {
836 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
837 Tflag = NULL;
839 if (!edit) {
840 holdbits();
841 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
842 if (m->m_flag & MBOX)
843 c++;
845 if (c > 0)
846 makembox();
848 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
849 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
850 char *id;
852 if ((id = hfield1("message-id", m)) != NULL ||
853 (id = hfieldX("article-id", m)) != NULL)
854 fprintf(readstat, "%s\n", id);
856 if (edit) {
857 dodel = m->m_flag & MDELETED;
858 } else {
859 dodel = !((m->m_flag&MPRESERVE) ||
860 (m->m_flag&MTOUCH) == 0);
862 if (dodel) {
863 pop3_delete(mp, m - message + 1);
864 gotcha++;
865 } else
866 held++;
868 if (readstat != NULL)
869 Fclose(readstat);
870 if (gotcha && edit) {
871 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
872 printf(value("bsdcompat") || value("bsdmsgs") ?
873 catgets(catd, CATSET, 170, "complete\n") :
874 catgets(catd, CATSET, 212, "updated.\n"));
875 } else if (held && !edit) {
876 if (held == 1)
877 printf(catgets(catd, CATSET, 155,
878 "Held 1 message in %s\n"), mailname);
879 else if (held > 1)
880 printf(catgets(catd, CATSET, 156,
881 "Held %d messages in %s\n"), held, mailname);
883 fflush(stdout);
884 return OKAY;
887 void
888 pop3_quit(void)
890 sighandler_type saveint;
891 sighandler_type savepipe;
893 verbose = value("verbose") != NULL;
894 if (mb.mb_sock.s_fd < 0) {
895 fprintf(stderr, catgets(catd, CATSET, 219,
896 "POP3 connection already closed.\n"));
897 return;
899 pop3lock = 1;
900 saveint = safe_signal(SIGINT, SIG_IGN);
901 savepipe = safe_signal(SIGPIPE, SIG_IGN);
902 if (sigsetjmp(pop3jmp, 1)) {
903 safe_signal(SIGINT, saveint);
904 safe_signal(SIGPIPE, saveint);
905 pop3lock = 0;
906 return;
908 if (saveint != SIG_IGN)
909 safe_signal(SIGINT, pop3catch);
910 if (savepipe != SIG_IGN)
911 safe_signal(SIGPIPE, pop3catch);
912 pop3_update(&mb);
913 pop3_exit(&mb);
914 sclose(&mb.mb_sock);
915 safe_signal(SIGINT, saveint);
916 safe_signal(SIGPIPE, savepipe);
917 pop3lock = 0;
919 #else /* !USE_POP3 */
920 static void
921 nopop3(void)
923 fprintf(stderr, catgets(catd, CATSET, 216,
924 "No POP3 support compiled in.\n"));
927 int
928 pop3_setfile(const char *server, int newmail, int isedit)
930 (void)server;
931 (void)newmail;
932 (void)isedit;
933 nopop3();
934 return -1;
937 enum okay
938 pop3_header(struct message *mp)
940 (void)mp;
941 nopop3();
942 return STOP;
945 enum okay
946 pop3_body(struct message *mp)
948 (void)mp;
949 nopop3();
950 return STOP;
953 void
954 pop3_quit(void)
956 nopop3();
959 enum okay
960 pop3_noop(void)
962 nopop3();
963 return STOP;
965 #endif /* USE_POP3 */