cmd3.c: fix compiler warnings..
[s-mailx.git] / pop3.c
blob0f113462af1b595408af769284391ecba9102842
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * Copyright (c) 2002
8 * Gunnar Ritter. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Gunnar Ritter
21 * and his contributors.
22 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #ifndef lint
40 #ifdef DOSCCS
41 static char sccsid[] = "@(#)pop3.c 2.43 (gritter) 3/4/06";
42 #endif
43 #endif /* not lint */
45 #include "config.h"
47 #include "rcv.h"
48 #include "extern.h"
49 #include <errno.h>
50 #include <sys/stat.h>
51 #include <unistd.h>
52 #include <time.h>
54 #include "md5.h"
57 * Mail -- a mail program
59 * POP3 client.
62 #ifdef USE_POP3
63 static int verbose;
65 #define POP3_ANSWER() if (pop3_answer(mp) == STOP) \
66 return STOP;
67 #define POP3_OUT(x, y) if (pop3_finish(mp) == STOP) \
68 return STOP; \
69 if (verbose) \
70 fprintf(stderr, ">>> %s", x); \
71 mp->mb_active |= (y); \
72 if (swrite(&mp->mb_sock, x) == STOP) \
73 return STOP;
75 static char *pop3buf;
76 static size_t pop3bufsize;
77 static sigjmp_buf pop3jmp;
78 static sighandler_type savealrm;
79 static int reset_tio;
80 static struct termios otio;
81 static int pop3keepalive;
82 static volatile int pop3lock;
84 static void pop3_timer_off(void);
85 static enum okay pop3_answer(struct mailbox *mp);
86 static enum okay pop3_finish(struct mailbox *mp);
87 static void pop3catch(int s);
88 static void maincatch(int s);
89 static enum okay pop3_noop1(struct mailbox *mp);
90 static void pop3alarm(int s);
91 static enum okay pop3_pass(struct mailbox *mp, const char *pass);
92 static char *pop3_find_timestamp(const char *bp);
93 static enum okay pop3_apop(struct mailbox *mp, char *xuser, const char *pass,
94 const char *ts);
95 static enum okay pop3_apop1(struct mailbox *mp,
96 const char *user, const char *xp);
97 static int pop3_use_starttls(const char *uhp);
98 static int pop3_use_apop(const char *uhp);
99 static enum okay pop3_user(struct mailbox *mp, char *xuser, const char *pass,
100 const char *uhp, const char *xserver);
101 static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *count);
102 static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
103 static void pop3_init(struct mailbox *mp, int n);
104 static void pop3_dates(struct mailbox *mp);
105 static void pop3_setptr(struct mailbox *mp);
106 static char *pop3_have_password(const char *server);
107 static enum okay pop3_get(struct mailbox *mp, struct message *m,
108 enum needspec need);
109 static enum okay pop3_exit(struct mailbox *mp);
110 static enum okay pop3_delete(struct mailbox *mp, int n);
111 static enum okay pop3_update(struct mailbox *mp);
113 static void
114 pop3_timer_off(void)
116 if (pop3keepalive > 0) {
117 alarm(0);
118 safe_signal(SIGALRM, savealrm);
122 static enum okay
123 pop3_answer(struct mailbox *mp)
125 int sz;
126 enum okay ok = STOP;
128 retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
129 if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
130 goto multiline;
131 if (verbose)
132 fputs(pop3buf, stderr);
133 switch (*pop3buf) {
134 case '+':
135 ok = OKAY;
136 mp->mb_active &= ~MB_COMD;
137 break;
138 case '-':
139 ok = STOP;
140 mp->mb_active = MB_NONE;
141 fprintf(stderr, catgets(catd, CATSET, 218,
142 "POP3 error: %s"), pop3buf);
143 break;
144 default:
146 * If the answer starts neither with '+' nor with
147 * '-', it must be part of a multiline response,
148 * e. g. because the user interrupted a file
149 * download. Get lines until a single dot appears.
151 multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
152 pop3buf[2] != '\n' ||
153 pop3buf[3] != '\0') {
154 sz = sgetline(&pop3buf, &pop3bufsize,
155 NULL, &mp->mb_sock);
156 if (sz <= 0)
157 goto eof;
159 mp->mb_active &= ~MB_MULT;
160 if (mp->mb_active != MB_NONE)
161 goto retry;
163 } else {
164 eof: ok = STOP;
165 mp->mb_active = MB_NONE;
167 return ok;
170 static enum okay
171 pop3_finish(struct mailbox *mp)
173 while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
174 pop3_answer(mp);
175 return OKAY;
178 static void
179 pop3catch(int s)
181 if (reset_tio)
182 tcsetattr(0, TCSADRAIN, &otio);
183 switch (s) {
184 case SIGINT:
185 fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
186 siglongjmp(pop3jmp, 1);
187 break;
188 case SIGPIPE:
189 fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
190 break;
194 static void
195 maincatch(int 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;
244 if (pop3lock++ == 0) {
245 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
246 safe_signal(SIGINT, maincatch);
247 savepipe = safe_signal(SIGPIPE, SIG_IGN);
248 if (sigsetjmp(pop3jmp, 1)) {
249 safe_signal(SIGINT, saveint);
250 safe_signal(SIGPIPE, savepipe);
251 goto brk;
253 if (savepipe != SIG_IGN)
254 safe_signal(SIGPIPE, pop3catch);
255 if (pop3_noop1(&mb) != OKAY) {
256 safe_signal(SIGINT, saveint);
257 safe_signal(SIGPIPE, savepipe);
258 goto out;
260 safe_signal(SIGINT, saveint);
261 safe_signal(SIGPIPE, savepipe);
263 brk: alarm(pop3keepalive);
264 out: pop3lock--;
267 static enum okay
268 pop3_pass(struct mailbox *mp, const char *pass)
270 char o[LINESIZE];
272 snprintf(o, sizeof o, "PASS %s\r\n", pass);
273 POP3_OUT(o, MB_COMD)
274 POP3_ANSWER()
275 return OKAY;
278 static char *
279 pop3_find_timestamp(const char *bp)
281 const char *cp, *ep;
282 char *rp;
283 int hadat = 0;
285 if ((cp = strchr(bp, '<')) == NULL)
286 return NULL;
287 for (ep = cp; *ep; ep++) {
288 if (spacechar(*ep&0377))
289 return NULL;
290 else if (*ep == '@')
291 hadat = 1;
292 else if (*ep == '>') {
293 if (hadat != 1)
294 return NULL;
295 break;
298 if (*ep != '>')
299 return NULL;
300 rp = salloc(ep - cp + 2);
301 memcpy(rp, cp, ep - cp + 1);
302 rp[ep - cp + 1] = '\0';
303 return rp;
306 static enum okay
307 pop3_apop(struct mailbox *mp, char *xuser, const char *pass, const char *ts)
309 char *user, *catp, *xp;
310 unsigned char digest[16];
311 MD5_CTX ctx;
313 retry: if (xuser == NULL) {
314 if ((user = getuser()) == NULL)
315 return STOP;
316 } else
317 user = xuser;
318 if (pass == NULL) {
319 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
320 return STOP;
322 catp = savecat(ts, pass);
323 MD5Init(&ctx);
324 MD5Update(&ctx, (unsigned char *)catp, strlen(catp));
325 MD5Final(digest, &ctx);
326 xp = md5tohex(digest);
327 if (pop3_apop1(mp, user, xp) == STOP) {
328 pass = NULL;
329 goto retry;
331 return OKAY;
334 static enum okay
335 pop3_apop1(struct mailbox *mp, const char *user, const char *xp)
337 char o[LINESIZE];
339 snprintf(o, sizeof o, "APOP %s %s\r\n", user, xp);
340 POP3_OUT(o, MB_COMD)
341 POP3_ANSWER()
342 return OKAY;
345 static int
346 pop3_use_starttls(const char *uhp)
348 char *var;
350 if (value("pop3-use-starttls"))
351 return 1;
352 var = savecat("pop3-use-starttls-", uhp);
353 return value(var) != NULL;
356 static int
357 pop3_use_apop(const char *uhp)
359 char *var;
361 if (value("pop3-use-apop"))
362 return 1;
363 var = savecat("pop3-use-apop-", uhp);
364 return value(var) != NULL;
367 static enum okay
368 pop3_user(struct mailbox *mp, char *xuser, const char *pass,
369 const char *uhp, const char *xserver)
371 char o[LINESIZE], *user, *ts = NULL, *server, *cp;
373 POP3_ANSWER()
374 if (pop3_use_apop(uhp)) {
375 if ((ts = pop3_find_timestamp(pop3buf)) == NULL) {
376 fprintf(stderr, "Could not determine timestamp from "
377 "server greeting. Impossible to use APOP.\n");
378 return STOP;
381 if ((cp = strchr(xserver, ':')) != NULL) {
382 server = salloc(cp - xserver + 1);
383 memcpy(server, xserver, cp - xserver);
384 server[cp - xserver] = '\0';
385 } else
386 server = (char *)xserver;
387 #ifdef USE_SSL
388 if (mp->mb_sock.s_use_ssl == 0 && pop3_use_starttls(uhp)) {
389 POP3_OUT("STLS\r\n", MB_COMD)
390 POP3_ANSWER()
391 if (ssl_open(server, &mp->mb_sock, uhp) != OKAY)
392 return STOP;
394 #else /* !USE_SSL */
395 if (pop3_use_starttls(uhp)) {
396 fprintf(stderr, "No SSL support compiled in.\n");
397 return STOP;
399 #endif /* !USE_SSL */
400 if (ts != NULL)
401 return pop3_apop(mp, xuser, pass, ts);
402 retry: if (xuser == NULL) {
403 if ((user = getuser()) == NULL)
404 return STOP;
405 } else
406 user = xuser;
407 snprintf(o, sizeof o, "USER %s\r\n", user);
408 POP3_OUT(o, MB_COMD)
409 POP3_ANSWER()
410 if (pass == NULL) {
411 if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
412 return STOP;
414 if (pop3_pass(mp, pass) == STOP) {
415 pass = NULL;
416 goto retry;
418 return OKAY;
421 static enum okay
422 pop3_stat(struct mailbox *mp, off_t *size, int *count)
424 char *cp;
425 enum okay ok = OKAY;
427 POP3_OUT("STAT\r\n", MB_COMD);
428 POP3_ANSWER()
429 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
430 while (*cp && spacechar(*cp & 0377))
431 cp++;
432 if (*cp) {
433 *count = (int)strtol(cp, NULL, 10);
434 while (*cp && !spacechar(*cp & 0377))
435 cp++;
436 while (*cp && spacechar(*cp & 0377))
437 cp++;
438 if (*cp)
439 *size = (int)strtol(cp, NULL, 10);
440 else
441 ok = STOP;
442 } else
443 ok = STOP;
444 if (ok == STOP)
445 fprintf(stderr, catgets(catd, CATSET, 260,
446 "invalid POP3 STAT response: %s\n"), pop3buf);
447 return ok;
450 static enum okay
451 pop3_list(struct mailbox *mp, int n, size_t *size)
453 char o[LINESIZE], *cp;
455 snprintf(o, sizeof o, "LIST %u\r\n", n);
456 POP3_OUT(o, MB_COMD)
457 POP3_ANSWER()
458 for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
459 while (*cp && spacechar(*cp & 0377))
460 cp++;
461 while (*cp && !spacechar(*cp & 0377))
462 cp++;
463 while (*cp && spacechar(*cp & 0377))
464 cp++;
465 if (*cp)
466 *size = (size_t)strtol(cp, NULL, 10);
467 else
468 *size = 0;
469 return OKAY;
472 static void
473 pop3_init(struct mailbox *mp, int n)
475 struct message *m = &message[n];
476 char *cp;
478 m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
479 m->m_block = 0;
480 m->m_offset = 0;
481 pop3_list(mp, m - message + 1, &m->m_xsize);
482 if ((cp = hfield("status", m)) != NULL) {
483 while (*cp != '\0') {
484 if (*cp == 'R')
485 m->m_flag |= MREAD;
486 else if (*cp == 'O')
487 m->m_flag &= ~MNEW;
488 cp++;
493 /*ARGSUSED*/
494 static void
495 pop3_dates(struct mailbox *mp)
497 int i;
499 for (i = 0; i < msgCount; i++)
500 substdate(&message[i]);
503 static void
504 pop3_setptr(struct mailbox *mp)
506 int i;
508 message = scalloc(msgCount + 1, sizeof *message);
509 for (i = 0; i < msgCount; i++)
510 pop3_init(mp, i);
511 setdot(message);
512 message[msgCount].m_size = 0;
513 message[msgCount].m_lines = 0;
514 pop3_dates(mp);
517 static char *
518 pop3_have_password(const char *server)
520 char *var, *cp;
522 var = ac_alloc(strlen(server) + 10);
523 strcpy(var, "password-");
524 strcpy(&var[9], server);
525 if ((cp = value(var)) != NULL)
526 cp = savestr(cp);
527 ac_free(var);
528 return cp;
531 int
532 pop3_setfile(const char *server, int newmail, int isedit)
534 struct sock so;
535 sighandler_type saveint;
536 sighandler_type savepipe;
537 char *user;
538 const char *cp, *sp = server, *pass, *uhp;
539 int use_ssl = 0;
541 (void)&sp;
542 (void)&use_ssl;
543 (void)&user;
544 if (newmail)
545 return 1;
546 if (strncmp(sp, "pop3://", 7) == 0) {
547 sp = &sp[7];
548 use_ssl = 0;
549 #ifdef USE_SSL
550 } else if (strncmp(sp, "pop3s://", 8) == 0) {
551 sp = &sp[8];
552 use_ssl = 1;
553 #endif /* USE_SSL */
555 uhp = sp;
556 pass = pop3_have_password(uhp);
557 if ((cp = last_at_before_slash(sp)) != NULL) {
558 user = salloc(cp - sp + 1);
559 memcpy(user, sp, cp - sp);
560 user[cp - sp] = '\0';
561 sp = &cp[1];
562 user = strdec(user);
563 } else
564 user = NULL;
565 verbose = value("verbose") != NULL;
566 if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
567 verbose) != OKAY) {
568 return -1;
570 quit();
571 edit = isedit;
572 if (mb.mb_sock.s_fd >= 0)
573 sclose(&mb.mb_sock);
574 if (mb.mb_itf) {
575 fclose(mb.mb_itf);
576 mb.mb_itf = NULL;
578 if (mb.mb_otf) {
579 fclose(mb.mb_otf);
580 mb.mb_otf = NULL;
582 initbox(server);
583 mb.mb_type = MB_VOID;
584 pop3lock = 1;
585 mb.mb_sock = so;
586 saveint = safe_signal(SIGINT, SIG_IGN);
587 savepipe = safe_signal(SIGPIPE, SIG_IGN);
588 if (sigsetjmp(pop3jmp, 1)) {
589 sclose(&mb.mb_sock);
590 safe_signal(SIGINT, saveint);
591 safe_signal(SIGPIPE, savepipe);
592 pop3lock = 0;
593 return 1;
595 if (saveint != SIG_IGN)
596 safe_signal(SIGINT, pop3catch);
597 if (savepipe != SIG_IGN)
598 safe_signal(SIGPIPE, pop3catch);
599 if ((cp = value("pop3-keepalive")) != NULL) {
600 if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
601 savealrm = safe_signal(SIGALRM, pop3alarm);
602 alarm(pop3keepalive);
605 mb.mb_sock.s_desc = "POP3";
606 mb.mb_sock.s_onclose = pop3_timer_off;
607 if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
608 pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
609 sclose(&mb.mb_sock);
610 pop3_timer_off();
611 safe_signal(SIGINT, saveint);
612 safe_signal(SIGPIPE, savepipe);
613 pop3lock = 0;
614 return 1;
616 mb.mb_type = MB_POP3;
617 mb.mb_perm = Rflag ? 0 : MB_DELE;
618 pop3_setptr(&mb);
619 setmsize(msgCount);
620 sawcom = 0;
621 safe_signal(SIGINT, saveint);
622 safe_signal(SIGPIPE, savepipe);
623 pop3lock = 0;
624 if (!edit && msgCount == 0) {
625 if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
626 fprintf(stderr, catgets(catd, CATSET, 258,
627 "No mail at %s\n"), server);
628 return 1;
630 return 0;
633 static enum okay
634 pop3_get(struct mailbox *mp, struct message *m, enum needspec need)
636 sighandler_type saveint = SIG_IGN;
637 sighandler_type savepipe = SIG_IGN;
638 off_t offset;
639 char o[LINESIZE], *line = NULL, *lp;
640 size_t linesize = 0, linelen, size;
641 int number = m - message + 1;
642 int emptyline = 0, lines;
644 (void)&saveint;
645 (void)&savepipe;
646 (void)&number;
647 (void)&emptyline;
648 (void)&need;
649 verbose = value("verbose") != NULL;
650 if (mp->mb_sock.s_fd < 0) {
651 fprintf(stderr, catgets(catd, CATSET, 219,
652 "POP3 connection already closed.\n"));
653 return STOP;
655 if (pop3lock++ == 0) {
656 if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
657 safe_signal(SIGINT, maincatch);
658 savepipe = safe_signal(SIGPIPE, SIG_IGN);
659 if (sigsetjmp(pop3jmp, 1)) {
660 safe_signal(SIGINT, saveint);
661 safe_signal(SIGPIPE, savepipe);
662 pop3lock--;
663 return STOP;
665 if (savepipe != SIG_IGN)
666 safe_signal(SIGPIPE, pop3catch);
668 fseek(mp->mb_otf, 0L, SEEK_END);
669 offset = ftell(mp->mb_otf);
670 retry: switch (need) {
671 case NEED_HEADER:
672 snprintf(o, sizeof o, "TOP %u 0\r\n", number);
673 break;
674 case NEED_BODY:
675 snprintf(o, sizeof o, "RETR %u\r\n", number);
676 break;
677 case NEED_UNSPEC:
678 abort();
680 POP3_OUT(o, MB_COMD|MB_MULT)
681 if (pop3_answer(mp) == STOP) {
682 if (need == NEED_HEADER) {
684 * The TOP POP3 command is optional, so retry
685 * with the entire message.
687 need = NEED_BODY;
688 goto retry;
690 if (interrupts)
691 onintr(0);
692 return STOP;
694 size = 0;
695 lines = 0;
696 while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
697 if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
698 line[3] == '\0') {
699 mp->mb_active &= ~MB_MULT;
700 break;
702 if (line[0] == '.') {
703 lp = &line[1];
704 linelen--;
705 } else
706 lp = line;
708 * Need to mask 'From ' lines. This cannot be done properly
709 * since some servers pass them as 'From ' and others as
710 * '>From '. Although one could identify the first kind of
711 * server in principle, it is not possible to identify the
712 * second as '>From ' may also come from a server of the
713 * first type as actual data. So do what is absolutely
714 * necessary only - mask 'From '.
716 * If the line is the first line of the message header, it
717 * is likely a real 'From ' line. In this case, it is just
718 * ignored since it violates all standards.
720 if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
721 lp[3] == 'm' && lp[4] == ' ') {
722 if (lines != 0) {
723 fputc('>', mp->mb_otf);
724 size++;
725 } else
726 continue;
728 lines++;
729 if (lp[linelen-1] == '\n' && (linelen == 1 ||
730 lp[linelen-2] == '\r')) {
731 emptyline = linelen <= 2;
732 if (linelen > 2)
733 fwrite(lp, 1, linelen - 2, mp->mb_otf);
734 fputc('\n', mp->mb_otf);
735 size += linelen - 1;
736 } else {
737 emptyline = 0;
738 fwrite(lp, 1, linelen, mp->mb_otf);
739 size += linelen;
742 if (!emptyline) {
744 * This is very ugly; but some POP3 daemons don't end a
745 * message with \r\n\r\n, and we need \n\n for mbox format.
747 fputc('\n', mp->mb_otf);
748 lines++;
749 size++;
751 m->m_size = size;
752 m->m_lines = lines;
753 m->m_block = mailx_blockof(offset);
754 m->m_offset = mailx_offsetof(offset);
755 fflush(mp->mb_otf);
756 switch (need) {
757 case NEED_HEADER:
758 m->m_have |= HAVE_HEADER;
759 break;
760 case NEED_BODY:
761 m->m_have |= HAVE_HEADER|HAVE_BODY;
762 m->m_xlines = m->m_lines;
763 m->m_xsize = m->m_size;
764 break;
765 case NEED_UNSPEC:
766 break;
768 if (line)
769 free(line);
770 if (saveint != SIG_IGN)
771 safe_signal(SIGINT, saveint);
772 if (savepipe != SIG_IGN)
773 safe_signal(SIGPIPE, savepipe);
774 pop3lock--;
775 if (interrupts)
776 onintr(0);
777 return OKAY;
780 enum okay
781 pop3_header(struct message *m)
783 return pop3_get(&mb, m, NEED_HEADER);
787 enum okay
788 pop3_body(struct message *m)
790 return pop3_get(&mb, m, NEED_BODY);
793 static enum okay
794 pop3_exit(struct mailbox *mp)
796 POP3_OUT("QUIT\r\n", MB_COMD)
797 POP3_ANSWER()
798 return OKAY;
801 static enum okay
802 pop3_delete(struct mailbox *mp, int n)
804 char o[LINESIZE];
806 snprintf(o, sizeof o, "DELE %u\r\n", n);
807 POP3_OUT(o, MB_COMD)
808 POP3_ANSWER()
809 return OKAY;
812 static enum okay
813 pop3_update(struct mailbox *mp)
815 FILE *readstat = NULL;
816 struct message *m;
817 int dodel, c, gotcha, held;
819 if (Tflag != NULL) {
820 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
821 Tflag = NULL;
823 if (!edit) {
824 holdbits();
825 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
826 if (m->m_flag & MBOX)
827 c++;
829 if (c > 0)
830 makembox();
832 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
833 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
834 char *id;
836 if ((id = hfield("message-id", m)) != NULL ||
837 (id = hfield("article-id", m)) != NULL)
838 fprintf(readstat, "%s\n", id);
840 if (edit) {
841 dodel = m->m_flag & MDELETED;
842 } else {
843 dodel = !((m->m_flag&MPRESERVE) ||
844 (m->m_flag&MTOUCH) == 0);
846 if (dodel) {
847 pop3_delete(mp, m - message + 1);
848 gotcha++;
849 } else
850 held++;
852 if (readstat != NULL)
853 Fclose(readstat);
854 if (gotcha && edit) {
855 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
856 printf(value("bsdcompat") || value("bsdmsgs") ?
857 catgets(catd, CATSET, 170, "complete\n") :
858 catgets(catd, CATSET, 212, "updated.\n"));
859 } else if (held && !edit) {
860 if (held == 1)
861 printf(catgets(catd, CATSET, 155,
862 "Held 1 message in %s\n"), mailname);
863 else if (held > 1)
864 printf(catgets(catd, CATSET, 156,
865 "Held %d messages in %s\n"), held, mailname);
867 fflush(stdout);
868 return OKAY;
871 void
872 pop3_quit(void)
874 sighandler_type saveint;
875 sighandler_type savepipe;
877 verbose = value("verbose") != NULL;
878 if (mb.mb_sock.s_fd < 0) {
879 fprintf(stderr, catgets(catd, CATSET, 219,
880 "POP3 connection already closed.\n"));
881 return;
883 pop3lock = 1;
884 saveint = safe_signal(SIGINT, SIG_IGN);
885 savepipe = safe_signal(SIGPIPE, SIG_IGN);
886 if (sigsetjmp(pop3jmp, 1)) {
887 safe_signal(SIGINT, saveint);
888 safe_signal(SIGPIPE, saveint);
889 pop3lock = 0;
890 return;
892 if (saveint != SIG_IGN)
893 safe_signal(SIGINT, pop3catch);
894 if (savepipe != SIG_IGN)
895 safe_signal(SIGPIPE, pop3catch);
896 pop3_update(&mb);
897 pop3_exit(&mb);
898 sclose(&mb.mb_sock);
899 safe_signal(SIGINT, saveint);
900 safe_signal(SIGPIPE, savepipe);
901 pop3lock = 0;
903 #else /* !USE_POP3 */
904 static void
905 nopop3(void)
907 fprintf(stderr, catgets(catd, CATSET, 216,
908 "No POP3 support compiled in.\n"));
911 int
912 pop3_setfile(const char *server, int newmail, int isedit)
914 nopop3();
915 return -1;
918 enum okay
919 pop3_header(struct message *mp)
921 nopop3();
922 return STOP;
925 enum okay
926 pop3_body(struct message *mp)
928 nopop3();
929 return STOP;
932 void
933 pop3_quit(void)
935 nopop3();
938 enum okay
939 pop3_noop(void)
941 nopop3();
942 return STOP;
944 #endif /* USE_POP3 */