#include "config.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#if defined(STDC_HEADERS)
#include <stdlib.h>
#endif
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#if defined(HAVE_STDARG_H)
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#ifdef HAVE_NET_SOCKET_H
#include <net/socket.h>
#endif
#include "md5.h"
#include "i18n.h"
#include "socket.h"
#include "fetchmail.h"
#ifndef strstr
extern char *strstr();
#endif
int mytimeout;
int suppress_tags;
char shroud[PASSWORDLEN*2+3];
struct msgblk msgblk;
char tag[TAGLEN];
static int tagnum;
#define GENSYM (sprintf(tag, "A%04d", ++tagnum % TAGMOD), tag)
static int accept_count, reject_count;
static struct method *protocol;
static void map_name(const char *name, struct query *ctl, struct idlist **xmit_names)
{
const char *lname;
int off = 0;
lname = idpair_find(&ctl->localnames, name+off);
if (!lname && ctl->wildcard)
lname = name+off;
if (lname != (char *)NULL)
{
if (outlevel >= O_DEBUG)
report(stdout, GT_("mapped %s to local %s\n"), name, lname);
save_str(xmit_names, lname, XMIT_ACCEPT);
accept_count++;
}
}
static void find_server_names(const char *hdr,
struct query *ctl,
struct idlist **xmit_names)
{
if (hdr == (char *)NULL)
return;
else
{
char *cp;
for (cp = nxtaddr(hdr);
cp != NULL;
cp = nxtaddr(NULL))
{
char *atsign;
if (!*cp)
continue;
if (ctl->server.qvirtual)
{
int sl = strlen(ctl->server.qvirtual);
if (!strncasecmp(cp, ctl->server.qvirtual, sl))
cp += sl;
}
if ((atsign = strchr(cp, '@'))) {
struct idlist *idp;
for (idp = ctl->server.localdomains; idp; idp = idp->next) {
char *rhs;
rhs = atsign + (strlen(atsign) - strlen(idp->id));
if (rhs > atsign &&
(rhs[-1] == '.' || rhs[-1] == '@') &&
strcasecmp(rhs, idp->id) == 0)
{
if (outlevel >= O_DEBUG)
report(stdout, GT_("passed through %s matching %s\n"),
cp, idp->id);
save_str(xmit_names, cp, XMIT_ACCEPT);
accept_count++;
goto nomap;
}
}
if (!idp)
{
if (!is_host_alias(atsign+1, ctl))
{
save_str(xmit_names, cp, XMIT_REJECT);
reject_count++;
continue;
}
}
atsign[0] = '\0';
map_name(cp, ctl, xmit_names);
nomap:;
}
}
}
}
#define VALID_ADDRESS(a) !strchr(a, '@')
static char *parse_received(struct query *ctl, char *bufp)
{
char *base, *ok = (char *)NULL;
static char rbuf[HOSTLEN + USERNAMELEN + 4];
#define RBUF_WRITE(value) if (tp < rbuf+sizeof(rbuf)-1) *tp++=value
if (outlevel >= O_DEBUG)
report(stdout, GT_("analyzing Received line:\n%s"), bufp);
for (base = bufp; ; base = ok + 2)
{
if (!(ok = strstr(base, "by")))
break;
else if (!isspace(ok[-1]) || !isspace(ok[2]))
continue;
else
{
char *sp, *tp;
for (sp = ok + 2; isspace(*sp); sp++)
continue;
tp = rbuf;
for (; !isspace(*sp); sp++)
RBUF_WRITE(*sp);
*tp = '\0';
if (VALID_ADDRESS(rbuf))
break;
else
ok = sp - 1;
}
}
if (ok)
{
if (is_host_alias(rbuf, ctl))
{
if (outlevel >= O_DEBUG)
report(stdout,
GT_("line accepted, %s is an alias of the mailserver\n"), rbuf);
}
else
{
if (outlevel >= O_DEBUG)
report(stdout,
GT_("line rejected, %s is not an alias of the mailserver\n"),
rbuf);
return(NULL);
}
for (base = ok + 4 + strlen(rbuf); ; base = ok + 2)
{
if (!(ok = strstr(base, "for")))
break;
else if (!isspace(ok[-1]) || !isspace(ok[3]))
continue;
else
{
char *sp, *tp;
for (sp = ok + 3; isspace(*sp); sp++)
continue;
tp = rbuf;
for (; !isspace(*sp); sp++)
RBUF_WRITE(*sp);
*tp = '\0';
if (strchr(rbuf, '@'))
break;
else
ok = sp - 1;
}
}
if (ok)
{
flag want_gt = FALSE;
char *sp, *tp;
for (sp = ok + 4; isspace(*sp); sp++)
continue;
tp = rbuf;
RBUF_WRITE(':');
RBUF_WRITE(' ');
if (*sp == '<')
{
want_gt = TRUE;
sp++;
}
while (*sp == '@')
while (*sp && *sp++ != ':')
continue;
while (*sp
&& (want_gt ? (*sp != '>') : !isspace(*sp))
&& *sp != ';')
if (!isspace(*sp))
{
RBUF_WRITE(*sp);
sp++;
}
else
{
ok = (char *)NULL;
break;
}
RBUF_WRITE('\n');
*tp = '\0';
if (strlen(rbuf) <= 3)
ok = NULL;
} else
ok = (char *)NULL;
}
if (!ok)
{
if (outlevel >= O_DEBUG)
report(stdout, GT_("no Received address found\n"));
return(NULL);
}
else
{
if (outlevel >= O_DEBUG) {
char *lf = rbuf + strlen(rbuf)-1;
*lf = '\0';
if (outlevel >= O_DEBUG)
report(stdout, GT_("found Received address `%s'\n"), rbuf+2);
*lf = '\n';
}
return(rbuf);
}
}
static int sizeticker;
#define EMPTYLINE(s) (((s)[0] == '\r' && (s)[1] == '\n' && (s)[2] == '\0') \
|| ((s)[0] == '\n' && (s)[1] == '\0'))
static int end_of_header (const char *s)
{
while (s[0] == '\r')
s++;
return (s[0] == '\n' && s[1] == '\0');
}
int readheaders(int sock,
long fetchlen,
long reallen,
struct query *ctl,
int num,
flag *suppress_readbody)
{
struct addrblk
{
int offset;
struct addrblk *next;
};
struct addrblk *to_addrchain = NULL;
struct addrblk **to_chainptr = &to_addrchain;
struct addrblk *resent_to_addrchain = NULL;
struct addrblk **resent_to_chainptr = &resent_to_addrchain;
char buf[MSGBUFSIZE+1];
int from_offs, reply_to_offs, resent_from_offs;
int app_from_offs, sender_offs, resent_sender_offs;
int env_offs;
char *received_for, *rcv, *cp;
static char *delivered_to = NULL;
int n, linelen, oldlen, ch, remaining, skipcount;
struct idlist *idp;
flag no_local_matches = FALSE;
flag has_nuls;
int olderrs, good_addresses, bad_addresses;
int retain_mail = 0, refuse_mail = 0;
flag already_has_return_path = FALSE;
sizeticker = 0;
has_nuls = FALSE;
msgblk.return_path[0] = '\0';
olderrs = ctl->errcount;
msgblk.reallen = reallen;
if (msgblk.headers)
free(msgblk.headers);
free_str_list(&msgblk.recipients);
if (delivered_to)
free(delivered_to);
memset(ctl->digest, '\0', sizeof(ctl->digest));
msgblk.headers = received_for = delivered_to = NULL;
from_offs = reply_to_offs = resent_from_offs = app_from_offs =
sender_offs = resent_sender_offs = env_offs = -1;
oldlen = 0;
msgblk.msglen = 0;
skipcount = 0;
ctl->mimemsg = 0;
for (remaining = fetchlen; remaining > 0 || protocol->delimited; )
{
char *line, *rline;
int overlong = FALSE;
line = xmalloc(sizeof(buf));
linelen = 0;
line[0] = '\0';
do {
do {
char *sp, *tp;
set_timeout(mytimeout);
if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1) {
set_timeout(0);
free(line);
free(msgblk.headers);
msgblk.headers = NULL;
return(PS_SOCKET);
}
set_timeout(0);
for (sp = tp = buf; sp < buf + n; sp++)
if (*sp)
*tp++ = *sp;
*tp = '\0';
n = tp - buf;
} while
(n == 0);
remaining -= n;
linelen += n;
msgblk.msglen += n;
if (n && buf[n-1] != '\n')
{
overlong = TRUE;
rline = (char *) realloc(line, linelen + 1);
if (rline == NULL)
{
free (line);
return(PS_IOERR);
}
line = rline;
memcpy(line + linelen - n, buf, n);
line[linelen] = '\0';
ch = ' ';
continue;
}
if (ctl->forcecr && buf[n-1]=='\n' && (n==1 || buf[n-2]!='\r'))
{
char * tcp;
rline = (char *) realloc(line, linelen + 2);
if (rline == NULL)
{
free (line);
return(PS_IOERR);
}
line = rline;
memcpy(line + linelen - n, buf, n - 1);
tcp = line + linelen - 1;
*tcp++ = '\r';
*tcp++ = '\n';
*tcp++ = '\0';
n++;
linelen++;
}
else
{
rline = (char *) realloc(line, linelen + 1);
if (rline == NULL)
{
free (line);
return(PS_IOERR);
}
line = rline;
memcpy(line + linelen - n, buf, n + 1);
}
if (end_of_header(line))
{
if (linelen != strlen (line))
has_nuls = TRUE;
free(line);
goto process_headers;
}
if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
{
if (outlevel > O_SILENT)
report(stdout,
GT_("message delimiter found while scanning headers\n"));
if (suppress_readbody)
*suppress_readbody = TRUE;
if (linelen != strlen (line))
has_nuls = TRUE;
free(line);
goto process_headers;
}
if (!refuse_mail && !isspace(line[0]) && !strchr(line, ':'))
{
if (linelen != strlen (line))
has_nuls = TRUE;
if (outlevel > O_SILENT)
report(stdout,
GT_("incorrect header line found while scanning headers\n"));
if (outlevel >= O_VERBOSE)
report (stdout, GT_("line: %s"), line);
refuse_mail = 1;
}
set_timeout(mytimeout);
ch = SockPeek(sock);
set_timeout(0);
} while
(ch == ' ' || ch == '\t');
if ((outlevel > O_SILENT && outlevel < O_VERBOSE) && linelen > 0)
{
sizeticker += linelen;
while (sizeticker >= SIZETICKER)
{
if (outlevel > O_SILENT && run.showdots)
{
fputc('.', stdout);
fflush(stdout);
}
sizeticker -= SIZETICKER;
}
}
if ( ctl->mimedecode )
{
char *tcp;
UnMimeHeader(line);
for(tcp = line + linelen - 1; tcp > line && (*tcp != 0 || tcp[-1] != '\n'); tcp--);
if(tcp > line) linelen = tcp - line;
}
if (retain_mail || refuse_mail)
{
free(line);
continue;
}
if (linelen != strlen (line))
has_nuls = TRUE;
#ifdef POP2_ENABLE
#if INET6_ENABLE
if (strncmp(protocol->service, "pop2", 4))
#else
if (protocol->port != 109)
#endif
#endif
if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
free(line);
retain_mail = 1;
continue;
}
if (!strncasecmp(line, ">From ", 6) || !strncasecmp(line, "From ", 5))
{
free(line);
continue;
}
if (ctl->dropdelivered && !strncasecmp(line, "Delivered-To:", 13))
{
if (delivered_to)
free(line);
else
delivered_to = line;
continue;
}
{
char *cp;
if (!strncasecmp(line, "Status:", 7))
cp = line + 7;
else if (!strncasecmp(line, "X-Mozilla-Status:", 17))
cp = line + 17;
else
cp = NULL;
if (cp) {
while (*cp && isspace(*cp)) cp++;
if (!*cp || ctl->dropstatus)
{
free(line);
continue;
}
}
}
if (ctl->rewrite)
line = reply_hack(line, ctl->server.truename, &linelen);
if ((already_has_return_path==FALSE) && !strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line)))
{
already_has_return_path = TRUE;
if (cp[0]=='\0')
cp="<>";
strncpy(msgblk.return_path, cp, sizeof(msgblk.return_path));
msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0';
if (!ctl->mda) {
free(line);
continue;
}
}
if (!msgblk.headers)
{
oldlen = linelen;
msgblk.headers = xmalloc(oldlen + 1);
(void) memcpy(msgblk.headers, line, linelen);
msgblk.headers[oldlen] = '\0';
free(line);
line = msgblk.headers;
}
else
{
char *newhdrs;
int newlen;
newlen = oldlen + linelen;
newhdrs = (char *) realloc(msgblk.headers, newlen + 1);
if (newhdrs == NULL) {
free(line);
return(PS_IOERR);
}
msgblk.headers = newhdrs;
memcpy(msgblk.headers + oldlen, line, linelen);
msgblk.headers[newlen] = '\0';
free(line);
line = msgblk.headers + oldlen;
oldlen = newlen;
}
if (!strncasecmp("From:", line, 5))
from_offs = (line - msgblk.headers);
else if (!strncasecmp("Reply-To:", line, 9))
reply_to_offs = (line - msgblk.headers);
else if (!strncasecmp("Resent-From:", line, 12))
resent_from_offs = (line - msgblk.headers);
else if (!strncasecmp("Apparently-From:", line, 16))
app_from_offs = (line - msgblk.headers);
else if (!strncasecmp("Sender:", line, 7) && (strchr(line, '@') || strchr(line, '!')))
sender_offs = (line - msgblk.headers);
else if (!strncasecmp("Resent-Sender:", line, 14) && (strchr(line, '@') || strchr(line, '!')))
resent_sender_offs = (line - msgblk.headers);
#ifdef __UNUSED__
else if (!strncasecmp("Message-Id:", line, 11))
{
if (ctl->server.uidl)
{
char id[IDLEN+1];
line[IDLEN+12] = 0;
sscanf(line+12, "%s", id);
if (!str_find( &ctl->newsaved, num))
{
struct idlist *new = save_str(&ctl->newsaved,id,UID_SEEN);
new->val.status.num = num;
}
}
}
#endif
if (MULTIDROP(ctl))
{
if (!strncasecmp("To:", line, 3)
|| !strncasecmp("Cc:", line, 3)
|| !strncasecmp("Bcc:", line, 4)
|| !strncasecmp("Apparently-To:", line, 14))
{
*to_chainptr = xmalloc(sizeof(struct addrblk));
(*to_chainptr)->offset = (line - msgblk.headers);
to_chainptr = &(*to_chainptr)->next;
*to_chainptr = NULL;
}
else if (!strncasecmp("Resent-To:", line, 10)
|| !strncasecmp("Resent-Cc:", line, 10)
|| !strncasecmp("Resent-Bcc:", line, 11))
{
*resent_to_chainptr = xmalloc(sizeof(struct addrblk));
(*resent_to_chainptr)->offset = (line - msgblk.headers);
resent_to_chainptr = &(*resent_to_chainptr)->next;
*resent_to_chainptr = NULL;
}
else if (ctl->server.envelope != STRING_DISABLED)
{
if (ctl->server.envelope
&& strcasecmp(ctl->server.envelope, "Received"))
{
if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
line,
strlen(ctl->server.envelope)))
{
if (skipcount++ < ctl->server.envskip)
continue;
env_offs = (line - msgblk.headers);
}
}
else if (!received_for && !strncasecmp("Received:", line, 9))
{
if (skipcount++ < ctl->server.envskip)
continue;
received_for = parse_received(ctl, line);
}
}
}
}
process_headers:
if (retain_mail)
{
free(msgblk.headers);
msgblk.headers = NULL;
return(PS_RETAINED);
}
if (refuse_mail)
return(PS_REFUSED);
if (MULTIDROP(ctl))
{
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, msgblk.headers, strlen(msgblk.headers));
MD5Final(ctl->digest, &context);
if (!received_for && env_offs == -1 && !delivered_to)
{
if (!memcmp(ctl->lastdigest, ctl->digest, DIGESTLEN))
return(PS_REFUSED);
}
memcpy(ctl->lastdigest, ctl->digest, DIGESTLEN);
}
if (msgblk.headers == (char *)NULL)
{
#ifdef HAVE_SNPRINTF
snprintf(buf, sizeof(buf),
#else
sprintf(buf,
#endif
"From: FETCHMAIL-DAEMON\r\nTo: %s@%s\r\nSubject: Headerless mail from %s's mailbox on %s\r\n",
user, fetchmailhost, ctl->remotename, ctl->server.truename);
msgblk.headers = xstrdup(buf);
}
ctl->mimemsg = MimeBodyType(msgblk.headers, ctl->mimedecode);
#ifdef SDPS_ENABLE
if (ctl->server.sdps && sdps_envfrom)
{
strcpy(msgblk.return_path, sdps_envfrom);
free(sdps_envfrom);
} else
#endif
if( !msgblk.return_path[0] ){
char *ap = NULL;
if (resent_sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_sender_offs)));
else if (sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + sender_offs)));
else if (resent_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_from_offs)));
else if (from_offs >= 0 && (ap = nxtaddr(msgblk.headers + from_offs)));
else if (reply_to_offs >= 0 && (ap = nxtaddr(msgblk.headers + reply_to_offs)));
else if (app_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + app_from_offs)));
if (ap && !strchr(ap, '\n')) {
strncpy(msgblk.return_path, ap, sizeof(msgblk.return_path));
msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0';
}
}
msgblk.recipients = (struct idlist *)NULL;
accept_count = reject_count = 0;
if (MULTIDROP(ctl))
{
#ifdef SDPS_ENABLE
if (ctl->server.sdps && sdps_envto)
{
find_server_names(sdps_envto, ctl, &msgblk.recipients);
free(sdps_envto);
} else
#endif
if (env_offs > -1)
find_server_names(msgblk.headers + env_offs, ctl, &msgblk.recipients);
else if (delivered_to && ctl->server.envelope != STRING_DISABLED &&
ctl->server.envelope && !strcasecmp(ctl->server.envelope, "Delivered-To"))
{
find_server_names(delivered_to, ctl, &msgblk.recipients);
free(delivered_to);
delivered_to = NULL;
}
else if (received_for)
find_server_names(received_for, ctl, &msgblk.recipients);
else
{
register struct addrblk *nextptr;
if (resent_to_addrchain) {
while (to_addrchain) {
nextptr = to_addrchain->next;
free(to_addrchain);
to_addrchain = nextptr;
}
to_addrchain = resent_to_addrchain;
resent_to_addrchain = NULL;
}
while (to_addrchain) {
find_server_names(msgblk.headers+to_addrchain->offset, ctl, &msgblk.recipients);
nextptr = to_addrchain->next;
free(to_addrchain);
to_addrchain = nextptr;
}
}
if (!accept_count)
{
no_local_matches = TRUE;
save_str(&msgblk.recipients, run.postmaster, XMIT_ACCEPT);
if (outlevel >= O_DEBUG)
report(stdout,
GT_("no local matches, forwarding to %s\n"),
run.postmaster);
}
}
else
save_str(&msgblk.recipients, ctl->localnames->id, XMIT_ACCEPT);
if (ctl->errcount > olderrs)
{
if (outlevel >= O_DEBUG)
report(stdout,
GT_("forwarding and deletion suppressed due to DNS errors\n"));
free(msgblk.headers);
msgblk.headers = NULL;
free_str_list(&msgblk.recipients);
return(PS_TRANSIENT);
}
else
{
if ((n = open_sink(ctl, &msgblk,
&good_addresses, &bad_addresses)) != PS_SUCCESS)
{
free(msgblk.headers);
msgblk.headers = NULL;
free_str_list(&msgblk.recipients);
return(n);
}
}
n = 0;
if ((rcv = strstr(msgblk.headers, "Received:")) == (char *)NULL)
rcv = msgblk.headers;
while (rcv > msgblk.headers && rcv[-1] != '\n')
rcv--;
if (rcv > msgblk.headers)
{
char c = *rcv;
*rcv = '\0';
n = stuffline(ctl, msgblk.headers);
*rcv = c;
}
if (!run.invisible && n != -1)
{
if (ctl->server.trueaddr) {
#ifdef HAVE_SNPRINTF
snprintf(buf, sizeof(buf),
#else
sprintf(buf,
#endif
"Received: from %s [%u.%u.%u.%u]\r\n",
ctl->server.truename,
(unsigned char)ctl->server.trueaddr[0],
(unsigned char)ctl->server.trueaddr[1],
(unsigned char)ctl->server.trueaddr[2],
(unsigned char)ctl->server.trueaddr[3]);
} else {
#ifdef HAVE_SNPRINTF
snprintf(buf, sizeof(buf),
#else
sprintf(buf,
#endif
"Received: from %s\r\n", ctl->server.truename);
}
n = stuffline(ctl, buf);
if (n != -1)
{
#ifdef HAVE_SNPRINTF
snprintf(buf, sizeof(buf),
#else
sprintf(buf,
#endif
"\tby %s with %s (fetchmail-%s",
fetchmailhost,
protocol->name,
VERSION);
if (ctl->tracepolls)
{
sprintf(buf + strlen(buf), " polling %s account %s",
ctl->server.pollname,
ctl->remotename);
}
#ifdef HAVE_SNPRINTF
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), ")\r\n");
#else
strcat(buf, ")\r\n");
#endif
n = stuffline(ctl, buf);
if (n != -1)
{
buf[0] = '\t';
if (good_addresses == 0)
{
#ifdef HAVE_SNPRINTF
snprintf(buf+1, sizeof(buf)-1,
#else
sprintf(buf+1,
#endif
"for %s (by default); ",
rcpt_address (ctl, run.postmaster, 0));
}
else if (good_addresses == 1)
{
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_ACCEPT)
break;
#ifdef HAVE_SNPRINTF
snprintf(buf+1, sizeof(buf)-1,
#else
sprintf(buf+1,
#endif
"for %s", rcpt_address (ctl, idp->id, 1));
sprintf(buf+strlen(buf), " (%s); ",
MULTIDROP(ctl) ? "multi-drop" : "single-drop");
}
else
buf[1] = '\0';
#ifdef HAVE_SNPRINTF
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s\r\n",
rfc822timestamp());
#else
strcat(buf, rfc822timestamp());
strcat(buf, "\r\n");
#endif
n = stuffline(ctl, buf);
}
}
}
if (n != -1)
n = stuffline(ctl, rcv);
if (n == -1)
{
report(stdout, GT_("writing RFC822 msgblk.headers\n"));
release_sink(ctl);
free(msgblk.headers);
msgblk.headers = NULL;
free_str_list(&msgblk.recipients);
return(PS_IOERR);
}
else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE && !isafile(2))
fputs("#", stdout);
if (no_local_matches || has_nuls || bad_addresses)
{
int errlen = 0;
char errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
errmsg = errhd;
(void) strcpy(errhd, "X-Fetchmail-Warning: ");
if (no_local_matches)
{
if (reject_count != 1)
strcat(errhd, GT_("no recipient addresses matched declared local names"));
else
{
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_REJECT)
break;
#ifdef HAVE_SNPRINTF
snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd),
#else
sprintf(errhd+strlen(errhd),
#endif
GT_("recipient address %s didn't match any local name"), idp->id);
}
}
if (has_nuls)
{
if (errhd[sizeof("X-Fetchmail-Warning: ")])
#ifdef HAVE_SNPRINTF
snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), "; ");
snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd),
#else
strcat(errhd, "; ");
strcat(errhd,
#endif
GT_("message has embedded NULs"));
}
if (bad_addresses)
{
if (errhd[sizeof("X-Fetchmail-Warning: ")])
#ifdef HAVE_SNPRINTF
snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), "; ");
snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd),
#else
strcat(errhd, "; ");
strcat(errhd,
#endif
GT_("SMTP listener rejected local recipient addresses: "));
errlen = strlen(errhd);
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_RCPTBAD)
errlen += strlen(idp->id) + 2;
xalloca(errmsg, char *, errlen+3);
(void) strcpy(errmsg, errhd);
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_RCPTBAD)
{
strcat(errmsg, idp->id);
if (idp->next)
strcat(errmsg, ", ");
}
}
strcat(errmsg, "\r\n");
stuffline(ctl, errmsg);
}
cp = buf;
*cp++ = '\r';
*cp++ = '\n';
*cp++ = '\0';
stuffline(ctl, buf);
return(PS_SUCCESS);
}
int readbody(int sock, struct query *ctl, flag forward, int len)
{
int linelen;
unsigned char buf[MSGBUFSIZE+4];
unsigned char *inbufp = buf;
flag issoftline = FALSE;
while (protocol->delimited || len > 0)
{
set_timeout(mytimeout);
if ((linelen = SockRead(sock, inbufp, sizeof(buf)-4-(inbufp-buf)))==-1)
{
set_timeout(0);
release_sink(ctl);
return(PS_SOCKET);
}
set_timeout(0);
if (linelen > 0)
{
sizeticker += linelen;
while (sizeticker >= SIZETICKER)
{
if (outlevel > O_SILENT && run.showdots)
{
fputc('.', stdout);
fflush(stdout);
}
sizeticker -= SIZETICKER;
}
}
len -= linelen;
if (protocol->delimited && *inbufp == '.')
{
if (EMPTYLINE(inbufp+1))
break;
else
msgblk.msglen--;
}
msgblk.msglen += linelen;
if (ctl->mimedecode && (ctl->mimemsg & MSG_NEEDS_DECODE)) {
issoftline = UnMimeBodyline(&inbufp, protocol->delimited, issoftline);
if (issoftline && (sizeof(buf)-1-(inbufp-buf) < 200))
{
*inbufp = '\n'; *(inbufp+1) = '\0';
issoftline = 0;
}
}
if (forward && (!issoftline))
{
int n;
inbufp = buf;
buf[MSGBUFSIZE+1] = '\r';
buf[MSGBUFSIZE+2] = '\n';
buf[MSGBUFSIZE+3] = '\0';
n = stuffline(ctl, buf);
if (n < 0)
{
report(stdout, GT_("writing message text\n"));
release_sink(ctl);
return(PS_IOERR);
}
else if (outlevel >= O_VERBOSE && !isafile(1))
{
fputc('*', stdout);
fflush(stdout);
}
}
}
return(PS_SUCCESS);
}
void init_transact(const struct method *proto)
{
tagnum = 0;
tag[0] = '\0';
protocol = (struct method *)proto;
}
static void enshroud(char *buf)
{
char *cp;
if (shroud[0] && (cp = strstr(buf, shroud)))
{
char *sp;
sp = cp + strlen(shroud);
*cp++ = '*';
while (*sp)
*cp++ = *sp++;
*cp = '\0';
}
}
#if defined(HAVE_STDARG_H)
void gen_send(int sock, const char *fmt, ... )
#else
void gen_send(sock, fmt, va_alist)
int sock;
const char *fmt;
va_dcl
#endif
{
char buf [MSGBUFSIZE+1];
va_list ap;
if (protocol->tagged && !suppress_tags)
(void) sprintf(buf, "%s ", GENSYM);
else
buf[0] = '\0';
#if defined(HAVE_STDARG_H)
va_start(ap, fmt);
#else
va_start(ap);
#endif
#ifdef HAVE_VSNPRINTF
vsnprintf(buf + strlen(buf), sizeof(buf)-strlen(buf), fmt, ap);
#else
vsprintf(buf + strlen(buf), fmt, ap);
#endif
va_end(ap);
#ifdef HAVE_SNPRINTF
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
#else
strcat(buf, "\r\n");
#endif
SockWrite(sock, buf, strlen(buf));
if (outlevel >= O_MONITOR)
{
enshroud(buf);
buf[strlen(buf)-2] = '\0';
report(stdout, "%s> %s\n", protocol->name, buf);
}
}
int gen_recv(sock, buf, size)
int sock;
char *buf;
int size;
{
int oldphase = phase;
phase = SERVER_WAIT;
set_timeout(mytimeout);
if (SockRead(sock, buf, size) == -1)
{
set_timeout(0);
phase = oldphase;
if(isidletimeout())
{
resetidletimeout();
return(PS_IDLETIMEOUT);
}
else
return(PS_SOCKET);
}
else
{
set_timeout(0);
if (buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = '\0';
if (buf[strlen(buf)-1] == '\r')
buf[strlen(buf)-1] = '\0';
if (outlevel >= O_MONITOR)
report(stdout, "%s< %s\n", protocol->name, buf);
phase = oldphase;
return(PS_SUCCESS);
}
}
#if defined(HAVE_STDARG_H)
int gen_transact(int sock, const char *fmt, ... )
#else
int gen_transact(int sock, fmt, va_alist)
int sock;
const char *fmt;
va_dcl
#endif
{
int ok;
char buf [MSGBUFSIZE+1];
va_list ap;
int oldphase = phase;
phase = SERVER_WAIT;
if (protocol->tagged && !suppress_tags)
(void) sprintf(buf, "%s ", GENSYM);
else
buf[0] = '\0';
#if defined(HAVE_STDARG_H)
va_start(ap, fmt) ;
#else
va_start(ap);
#endif
#ifdef HAVE_VSNPRINTF
vsnprintf(buf + strlen(buf), sizeof(buf)-strlen(buf), fmt, ap);
#else
vsprintf(buf + strlen(buf), fmt, ap);
#endif
va_end(ap);
#ifdef HAVE_SNPRINTF
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
#else
strcat(buf, "\r\n");
#endif
SockWrite(sock, buf, strlen(buf));
if (outlevel >= O_MONITOR)
{
enshroud(buf);
buf[strlen(buf)-2] = '\0';
report(stdout, "%s> %s\n", protocol->name, buf);
}
ok = (protocol->parse_response)(sock, buf);
phase = oldphase;
return(ok);
}