/*
* Heirloom mailx - a mail user agent derived from Berkeley Mail.
*
* Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
*/
/*
* Copyright (c) 2002
* Gunnar Ritter. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Gunnar Ritter
* and his contributors.
* 4. Neither the name of Gunnar Ritter nor the names of his contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
#ifdef DOSCCS
static char sccsid[] = "@(#)pop3.c 2.43 (gritter) 3/4/06";
#endif
#endif /* not lint */
#include "config.h"
#include "rcv.h"
#include "extern.h"
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include "md5.h"
/*
* Mail -- a mail program
*
* POP3 client.
*/
#ifdef HAVE_SOCKETS
static int verbose;
#define POP3_ANSWER() if (pop3_answer(mp) == STOP) \
return STOP;
#define POP3_OUT(x, y) if (pop3_finish(mp) == STOP) \
return STOP; \
if (verbose) \
fprintf(stderr, ">>> %s", x); \
mp->mb_active |= (y); \
if (swrite(&mp->mb_sock, x) == STOP) \
return STOP;
static char *pop3buf;
static size_t pop3bufsize;
static sigjmp_buf pop3jmp;
static sighandler_type savealrm;
static int reset_tio;
static struct termios otio;
static int pop3keepalive;
static volatile int pop3lock;
static void pop3_timer_off(void);
static enum okay pop3_answer(struct mailbox *mp);
static enum okay pop3_finish(struct mailbox *mp);
static void pop3catch(int s);
static void maincatch(int s);
static enum okay pop3_noop1(struct mailbox *mp);
static void pop3alarm(int s);
static enum okay pop3_pass(struct mailbox *mp, const char *pass);
static char *pop3_find_timestamp(const char *bp);
static enum okay pop3_apop(struct mailbox *mp, char *xuser, const char *pass,
const char *ts);
static enum okay pop3_apop1(struct mailbox *mp,
const char *user, const char *xp);
static int pop3_use_starttls(const char *uhp);
static int pop3_use_apop(const char *uhp);
static enum okay pop3_user(struct mailbox *mp, char *xuser, const char *pass,
const char *uhp, const char *xserver);
static enum okay pop3_stat(struct mailbox *mp, off_t *size, int *count);
static enum okay pop3_list(struct mailbox *mp, int n, size_t *size);
static void pop3_init(struct mailbox *mp, int n);
static void pop3_dates(struct mailbox *mp);
static void pop3_setptr(struct mailbox *mp);
static char *pop3_have_password(const char *server);
static enum okay pop3_get(struct mailbox *mp, struct message *m,
enum needspec need);
static enum okay pop3_exit(struct mailbox *mp);
static enum okay pop3_delete(struct mailbox *mp, int n);
static enum okay pop3_update(struct mailbox *mp);
static void
pop3_timer_off(void)
{
if (pop3keepalive > 0) {
alarm(0);
safe_signal(SIGALRM, savealrm);
}
}
static enum okay
pop3_answer(struct mailbox *mp)
{
int sz;
enum okay ok = STOP;
retry: if ((sz = sgetline(&pop3buf, &pop3bufsize, NULL, &mp->mb_sock)) > 0) {
if ((mp->mb_active & (MB_COMD|MB_MULT)) == MB_MULT)
goto multiline;
if (verbose)
fputs(pop3buf, stderr);
switch (*pop3buf) {
case '+':
ok = OKAY;
mp->mb_active &= ~MB_COMD;
break;
case '-':
ok = STOP;
mp->mb_active = MB_NONE;
fprintf(stderr, catgets(catd, CATSET, 218,
"POP3 error: %s"), pop3buf);
break;
default:
/*
* If the answer starts neither with '+' nor with
* '-', it must be part of a multiline response,
* e. g. because the user interrupted a file
* download. Get lines until a single dot appears.
*/
multiline: while (pop3buf[0] != '.' || pop3buf[1] != '\r' ||
pop3buf[2] != '\n' ||
pop3buf[3] != '\0') {
sz = sgetline(&pop3buf, &pop3bufsize,
NULL, &mp->mb_sock);
if (sz <= 0)
goto eof;
}
mp->mb_active &= ~MB_MULT;
if (mp->mb_active != MB_NONE)
goto retry;
}
} else {
eof: ok = STOP;
mp->mb_active = MB_NONE;
}
return ok;
}
static enum okay
pop3_finish(struct mailbox *mp)
{
while (mp->mb_sock.s_fd > 0 && mp->mb_active != MB_NONE)
pop3_answer(mp);
return OKAY;
}
static void
pop3catch(int s)
{
if (reset_tio)
tcsetattr(0, TCSADRAIN, &otio);
switch (s) {
case SIGINT:
fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
siglongjmp(pop3jmp, 1);
break;
case SIGPIPE:
fprintf(stderr, "Received SIGPIPE during POP3 operation\n");
break;
}
}
static void
maincatch(int s)
{
if (interrupts++ == 0) {
fprintf(stderr, catgets(catd, CATSET, 102, "Interrupt\n"));
return;
}
onintr(0);
}
static enum okay
pop3_noop1(struct mailbox *mp)
{
POP3_OUT("NOOP\r\n", MB_COMD)
POP3_ANSWER()
return OKAY;
}
enum okay
pop3_noop(void)
{
enum okay ok = STOP;
sighandler_type saveint, savepipe;
(void)&saveint;
(void)&savepipe;
(void)&ok;
verbose = value("verbose") != NULL;
pop3lock = 1;
if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
safe_signal(SIGINT, maincatch);
savepipe = safe_signal(SIGPIPE, SIG_IGN);
if (sigsetjmp(pop3jmp, 1) == 0) {
if (savepipe != SIG_IGN)
safe_signal(SIGPIPE, pop3catch);
ok = pop3_noop1(&mb);
}
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
pop3lock = 0;
return ok;
}
/*ARGSUSED*/
static void
pop3alarm(int s)
{
sighandler_type saveint;
sighandler_type savepipe;
if (pop3lock++ == 0) {
if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
safe_signal(SIGINT, maincatch);
savepipe = safe_signal(SIGPIPE, SIG_IGN);
if (sigsetjmp(pop3jmp, 1)) {
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
goto brk;
}
if (savepipe != SIG_IGN)
safe_signal(SIGPIPE, pop3catch);
if (pop3_noop1(&mb) != OKAY) {
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
goto out;
}
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
}
brk: alarm(pop3keepalive);
out: pop3lock--;
}
static enum okay
pop3_pass(struct mailbox *mp, const char *pass)
{
char o[LINESIZE];
snprintf(o, sizeof o, "PASS %s\r\n", pass);
POP3_OUT(o, MB_COMD)
POP3_ANSWER()
return OKAY;
}
static char *
pop3_find_timestamp(const char *bp)
{
const char *cp, *ep;
char *rp;
int hadat = 0;
if ((cp = strchr(bp, '<')) == NULL)
return NULL;
for (ep = cp; *ep; ep++) {
if (spacechar(*ep&0377))
return NULL;
else if (*ep == '@')
hadat = 1;
else if (*ep == '>') {
if (hadat != 1)
return NULL;
break;
}
}
if (*ep != '>')
return NULL;
rp = salloc(ep - cp + 2);
memcpy(rp, cp, ep - cp + 1);
rp[ep - cp + 1] = '\0';
return rp;
}
static enum okay
pop3_apop(struct mailbox *mp, char *xuser, const char *pass, const char *ts)
{
char *user, *catp, *xp;
unsigned char digest[16];
MD5_CTX ctx;
retry: if (xuser == NULL) {
if ((user = getuser()) == NULL)
return STOP;
} else
user = xuser;
if (pass == NULL) {
if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
return STOP;
}
catp = savecat(ts, pass);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *)catp, strlen(catp));
MD5Final(digest, &ctx);
xp = md5tohex(digest);
if (pop3_apop1(mp, user, xp) == STOP) {
pass = NULL;
goto retry;
}
return OKAY;
}
static enum okay
pop3_apop1(struct mailbox *mp, const char *user, const char *xp)
{
char o[LINESIZE];
snprintf(o, sizeof o, "APOP %s %s\r\n", user, xp);
POP3_OUT(o, MB_COMD)
POP3_ANSWER()
return OKAY;
}
static int
pop3_use_starttls(const char *uhp)
{
char *var;
if (value("pop3-use-starttls"))
return 1;
var = savecat("pop3-use-starttls-", uhp);
return value(var) != NULL;
}
static int
pop3_use_apop(const char *uhp)
{
char *var;
if (value("pop3-use-apop"))
return 1;
var = savecat("pop3-use-apop-", uhp);
return value(var) != NULL;
}
static enum okay
pop3_user(struct mailbox *mp, char *xuser, const char *pass,
const char *uhp, const char *xserver)
{
char o[LINESIZE], *user, *ts = NULL, *server, *cp;
POP3_ANSWER()
if (pop3_use_apop(uhp)) {
if ((ts = pop3_find_timestamp(pop3buf)) == NULL) {
fprintf(stderr, "Could not determine timestamp from "
"server greeting. Impossible to use APOP.\n");
return STOP;
}
}
if ((cp = strchr(xserver, ':')) != NULL) {
server = salloc(cp - xserver + 1);
memcpy(server, xserver, cp - xserver);
server[cp - xserver] = '\0';
} else
server = (char *)xserver;
#ifdef USE_SSL
if (mp->mb_sock.s_use_ssl == 0 && pop3_use_starttls(uhp)) {
POP3_OUT("STLS\r\n", MB_COMD)
POP3_ANSWER()
if (ssl_open(server, &mp->mb_sock, uhp) != OKAY)
return STOP;
}
#else /* !USE_SSL */
if (pop3_use_starttls(uhp)) {
fprintf(stderr, "No SSL support compiled in.\n");
return STOP;
}
#endif /* !USE_SSL */
if (ts != NULL)
return pop3_apop(mp, xuser, pass, ts);
retry: if (xuser == NULL) {
if ((user = getuser()) == NULL)
return STOP;
} else
user = xuser;
snprintf(o, sizeof o, "USER %s\r\n", user);
POP3_OUT(o, MB_COMD)
POP3_ANSWER()
if (pass == NULL) {
if ((pass = getpassword(&otio, &reset_tio, NULL)) == NULL)
return STOP;
}
if (pop3_pass(mp, pass) == STOP) {
pass = NULL;
goto retry;
}
return OKAY;
}
static enum okay
pop3_stat(struct mailbox *mp, off_t *size, int *count)
{
char *cp;
enum okay ok = OKAY;
POP3_OUT("STAT\r\n", MB_COMD);
POP3_ANSWER()
for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
while (*cp && spacechar(*cp & 0377))
cp++;
if (*cp) {
*count = (int)strtol(cp, NULL, 10);
while (*cp && !spacechar(*cp & 0377))
cp++;
while (*cp && spacechar(*cp & 0377))
cp++;
if (*cp)
*size = (int)strtol(cp, NULL, 10);
else
ok = STOP;
} else
ok = STOP;
if (ok == STOP)
fprintf(stderr, catgets(catd, CATSET, 260,
"invalid POP3 STAT response: %s\n"), pop3buf);
return ok;
}
static enum okay
pop3_list(struct mailbox *mp, int n, size_t *size)
{
char o[LINESIZE], *cp;
snprintf(o, sizeof o, "LIST %u\r\n", n);
POP3_OUT(o, MB_COMD)
POP3_ANSWER()
for (cp = pop3buf; *cp && !spacechar(*cp & 0377); cp++);
while (*cp && spacechar(*cp & 0377))
cp++;
while (*cp && !spacechar(*cp & 0377))
cp++;
while (*cp && spacechar(*cp & 0377))
cp++;
if (*cp)
*size = (size_t)strtol(cp, NULL, 10);
else
*size = 0;
return OKAY;
}
static void
pop3_init(struct mailbox *mp, int n)
{
struct message *m = &message[n];
char *cp;
m->m_flag = MUSED|MNEW|MNOFROM|MNEWEST;
m->m_block = 0;
m->m_offset = 0;
pop3_list(mp, m - message + 1, &m->m_xsize);
if ((cp = hfield("status", m)) != NULL) {
while (*cp != '\0') {
if (*cp == 'R')
m->m_flag |= MREAD;
else if (*cp == 'O')
m->m_flag &= ~MNEW;
cp++;
}
}
}
/*ARGSUSED*/
static void
pop3_dates(struct mailbox *mp)
{
int i;
for (i = 0; i < msgCount; i++)
substdate(&message[i]);
}
static void
pop3_setptr(struct mailbox *mp)
{
int i;
message = scalloc(msgCount + 1, sizeof *message);
for (i = 0; i < msgCount; i++)
pop3_init(mp, i);
setdot(message);
message[msgCount].m_size = 0;
message[msgCount].m_lines = 0;
pop3_dates(mp);
}
static char *
pop3_have_password(const char *server)
{
char *var, *cp;
var = ac_alloc(strlen(server) + 10);
strcpy(var, "password-");
strcpy(&var[9], server);
if ((cp = value(var)) != NULL)
cp = savestr(cp);
ac_free(var);
return cp;
}
int
pop3_setfile(const char *server, int newmail, int isedit)
{
struct sock so;
sighandler_type saveint;
sighandler_type savepipe;
char *user;
const char *cp, *sp = server, *pass, *uhp;
int use_ssl = 0;
(void)&sp;
(void)&use_ssl;
(void)&user;
if (newmail)
return 1;
if (strncmp(sp, "pop3://", 7) == 0) {
sp = &sp[7];
use_ssl = 0;
#ifdef USE_SSL
} else if (strncmp(sp, "pop3s://", 8) == 0) {
sp = &sp[8];
use_ssl = 1;
#endif /* USE_SSL */
}
uhp = sp;
pass = pop3_have_password(uhp);
if ((cp = last_at_before_slash(sp)) != NULL) {
user = salloc(cp - sp + 1);
memcpy(user, sp, cp - sp);
user[cp - sp] = '\0';
sp = &cp[1];
user = strdec(user);
} else
user = NULL;
verbose = value("verbose") != NULL;
if (sopen(sp, &so, use_ssl, uhp, use_ssl ? "pop3s" : "pop3",
verbose) != OKAY) {
return -1;
}
quit();
edit = isedit;
if (mb.mb_sock.s_fd >= 0)
sclose(&mb.mb_sock);
if (mb.mb_itf) {
fclose(mb.mb_itf);
mb.mb_itf = NULL;
}
if (mb.mb_otf) {
fclose(mb.mb_otf);
mb.mb_otf = NULL;
}
initbox(server);
mb.mb_type = MB_VOID;
pop3lock = 1;
mb.mb_sock = so;
saveint = safe_signal(SIGINT, SIG_IGN);
savepipe = safe_signal(SIGPIPE, SIG_IGN);
if (sigsetjmp(pop3jmp, 1)) {
sclose(&mb.mb_sock);
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
pop3lock = 0;
return 1;
}
if (saveint != SIG_IGN)
safe_signal(SIGINT, pop3catch);
if (savepipe != SIG_IGN)
safe_signal(SIGPIPE, pop3catch);
if ((cp = value("pop3-keepalive")) != NULL) {
if ((pop3keepalive = strtol(cp, NULL, 10)) > 0) {
savealrm = safe_signal(SIGALRM, pop3alarm);
alarm(pop3keepalive);
}
}
mb.mb_sock.s_desc = "POP3";
mb.mb_sock.s_onclose = pop3_timer_off;
if (pop3_user(&mb, user, pass, uhp, sp) != OKAY ||
pop3_stat(&mb, &mailsize, &msgCount) != OKAY) {
sclose(&mb.mb_sock);
pop3_timer_off();
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
pop3lock = 0;
return 1;
}
mb.mb_type = MB_POP3;
mb.mb_perm = Rflag ? 0 : MB_DELE;
pop3_setptr(&mb);
setmsize(msgCount);
sawcom = 0;
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
pop3lock = 0;
if (!edit && msgCount == 0) {
if (mb.mb_type == MB_POP3 && value("emptystart") == NULL)
fprintf(stderr, catgets(catd, CATSET, 258,
"No mail at %s\n"), server);
return 1;
}
return 0;
}
static enum okay
pop3_get(struct mailbox *mp, struct message *m, enum needspec need)
{
sighandler_type saveint = SIG_IGN;
sighandler_type savepipe = SIG_IGN;
off_t offset;
char o[LINESIZE], *line = NULL, *lp;
size_t linesize = 0, linelen, size;
int number = m - message + 1;
int emptyline = 0, lines;
(void)&saveint;
(void)&savepipe;
(void)&number;
(void)&emptyline;
(void)&need;
verbose = value("verbose") != NULL;
if (mp->mb_sock.s_fd < 0) {
fprintf(stderr, catgets(catd, CATSET, 219,
"POP3 connection already closed.\n"));
return STOP;
}
if (pop3lock++ == 0) {
if ((saveint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
safe_signal(SIGINT, maincatch);
savepipe = safe_signal(SIGPIPE, SIG_IGN);
if (sigsetjmp(pop3jmp, 1)) {
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
pop3lock--;
return STOP;
}
if (savepipe != SIG_IGN)
safe_signal(SIGPIPE, pop3catch);
}
fseek(mp->mb_otf, 0L, SEEK_END);
offset = ftell(mp->mb_otf);
retry: switch (need) {
case NEED_HEADER:
snprintf(o, sizeof o, "TOP %u 0\r\n", number);
break;
case NEED_BODY:
snprintf(o, sizeof o, "RETR %u\r\n", number);
break;
case NEED_UNSPEC:
abort();
}
POP3_OUT(o, MB_COMD|MB_MULT)
if (pop3_answer(mp) == STOP) {
if (need == NEED_HEADER) {
/*
* The TOP POP3 command is optional, so retry
* with the entire message.
*/
need = NEED_BODY;
goto retry;
}
if (interrupts)
onintr(0);
return STOP;
}
size = 0;
lines = 0;
while (sgetline(&line, &linesize, &linelen, &mp->mb_sock) > 0) {
if (line[0] == '.' && line[1] == '\r' && line[2] == '\n' &&
line[3] == '\0') {
mp->mb_active &= ~MB_MULT;
break;
}
if (line[0] == '.') {
lp = &line[1];
linelen--;
} else
lp = line;
/*
* Need to mask 'From ' lines. This cannot be done properly
* since some servers pass them as 'From ' and others as
* '>From '. Although one could identify the first kind of
* server in principle, it is not possible to identify the
* second as '>From ' may also come from a server of the
* first type as actual data. So do what is absolutely
* necessary only - mask 'From '.
*
* If the line is the first line of the message header, it
* is likely a real 'From ' line. In this case, it is just
* ignored since it violates all standards.
*/
if (lp[0] == 'F' && lp[1] == 'r' && lp[2] == 'o' &&
lp[3] == 'm' && lp[4] == ' ') {
if (lines != 0) {
fputc('>', mp->mb_otf);
size++;
} else
continue;
}
lines++;
if (lp[linelen-1] == '\n' && (linelen == 1 ||
lp[linelen-2] == '\r')) {
emptyline = linelen <= 2;
if (linelen > 2)
fwrite(lp, 1, linelen - 2, mp->mb_otf);
fputc('\n', mp->mb_otf);
size += linelen - 1;
} else {
emptyline = 0;
fwrite(lp, 1, linelen, mp->mb_otf);
size += linelen;
}
}
if (!emptyline) {
/*
* This is very ugly; but some POP3 daemons don't end a
* message with \r\n\r\n, and we need \n\n for mbox format.
*/
fputc('\n', mp->mb_otf);
lines++;
size++;
}
m->m_size = size;
m->m_lines = lines;
m->m_block = mailx_blockof(offset);
m->m_offset = mailx_offsetof(offset);
fflush(mp->mb_otf);
switch (need) {
case NEED_HEADER:
m->m_have |= HAVE_HEADER;
break;
case NEED_BODY:
m->m_have |= HAVE_HEADER|HAVE_BODY;
m->m_xlines = m->m_lines;
m->m_xsize = m->m_size;
break;
case NEED_UNSPEC:
break;
}
if (line)
free(line);
if (saveint != SIG_IGN)
safe_signal(SIGINT, saveint);
if (savepipe != SIG_IGN)
safe_signal(SIGPIPE, savepipe);
pop3lock--;
if (interrupts)
onintr(0);
return OKAY;
}
enum okay
pop3_header(struct message *m)
{
return pop3_get(&mb, m, NEED_HEADER);
}
enum okay
pop3_body(struct message *m)
{
return pop3_get(&mb, m, NEED_BODY);
}
static enum okay
pop3_exit(struct mailbox *mp)
{
POP3_OUT("QUIT\r\n", MB_COMD)
POP3_ANSWER()
return OKAY;
}
static enum okay
pop3_delete(struct mailbox *mp, int n)
{
char o[LINESIZE];
snprintf(o, sizeof o, "DELE %u\r\n", n);
POP3_OUT(o, MB_COMD)
POP3_ANSWER()
return OKAY;
}
static enum okay
pop3_update(struct mailbox *mp)
{
FILE *readstat = NULL;
struct message *m;
int dodel, c, gotcha, held;
if (Tflag != NULL) {
if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
Tflag = NULL;
}
if (!edit) {
holdbits();
for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
if (m->m_flag & MBOX)
c++;
}
if (c > 0)
makembox();
}
for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
char *id;
if ((id = hfield("message-id", m)) != NULL ||
(id = hfield("article-id", m)) != NULL)
fprintf(readstat, "%s\n", id);
}
if (edit) {
dodel = m->m_flag & MDELETED;
} else {
dodel = !((m->m_flag&MPRESERVE) ||
(m->m_flag&MTOUCH) == 0);
}
if (dodel) {
pop3_delete(mp, m - message + 1);
gotcha++;
} else
held++;
}
if (readstat != NULL)
Fclose(readstat);
if (gotcha && edit) {
printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
printf(value("bsdcompat") || value("bsdmsgs") ?
catgets(catd, CATSET, 170, "complete\n") :
catgets(catd, CATSET, 212, "updated.\n"));
} else if (held && !edit) {
if (held == 1)
printf(catgets(catd, CATSET, 155,
"Held 1 message in %s\n"), mailname);
else if (held > 1)
printf(catgets(catd, CATSET, 156,
"Held %d messages in %s\n"), held, mailname);
}
fflush(stdout);
return OKAY;
}
void
pop3_quit(void)
{
sighandler_type saveint;
sighandler_type savepipe;
verbose = value("verbose") != NULL;
if (mb.mb_sock.s_fd < 0) {
fprintf(stderr, catgets(catd, CATSET, 219,
"POP3 connection already closed.\n"));
return;
}
pop3lock = 1;
saveint = safe_signal(SIGINT, SIG_IGN);
savepipe = safe_signal(SIGPIPE, SIG_IGN);
if (sigsetjmp(pop3jmp, 1)) {
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, saveint);
pop3lock = 0;
return;
}
if (saveint != SIG_IGN)
safe_signal(SIGINT, pop3catch);
if (savepipe != SIG_IGN)
safe_signal(SIGPIPE, pop3catch);
pop3_update(&mb);
pop3_exit(&mb);
sclose(&mb.mb_sock);
safe_signal(SIGINT, saveint);
safe_signal(SIGPIPE, savepipe);
pop3lock = 0;
}
#else /* !HAVE_SOCKETS */
static void
nopop3(void)
{
fprintf(stderr, catgets(catd, CATSET, 216,
"No POP3 support compiled in.\n"));
}
int
pop3_setfile(const char *server, int newmail, int isedit)
{
nopop3();
return -1;
}
enum okay
pop3_header(struct message *mp)
{
nopop3();
return STOP;
}
enum okay
pop3_body(struct message *mp)
{
nopop3();
return STOP;
}
void
pop3_quit(void)
{
nopop3();
}
enum okay
pop3_noop(void)
{
nopop3();
return STOP;
}
#endif /* HAVE_SOCKETS */
syntax highlighted by Code2HTML, v. 0.9.1