README: document *next* branch etc.
[s-mailx.git] / pop3.c
blob04509be0ce0dcfa91f300057c1d3a028e9fc005e
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 #ifdef USE_POP3
60 static int verbose;
62 #define POP3_ANSWER() if (pop3_answer(mp) == STOP) \
63 return STOP;
64 #define POP3_OUT(x, y) if (pop3_finish(mp) == STOP) \
65 return STOP; \
66 if (verbose) \
67 fprintf(stderr, ">>> %s", x); \
68 mp->mb_active |= (y); \
69 if (swrite(&mp->mb_sock, x) == STOP) \
70 return STOP;
72 static char *pop3buf;
73 static size_t pop3bufsize;
74 static sigjmp_buf pop3jmp;
75 static sighandler_type savealrm;
76 static int reset_tio;
77 static struct termios otio;
78 static int pop3keepalive;
79 static volatile int pop3lock;
81 static void pop3_timer_off(void);
82 static enum okay pop3_answer(struct mailbox *mp);
83 static enum okay pop3_finish(struct mailbox *mp);
84 static void pop3catch(int s);
85 static void maincatch(int s);
86 static enum okay pop3_noop1(struct mailbox *mp);
87 static void pop3alarm(int s);
88 static enum okay pop3_pass(struct mailbox *mp, const char *pass);
89 #ifdef USE_MD5
90 static char *pop3_find_timestamp(const char *bp);
91 static enum okay pop3_apop(struct mailbox *mp, char *xuser, const char *pass,
92 const char *ts);
93 static enum okay pop3_apop1(struct mailbox *mp,
94 const char *user, const char *xp);
95 static int pop3_use_apop(const char *uhp);
96 #endif
97 static int pop3_use_starttls(const char *uhp);
98 static enum okay pop3_user(struct mailbox *mp, char *xuser, const char *pass,
99 const char *uhp, const char *xserver);
100 static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *count);
101 static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
102 static void pop3_init(struct mailbox *mp, int n);
103 static void pop3_dates(struct mailbox *mp);
104 static void pop3_setptr(struct mailbox *mp);
105 static char *pop3_have_password(const char *server);
106 static enum okay pop3_get(struct mailbox *mp, struct message *m,
107 enum needspec need);
108 static enum okay pop3_exit(struct mailbox *mp);
109 static enum okay pop3_delete(struct mailbox *mp, int n);
110 static enum okay pop3_update(struct mailbox *mp);
112 static void
113 pop3_timer_off(void)
115 if (pop3keepalive > 0) {
116 alarm(0);
117 safe_signal(SIGALRM, savealrm);
121 static enum okay
122 pop3_answer(struct mailbox *mp)
124 int sz;
125 enum okay ok = STOP;
127 retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
128 if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
129 goto multiline;
130 if (verbose)
131 fputs(pop3buf, stderr);
132 switch (*pop3buf) {
133 case '+':
134 ok = OKAY;
135 mp->mb_active &= ~MB_COMD;
136 break;
137 case '-':
138 ok = STOP;
139 mp->mb_active = MB_NONE;
140 fprintf(stderr, catgets(catd, CATSET, 218,
141 "POP3 error: %s"), pop3buf);
142 break;
143 default:
145 * If the answer starts neither with '+' nor with
146 * '-', it must be part of a multiline response,
147 * e. g. because the user interrupted a file
148 * download. Get lines until a single dot appears.
150 multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
151 pop3buf[2] != '\n' ||
152 pop3buf[3] != '\0') {
153 sz = sgetline(&pop3buf, &pop3bufsize,
154 NULL, &mp->mb_sock);
155 if (sz <= 0)
156 goto eof;
158 mp->mb_active &= ~MB_MULT;
159 if (mp->mb_active != MB_NONE)
160 goto retry;
162 } else {
163 eof: ok = STOP;
164 mp->mb_active = MB_NONE;
166 return ok;
169 static enum okay
170 pop3_finish(struct mailbox *mp)
172 while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
173 pop3_answer(mp);
174 return OKAY;
177 static void
178 pop3catch(int s)
180 if (reset_tio)
181 tcsetattr(0, TCSADRAIN, &otio);
182 switch (s) {
183 case SIGINT:
184 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
185 siglongjmp(pop3jmp, 1);
186 break;
187 case SIGPIPE:
188 fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
189 break;
193 static void
194 maincatch(int s)
196 (void)s;
197 if (interrupts++ == 0) {
198 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
199 return;
201 onintr(0);
204 static enum okay
205 pop3_noop1(struct mailbox *mp)
207 POP3_OUT("NOOP\r\n", MB_COMD)
208 POP3_ANSWER()
209 return OKAY;
212 enum okay
213 pop3_noop(void)
215 enum okay ok = STOP;
216 sighandler_type saveint, savepipe;
218 (void)&saveint;
219 (void)&savepipe;
220 (void)&ok;
221 verbose = value("verbose") != NULL;
222 pop3lock = 1;
223 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
224 safe_signal(SIGINT, maincatch);
225 savepipe = safe_signal(SIGPIPE, SIG_IGN);
226 if (sigsetjmp(pop3jmp, 1) == 0) {
227 if (savepipe != SIG_IGN)
228 safe_signal(SIGPIPE, pop3catch);
229 ok = pop3_noop1(&mb);
231 safe_signal(SIGINT, saveint);
232 safe_signal(SIGPIPE, savepipe);
233 pop3lock = 0;
234 return ok;
237 /*ARGSUSED*/
238 static void
239 pop3alarm(int s)
241 sighandler_type saveint;
242 sighandler_type savepipe;
243 (void)s;
245 if (pop3lock++ == 0) {
246 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
247 safe_signal(SIGINT, maincatch);
248 savepipe = safe_signal(SIGPIPE, SIG_IGN);
249 if (sigsetjmp(pop3jmp, 1)) {
250 safe_signal(SIGINT, saveint);
251 safe_signal(SIGPIPE, savepipe);
252 goto brk;
254 if (savepipe != SIG_IGN)
255 safe_signal(SIGPIPE, pop3catch);
256 if (pop3_noop1(&mb) != OKAY) {
257 safe_signal(SIGINT, saveint);
258 safe_signal(SIGPIPE, savepipe);
259 goto out;
261 safe_signal(SIGINT, saveint);
262 safe_signal(SIGPIPE, savepipe);
264 brk: alarm(pop3keepalive);
265 out: pop3lock--;
268 static enum okay
269 pop3_pass(struct mailbox *mp, const char *pass)
271 char o[LINESIZE];
273 snprintf(o, sizeof o, "PASS %s\r\n", pass);
274 POP3_OUT(o, MB_COMD)
275 POP3_ANSWER()
276 return OKAY;
279 #ifdef USE_MD5
280 static char *
281 pop3_find_timestamp(const char *bp)
283 const char *cp, *ep;
284 char *rp;
285 int hadat = 0;
287 if ((cp = strchr(bp, '<')) == NULL)
288 return NULL;
289 for (ep = cp; *ep; ep++) {
290 if (spacechar(*ep&0377))
291 return NULL;
292 else if (*ep == '@')
293 hadat = 1;
294 else if (*ep == '>') {
295 if (hadat != 1)
296 return NULL;
297 break;
300 if (*ep != '>')
301 return NULL;
302 rp = salloc(ep - cp + 2);
303 memcpy(rp, cp, ep - cp + 1);
304 rp[ep - cp + 1] = '\0';
305 return rp;
308 static enum okay
309 pop3_apop(struct mailbox *mp, char *xuser, const char *pass, const char *ts)
311 char *user, *catp, *xp;
312 unsigned char digest[16];
313 MD5_CTX ctx;
315 retry: if (xuser == NULL) {
316 if ((user = getuser()) == NULL)
317 return STOP;
318 } else
319 user = xuser;
320 if (pass == NULL) {
321 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
322 return STOP;
324 catp = savecat(ts, pass);
325 MD5Init(&ctx);
326 MD5Update(&ctx, (unsigned char *)catp, strlen(catp));
327 MD5Final(digest, &ctx);
328 xp = md5tohex(digest);
329 if (pop3_apop1(mp, user, xp) == STOP) {
330 pass = NULL;
331 goto retry;
333 return OKAY;
336 static enum okay
337 pop3_apop1(struct mailbox *mp, const char *user, const char *xp)
339 char o[LINESIZE];
341 snprintf(o, sizeof o, "APOP %s %s\r\n", user, xp);
342 POP3_OUT(o, MB_COMD)
343 POP3_ANSWER()
344 return OKAY;
347 static int
348 pop3_use_apop(const char *uhp)
350 char *var;
352 if (value("pop3-use-apop"))
353 return 1;
354 var = savecat("pop3-use-apop-", uhp);
355 return value(var) != NULL;
357 #endif /* USE_MD5 */
359 static int
360 pop3_use_starttls(const char *uhp)
362 char *var;
364 if (value("pop3-use-starttls"))
365 return 1;
366 var = savecat("pop3-use-starttls-", uhp);
367 return value(var) != NULL;
370 static enum okay
371 pop3_user(struct mailbox *mp, char *xuser, const char *pass,
372 const char *uhp, const char *xserver)
374 char o[LINESIZE], *user, *server, *cp;
375 #ifdef USE_MD5
376 char *ts = NULL;
377 #endif
379 POP3_ANSWER()
380 #ifdef USE_MD5
381 if (pop3_use_apop(uhp)) {
382 if ((ts = pop3_find_timestamp(pop3buf)) == NULL) {
383 fprintf(stderr, tr(276,
384 "Could not determine timestamp from "
385 "server greeting. Can't use APOP.\n"));
386 return STOP;
389 #endif
390 if ((cp = strchr(xserver, ':')) != NULL) {
391 server = salloc(cp - xserver + 1);
392 memcpy(server, xserver, cp - xserver);
393 server[cp - xserver] = '\0';
394 } else
395 server = (char *)xserver;
396 #ifdef USE_SSL
397 if (mp->mb_sock.s_use_ssl == 0 && pop3_use_starttls(uhp)) {
398 POP3_OUT("STLS\r\n", MB_COMD)
399 POP3_ANSWER()
400 if (ssl_open(server, &mp->mb_sock, uhp) != OKAY)
401 return STOP;
403 #else /* !USE_SSL */
404 if (pop3_use_starttls(uhp)) {
405 fprintf(stderr, "No SSL support compiled in.\n");
406 return STOP;
408 #endif /* !USE_SSL */
409 #ifdef USE_MD5
410 if (ts != NULL)
411 return pop3_apop(mp, xuser, pass, ts);
412 #endif
413 retry: if (xuser == NULL) {
414 if ((user = getuser()) == NULL)
415 return STOP;
416 } else
417 user = xuser;
418 snprintf(o, sizeof o, "USER %s\r\n", user);
419 POP3_OUT(o, MB_COMD)
420 POP3_ANSWER()
421 if (pass == NULL) {
422 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
423 return STOP;
425 if (pop3_pass(mp, pass) == STOP) {
426 pass = NULL;
427 goto retry;
429 return OKAY;
432 static enum okay
433 pop3_stat(struct mailbox *mp, off_t *size, int *count)
435 char *cp;
436 enum okay ok = OKAY;
438 POP3_OUT("STAT\r\n", MB_COMD);
439 POP3_ANSWER()
440 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
441 while (*cp && spacechar(*cp & 0377))
442 cp++;
443 if (*cp) {
444 *count = (int)strtol(cp, NULL, 10);
445 while (*cp && !spacechar(*cp & 0377))
446 cp++;
447 while (*cp && spacechar(*cp & 0377))
448 cp++;
449 if (*cp)
450 *size = (int)strtol(cp, NULL, 10);
451 else
452 ok = STOP;
453 } else
454 ok = STOP;
455 if (ok == STOP)
456 fprintf(stderr, catgets(catd, CATSET, 260,
457 "invalid POP3 STAT response: %s\n"), pop3buf);
458 return ok;
461 static enum okay
462 pop3_list(struct mailbox *mp, int n, size_t *size)
464 char o[LINESIZE], *cp;
466 snprintf(o, sizeof o, "LIST %u\r\n", n);
467 POP3_OUT(o, MB_COMD)
468 POP3_ANSWER()
469 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
470 while (*cp && spacechar(*cp & 0377))
471 cp++;
472 while (*cp && !spacechar(*cp & 0377))
473 cp++;
474 while (*cp && spacechar(*cp & 0377))
475 cp++;
476 if (*cp)
477 *size = (size_t)strtol(cp, NULL, 10);
478 else
479 *size = 0;
480 return OKAY;
483 static void
484 pop3_init(struct mailbox *mp, int n)
486 struct message *m = &message[n];
487 char *cp;
489 m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
490 m->m_block = 0;
491 m->m_offset = 0;
492 pop3_list(mp, m - message + 1, &m->m_xsize);
493 if ((cp = hfield1("status", m)) != NULL) {
494 while (*cp != '\0') {
495 if (*cp == 'R')
496 m->m_flag |= MREAD;
497 else if (*cp == 'O')
498 m->m_flag &= ~MNEW;
499 cp++;
504 /*ARGSUSED*/
505 static void
506 pop3_dates(struct mailbox *mp)
508 int i;
509 (void)mp;
511 for (i = 0; i < msgCount; i++)
512 substdate(&message[i]);
515 static void
516 pop3_setptr(struct mailbox *mp)
518 int i;
520 message = scalloc(msgCount + 1, sizeof *message);
521 for (i = 0; i < msgCount; i++)
522 pop3_init(mp, i);
523 setdot(message);
524 message[msgCount].m_size = 0;
525 message[msgCount].m_lines = 0;
526 pop3_dates(mp);
529 static char *
530 pop3_have_password(const char *server)
532 char *var, *cp;
534 var = ac_alloc(strlen(server) + 10);
535 strcpy(var, "password-");
536 strcpy(&var[9], server);
537 if ((cp = value(var)) != NULL)
538 cp = savestr(cp);
539 ac_free(var);
540 return cp;
543 int
544 pop3_setfile(const char *server, int newmail, int isedit)
546 struct sock so;
547 sighandler_type saveint;
548 sighandler_type savepipe;
549 char *user;
550 const char *cp, *uhp, *volatile pass, *volatile sp = server;
551 int use_ssl = 0;
553 if (newmail)
554 return 1;
555 if (strncmp(sp, "pop3://", 7) == 0) {
556 sp = &sp[7];
557 use_ssl = 0;
558 #ifdef USE_SSL
559 } else if (strncmp(sp, "pop3s://", 8) == 0) {
560 sp = &sp[8];
561 use_ssl = 1;
562 #endif
564 uhp = sp;
565 pass = pop3_have_password(uhp);
566 if ((cp = last_at_before_slash(sp)) != NULL) {
567 user = salloc(cp - sp + 1);
568 memcpy(user, sp, cp - sp);
569 user[cp - sp] = '\0';
570 sp = &cp[1];
571 user = strdec(user);
572 } else
573 user = NULL;
574 verbose = value("verbose") != NULL;
575 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
576 verbose) != OKAY) {
577 return -1;
579 quit();
580 edit = isedit;
581 if (mb.mb_sock.s_fd >= 0)
582 sclose(&mb.mb_sock);
583 if (mb.mb_itf) {
584 fclose(mb.mb_itf);
585 mb.mb_itf = NULL;
587 if (mb.mb_otf) {
588 fclose(mb.mb_otf);
589 mb.mb_otf = NULL;
591 initbox(server);
592 mb.mb_type = MB_VOID;
593 pop3lock = 1;
594 mb.mb_sock = so;
595 saveint = safe_signal(SIGINT, SIG_IGN);
596 savepipe = safe_signal(SIGPIPE, SIG_IGN);
597 if (sigsetjmp(pop3jmp, 1)) {
598 sclose(&mb.mb_sock);
599 safe_signal(SIGINT, saveint);
600 safe_signal(SIGPIPE, savepipe);
601 pop3lock = 0;
602 return 1;
604 if (saveint != SIG_IGN)
605 safe_signal(SIGINT, pop3catch);
606 if (savepipe != SIG_IGN)
607 safe_signal(SIGPIPE, pop3catch);
608 if ((cp = value("pop3-keepalive")) != NULL) {
609 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
610 savealrm = safe_signal(SIGALRM, pop3alarm);
611 alarm(pop3keepalive);
614 mb.mb_sock.s_desc = "POP3";
615 mb.mb_sock.s_onclose = pop3_timer_off;
616 if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
617 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
618 sclose(&mb.mb_sock);
619 pop3_timer_off();
620 safe_signal(SIGINT, saveint);
621 safe_signal(SIGPIPE, savepipe);
622 pop3lock = 0;
623 return 1;
625 mb.mb_type = MB_POP3;
626 mb.mb_perm = Rflag ? 0 : MB_DELE;
627 pop3_setptr(&mb);
628 setmsize(msgCount);
629 sawcom = 0;
630 safe_signal(SIGINT, saveint);
631 safe_signal(SIGPIPE, savepipe);
632 pop3lock = 0;
633 if (!edit && msgCount == 0) {
634 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
635 fprintf(stderr, catgets(catd, CATSET, 258,
636 "No mail at %s\n"), server);
637 return 1;
639 return 0;
642 static enum okay
643 pop3_get(struct mailbox *mp, struct message *m, enum needspec volatile need)
645 sighandler_type volatile saveint = SIG_IGN, 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, emptyline = 0, lines;
651 (void)&saveint;
652 (void)&savepipe;
653 (void)&number;
654 (void)&emptyline;
655 (void)&need;
656 verbose = value("verbose") != NULL;
657 if (mp->mb_sock.s_fd < 0) {
658 fprintf(stderr, catgets(catd, CATSET, 219,
659 "POP3 connection already closed.\n"));
660 return STOP;
662 if (pop3lock++ == 0) {
663 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
664 safe_signal(SIGINT, maincatch);
665 savepipe = safe_signal(SIGPIPE, SIG_IGN);
666 if (sigsetjmp(pop3jmp, 1)) {
667 safe_signal(SIGINT, saveint);
668 safe_signal(SIGPIPE, savepipe);
669 pop3lock--;
670 return STOP;
672 if (savepipe != SIG_IGN)
673 safe_signal(SIGPIPE, pop3catch);
675 fseek(mp->mb_otf, 0L, SEEK_END);
676 offset = ftell(mp->mb_otf);
677 retry: switch (need) {
678 case NEED_HEADER:
679 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
680 break;
681 case NEED_BODY:
682 snprintf(o, sizeof o, "RETR %u\r\n", number);
683 break;
684 case NEED_UNSPEC:
685 abort();
687 POP3_OUT(o, MB_COMD|MB_MULT)
688 if (pop3_answer(mp) == STOP) {
689 if (need == NEED_HEADER) {
691 * The TOP POP3 command is optional, so retry
692 * with the entire message.
694 need = NEED_BODY;
695 goto retry;
697 if (interrupts)
698 onintr(0);
699 return STOP;
701 size = 0;
702 lines = 0;
703 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
704 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
705 line[3] == '\0') {
706 mp->mb_active &= ~MB_MULT;
707 break;
709 if (line[0] == '.') {
710 lp = &line[1];
711 linelen--;
712 } else
713 lp = line;
715 * Need to mask 'From ' lines. This cannot be done properly
716 * since some servers pass them as 'From ' and others as
717 * '>From '. Although one could identify the first kind of
718 * server in principle, it is not possible to identify the
719 * second as '>From ' may also come from a server of the
720 * first type as actual data. So do what is absolutely
721 * necessary only - mask 'From '.
723 * If the line is the first line of the message header, it
724 * is likely a real 'From ' line. In this case, it is just
725 * ignored since it violates all standards.
727 if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
728 lp[3] == 'm' && lp[4] == ' ') {
729 if (lines != 0) {
730 fputc('>', mp->mb_otf);
731 size++;
732 } else
733 continue;
735 lines++;
736 if (lp[linelen-1] == '\n' && (linelen == 1 ||
737 lp[linelen-2] == '\r')) {
738 emptyline = linelen <= 2;
739 if (linelen > 2)
740 fwrite(lp, 1, linelen - 2, mp->mb_otf);
741 fputc('\n', mp->mb_otf);
742 size += linelen - 1;
743 } else {
744 emptyline = 0;
745 fwrite(lp, 1, linelen, mp->mb_otf);
746 size += linelen;
749 if (!emptyline) {
751 * This is very ugly; but some POP3 daemons don't end a
752 * message with \r\n\r\n, and we need \n\n for mbox format.
754 fputc('\n', mp->mb_otf);
755 lines++;
756 size++;
758 m->m_size = size;
759 m->m_lines = lines;
760 m->m_block = mailx_blockof(offset);
761 m->m_offset = mailx_offsetof(offset);
762 fflush(mp->mb_otf);
763 switch (need) {
764 case NEED_HEADER:
765 m->m_have |= HAVE_HEADER;
766 break;
767 case NEED_BODY:
768 m->m_have |= HAVE_HEADER|HAVE_BODY;
769 m->m_xlines = m->m_lines;
770 m->m_xsize = m->m_size;
771 break;
772 case NEED_UNSPEC:
773 break;
775 if (line)
776 free(line);
777 if (saveint != SIG_IGN)
778 safe_signal(SIGINT, saveint);
779 if (savepipe != SIG_IGN)
780 safe_signal(SIGPIPE, savepipe);
781 pop3lock--;
782 if (interrupts)
783 onintr(0);
784 return OKAY;
787 enum okay
788 pop3_header(struct message *m)
790 return pop3_get(&mb, m, NEED_HEADER);
794 enum okay
795 pop3_body(struct message *m)
797 return pop3_get(&mb, m, NEED_BODY);
800 static enum okay
801 pop3_exit(struct mailbox *mp)
803 POP3_OUT("QUIT\r\n", MB_COMD)
804 POP3_ANSWER()
805 return OKAY;
808 static enum okay
809 pop3_delete(struct mailbox *mp, int n)
811 char o[LINESIZE];
813 snprintf(o, sizeof o, "DELE %u\r\n", n);
814 POP3_OUT(o, MB_COMD)
815 POP3_ANSWER()
816 return OKAY;
819 static enum okay
820 pop3_update(struct mailbox *mp)
822 FILE *readstat = NULL;
823 struct message *m;
824 int dodel, c, gotcha, held;
826 if (Tflag != NULL) {
827 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
828 Tflag = NULL;
830 if (!edit) {
831 holdbits();
832 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
833 if (m->m_flag & MBOX)
834 c++;
836 if (c > 0)
837 makembox();
839 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
840 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
841 char *id;
843 if ((id = hfield1("message-id", m)) != NULL ||
844 (id = hfieldX("article-id", m)) != NULL)
845 fprintf(readstat, "%s\n", id);
847 if (edit) {
848 dodel = m->m_flag & MDELETED;
849 } else {
850 dodel = !((m->m_flag&MPRESERVE) ||
851 (m->m_flag&MTOUCH) == 0);
853 if (dodel) {
854 pop3_delete(mp, m - message + 1);
855 gotcha++;
856 } else
857 held++;
859 if (readstat != NULL)
860 Fclose(readstat);
861 if (gotcha && edit) {
862 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
863 printf(value("bsdcompat") || value("bsdmsgs") ?
864 catgets(catd, CATSET, 170, "complete\n") :
865 catgets(catd, CATSET, 212, "updated.\n"));
866 } else if (held && !edit) {
867 if (held == 1)
868 printf(catgets(catd, CATSET, 155,
869 "Held 1 message in %s\n"), mailname);
870 else if (held > 1)
871 printf(catgets(catd, CATSET, 156,
872 "Held %d messages in %s\n"), held, mailname);
874 fflush(stdout);
875 return OKAY;
878 void
879 pop3_quit(void)
881 sighandler_type saveint;
882 sighandler_type savepipe;
884 verbose = value("verbose") != NULL;
885 if (mb.mb_sock.s_fd < 0) {
886 fprintf(stderr, catgets(catd, CATSET, 219,
887 "POP3 connection already closed.\n"));
888 return;
890 pop3lock = 1;
891 saveint = safe_signal(SIGINT, SIG_IGN);
892 savepipe = safe_signal(SIGPIPE, SIG_IGN);
893 if (sigsetjmp(pop3jmp, 1)) {
894 safe_signal(SIGINT, saveint);
895 safe_signal(SIGPIPE, saveint);
896 pop3lock = 0;
897 return;
899 if (saveint != SIG_IGN)
900 safe_signal(SIGINT, pop3catch);
901 if (savepipe != SIG_IGN)
902 safe_signal(SIGPIPE, pop3catch);
903 pop3_update(&mb);
904 pop3_exit(&mb);
905 sclose(&mb.mb_sock);
906 safe_signal(SIGINT, saveint);
907 safe_signal(SIGPIPE, savepipe);
908 pop3lock = 0;
910 #else /* !USE_POP3 */
911 static void
912 nopop3(void)
914 fprintf(stderr, catgets(catd, CATSET, 216,
915 "No POP3 support compiled in.\n"));
918 int
919 pop3_setfile(const char *server, int newmail, int isedit)
921 (void)server;
922 (void)newmail;
923 (void)isedit;
924 nopop3();
925 return -1;
928 enum okay
929 pop3_header(struct message *mp)
931 (void)mp;
932 nopop3();
933 return STOP;
936 enum okay
937 pop3_body(struct message *mp)
939 (void)mp;
940 nopop3();
941 return STOP;
944 void
945 pop3_quit(void)
947 nopop3();
950 enum okay
951 pop3_noop(void)
953 nopop3();
954 return STOP;
956 #endif /* USE_POP3 */