Silence longjmp() warnings and one harmless unused warning
[s-mailx.git] / pop3.c
blob9fe5050ebada69ff489ee6da589ce5f4ed9f8a5d
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, *pass, *uhp, *volatile sp = server;
555 int use_ssl = 0;
557 if (newmail)
558 return 1;
559 if (strncmp(sp, "pop3://", 7) == 0) {
560 sp = &sp[7];
561 use_ssl = 0;
562 #ifdef USE_SSL
563 } else if (strncmp(sp, "pop3s://", 8) == 0) {
564 sp = &sp[8];
565 use_ssl = 1;
566 #endif /* USE_SSL */
568 uhp = sp;
569 pass = pop3_have_password(uhp);
570 if ((cp = last_at_before_slash(sp)) != NULL) {
571 user = salloc(cp - sp + 1);
572 memcpy(user, sp, cp - sp);
573 user[cp - sp] = '\0';
574 sp = &cp[1];
575 user = strdec(user);
576 } else
577 user = NULL;
578 verbose = value("verbose") != NULL;
579 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
580 verbose) != OKAY) {
581 return -1;
583 quit();
584 edit = isedit;
585 if (mb.mb_sock.s_fd >= 0)
586 sclose(&mb.mb_sock);
587 if (mb.mb_itf) {
588 fclose(mb.mb_itf);
589 mb.mb_itf = NULL;
591 if (mb.mb_otf) {
592 fclose(mb.mb_otf);
593 mb.mb_otf = NULL;
595 initbox(server);
596 mb.mb_type = MB_VOID;
597 pop3lock = 1;
598 mb.mb_sock = so;
599 saveint = safe_signal(SIGINT, SIG_IGN);
600 savepipe = safe_signal(SIGPIPE, SIG_IGN);
601 if (sigsetjmp(pop3jmp, 1)) {
602 sclose(&mb.mb_sock);
603 safe_signal(SIGINT, saveint);
604 safe_signal(SIGPIPE, savepipe);
605 pop3lock = 0;
606 return 1;
608 if (saveint != SIG_IGN)
609 safe_signal(SIGINT, pop3catch);
610 if (savepipe != SIG_IGN)
611 safe_signal(SIGPIPE, pop3catch);
612 if ((cp = value("pop3-keepalive")) != NULL) {
613 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
614 savealrm = safe_signal(SIGALRM, pop3alarm);
615 alarm(pop3keepalive);
618 mb.mb_sock.s_desc = "POP3";
619 mb.mb_sock.s_onclose = pop3_timer_off;
620 if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
621 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
622 sclose(&mb.mb_sock);
623 pop3_timer_off();
624 safe_signal(SIGINT, saveint);
625 safe_signal(SIGPIPE, savepipe);
626 pop3lock = 0;
627 return 1;
629 mb.mb_type = MB_POP3;
630 mb.mb_perm = Rflag ? 0 : MB_DELE;
631 pop3_setptr(&mb);
632 setmsize(msgCount);
633 sawcom = 0;
634 safe_signal(SIGINT, saveint);
635 safe_signal(SIGPIPE, savepipe);
636 pop3lock = 0;
637 if (!edit && msgCount == 0) {
638 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
639 fprintf(stderr, catgets(catd, CATSET, 258,
640 "No mail at %s\n"), server);
641 return 1;
643 return 0;
646 static enum okay
647 pop3_get(struct mailbox *mp, struct message *m, enum needspec volatile need)
649 sighandler_type volatile saveint = SIG_IGN, savepipe = SIG_IGN;
650 off_t offset;
651 char o[LINESIZE], *line = NULL, *lp;
652 size_t linesize = 0, linelen, size;
653 int number = m - message + 1, emptyline = 0, lines;
655 (void)&saveint;
656 (void)&savepipe;
657 (void)&number;
658 (void)&emptyline;
659 (void)&need;
660 verbose = value("verbose") != NULL;
661 if (mp->mb_sock.s_fd < 0) {
662 fprintf(stderr, catgets(catd, CATSET, 219,
663 "POP3 connection already closed.\n"));
664 return STOP;
666 if (pop3lock++ == 0) {
667 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
668 safe_signal(SIGINT, maincatch);
669 savepipe = safe_signal(SIGPIPE, SIG_IGN);
670 if (sigsetjmp(pop3jmp, 1)) {
671 safe_signal(SIGINT, saveint);
672 safe_signal(SIGPIPE, savepipe);
673 pop3lock--;
674 return STOP;
676 if (savepipe != SIG_IGN)
677 safe_signal(SIGPIPE, pop3catch);
679 fseek(mp->mb_otf, 0L, SEEK_END);
680 offset = ftell(mp->mb_otf);
681 retry: switch (need) {
682 case NEED_HEADER:
683 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
684 break;
685 case NEED_BODY:
686 snprintf(o, sizeof o, "RETR %u\r\n", number);
687 break;
688 case NEED_UNSPEC:
689 abort();
691 POP3_OUT(o, MB_COMD|MB_MULT)
692 if (pop3_answer(mp) == STOP) {
693 if (need == NEED_HEADER) {
695 * The TOP POP3 command is optional, so retry
696 * with the entire message.
698 need = NEED_BODY;
699 goto retry;
701 if (interrupts)
702 onintr(0);
703 return STOP;
705 size = 0;
706 lines = 0;
707 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
708 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
709 line[3] == '\0') {
710 mp->mb_active &= ~MB_MULT;
711 break;
713 if (line[0] == '.') {
714 lp = &line[1];
715 linelen--;
716 } else
717 lp = line;
719 * Need to mask 'From ' lines. This cannot be done properly
720 * since some servers pass them as 'From ' and others as
721 * '>From '. Although one could identify the first kind of
722 * server in principle, it is not possible to identify the
723 * second as '>From ' may also come from a server of the
724 * first type as actual data. So do what is absolutely
725 * necessary only - mask 'From '.
727 * If the line is the first line of the message header, it
728 * is likely a real 'From ' line. In this case, it is just
729 * ignored since it violates all standards.
731 if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
732 lp[3] == 'm' && lp[4] == ' ') {
733 if (lines != 0) {
734 fputc('>', mp->mb_otf);
735 size++;
736 } else
737 continue;
739 lines++;
740 if (lp[linelen-1] == '\n' && (linelen == 1 ||
741 lp[linelen-2] == '\r')) {
742 emptyline = linelen <= 2;
743 if (linelen > 2)
744 fwrite(lp, 1, linelen - 2, mp->mb_otf);
745 fputc('\n', mp->mb_otf);
746 size += linelen - 1;
747 } else {
748 emptyline = 0;
749 fwrite(lp, 1, linelen, mp->mb_otf);
750 size += linelen;
753 if (!emptyline) {
755 * This is very ugly; but some POP3 daemons don't end a
756 * message with \r\n\r\n, and we need \n\n for mbox format.
758 fputc('\n', mp->mb_otf);
759 lines++;
760 size++;
762 m->m_size = size;
763 m->m_lines = lines;
764 m->m_block = mailx_blockof(offset);
765 m->m_offset = mailx_offsetof(offset);
766 fflush(mp->mb_otf);
767 switch (need) {
768 case NEED_HEADER:
769 m->m_have |= HAVE_HEADER;
770 break;
771 case NEED_BODY:
772 m->m_have |= HAVE_HEADER|HAVE_BODY;
773 m->m_xlines = m->m_lines;
774 m->m_xsize = m->m_size;
775 break;
776 case NEED_UNSPEC:
777 break;
779 if (line)
780 free(line);
781 if (saveint != SIG_IGN)
782 safe_signal(SIGINT, saveint);
783 if (savepipe != SIG_IGN)
784 safe_signal(SIGPIPE, savepipe);
785 pop3lock--;
786 if (interrupts)
787 onintr(0);
788 return OKAY;
791 enum okay
792 pop3_header(struct message *m)
794 return pop3_get(&mb, m, NEED_HEADER);
798 enum okay
799 pop3_body(struct message *m)
801 return pop3_get(&mb, m, NEED_BODY);
804 static enum okay
805 pop3_exit(struct mailbox *mp)
807 POP3_OUT("QUIT\r\n", MB_COMD)
808 POP3_ANSWER()
809 return OKAY;
812 static enum okay
813 pop3_delete(struct mailbox *mp, int n)
815 char o[LINESIZE];
817 snprintf(o, sizeof o, "DELE %u\r\n", n);
818 POP3_OUT(o, MB_COMD)
819 POP3_ANSWER()
820 return OKAY;
823 static enum okay
824 pop3_update(struct mailbox *mp)
826 FILE *readstat = NULL;
827 struct message *m;
828 int dodel, c, gotcha, held;
830 if (Tflag != NULL) {
831 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
832 Tflag = NULL;
834 if (!edit) {
835 holdbits();
836 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
837 if (m->m_flag & MBOX)
838 c++;
840 if (c > 0)
841 makembox();
843 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
844 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
845 char *id;
847 if ((id = hfield1("message-id", m)) != NULL ||
848 (id = hfieldX("article-id", m)) != NULL)
849 fprintf(readstat, "%s\n", id);
851 if (edit) {
852 dodel = m->m_flag & MDELETED;
853 } else {
854 dodel = !((m->m_flag&MPRESERVE) ||
855 (m->m_flag&MTOUCH) == 0);
857 if (dodel) {
858 pop3_delete(mp, m - message + 1);
859 gotcha++;
860 } else
861 held++;
863 if (readstat != NULL)
864 Fclose(readstat);
865 if (gotcha && edit) {
866 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
867 printf(value("bsdcompat") || value("bsdmsgs") ?
868 catgets(catd, CATSET, 170, "complete\n") :
869 catgets(catd, CATSET, 212, "updated.\n"));
870 } else if (held && !edit) {
871 if (held == 1)
872 printf(catgets(catd, CATSET, 155,
873 "Held 1 message in %s\n"), mailname);
874 else if (held > 1)
875 printf(catgets(catd, CATSET, 156,
876 "Held %d messages in %s\n"), held, mailname);
878 fflush(stdout);
879 return OKAY;
882 void
883 pop3_quit(void)
885 sighandler_type saveint;
886 sighandler_type savepipe;
888 verbose = value("verbose") != NULL;
889 if (mb.mb_sock.s_fd < 0) {
890 fprintf(stderr, catgets(catd, CATSET, 219,
891 "POP3 connection already closed.\n"));
892 return;
894 pop3lock = 1;
895 saveint = safe_signal(SIGINT, SIG_IGN);
896 savepipe = safe_signal(SIGPIPE, SIG_IGN);
897 if (sigsetjmp(pop3jmp, 1)) {
898 safe_signal(SIGINT, saveint);
899 safe_signal(SIGPIPE, saveint);
900 pop3lock = 0;
901 return;
903 if (saveint != SIG_IGN)
904 safe_signal(SIGINT, pop3catch);
905 if (savepipe != SIG_IGN)
906 safe_signal(SIGPIPE, pop3catch);
907 pop3_update(&mb);
908 pop3_exit(&mb);
909 sclose(&mb.mb_sock);
910 safe_signal(SIGINT, saveint);
911 safe_signal(SIGPIPE, savepipe);
912 pop3lock = 0;
914 #else /* !USE_POP3 */
915 static void
916 nopop3(void)
918 fprintf(stderr, catgets(catd, CATSET, 216,
919 "No POP3 support compiled in.\n"));
922 int
923 pop3_setfile(const char *server, int newmail, int isedit)
925 (void)server;
926 (void)newmail;
927 (void)isedit;
928 nopop3();
929 return -1;
932 enum okay
933 pop3_header(struct message *mp)
935 (void)mp;
936 nopop3();
937 return STOP;
940 enum okay
941 pop3_body(struct message *mp)
943 (void)mp;
944 nopop3();
945 return STOP;
948 void
949 pop3_quit(void)
951 nopop3();
954 enum okay
955 pop3_noop(void)
957 nopop3();
958 return STOP;
960 #endif /* USE_POP3 */