#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 "i18n.h"
#include "socket.h"
#include "fetchmail.h"
#ifndef strstr
extern char *strstr();
#endif
int mytimeout;
int suppress_tags;
char shroud[PASSWORDLEN];
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, _("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 (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, _("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];
if (outlevel >= O_DEBUG)
report(stdout, _("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++)
*tp++ = *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,
_("line accepted, %s is an alias of the mailserver\n"), rbuf);
}
else
{
if (outlevel >= O_DEBUG)
report(stdout,
_("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++)
*tp++ = *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;
*tp++ = ':';
*tp++ = ' ';
if (*sp == '<')
{
want_gt = TRUE;
sp++;
}
while (*sp == '@')
while (*sp && *sp++ != ':')
continue;
while (*sp
&& (want_gt ? (*sp != '>') : !isspace(*sp))
&& *sp != ';')
if (!isspace(*sp))
*tp++ = *sp++;
else
{
ok = (char *)NULL;
break;
}
*tp++ = '\n';
*tp = '\0';
if (strlen(rbuf) <= 3)
ok = NULL;
} else
ok = (char *)NULL;
}
if (!ok)
{
if (outlevel >= O_DEBUG)
report(stdout, _("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, _("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')
int readheaders(int sock,
long fetchlen,
long reallen,
struct query *ctl,
int num)
{
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, *delivered_to;
int n, linelen, oldlen, ch, remaining, skipcount;
struct idlist *idp;
flag no_local_matches = FALSE;
flag headers_ok, has_nuls;
int olderrs, good_addresses, bad_addresses;
sizeticker = 0;
has_nuls = headers_ok = FALSE;
msgblk.return_path[0] = '\0';
olderrs = ctl->errcount;
msgblk.reallen = reallen;
if (msgblk.headers)
free(msgblk.headers);
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; remaining -= linelen)
{
char *line;
int overlong = FALSE;
line = xmalloc(sizeof(buf));
linelen = 0;
line[0] = '\0';
do {
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);
linelen += n;
msgblk.msglen += n;
if ( n && buf[n-1] != '\n' ) {
unsigned int llen = strlen(line);
overlong = TRUE;
line = realloc(line, llen + n + 1);
strcpy(line + llen, buf);
ch = ' ';
continue;
}
if (ctl->forcecr)
{
cp = buf + strlen(buf) - 1;
if (*cp == '\n' && (cp == buf || cp[-1] != '\r'))
{
*cp++ = '\r';
*cp++ = '\n';
*cp++ = '\0';
}
}
if ( ctl->mimedecode && overlong ) {
line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
strcat(line, buf);
UnMimeHeader(line);
}
else {
if ( ctl->mimedecode )
UnMimeHeader(buf);
line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
strcat(line, buf);
}
if (EMPTYLINE(line))
{
headers_ok = TRUE;
has_nuls = (linelen != strlen(line));
free(line);
goto process_headers;
}
if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
{
has_nuls = (linelen != strlen(line));
free(line);
goto process_headers;
}
if (!isspace(line[0]) && !strchr(line, ':'))
{
headers_ok = TRUE;
has_nuls = (linelen != strlen(line));
free(line);
goto process_headers;
}
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 ((!run.use_syslog && !isafile(1)) || run.showdots)
{
fputc('.', stdout);
fflush(stdout);
}
sizeticker -= SIZETICKER;
}
}
has_nuls = (linelen != strlen(line));
if (MULTIDROP(ctl) && !strncasecmp(line, "Message-ID:", 11))
{
if (ctl->lastid && !strcasecmp(ctl->lastid, line))
{
if (accept_count > 1)
return(PS_REFUSED);
}
else
{
if (ctl->lastid)
free(ctl->lastid);
ctl->lastid = strdup(line);
}
}
#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);
free(msgblk.headers);
msgblk.headers = NULL;
return(PS_RETAINED);
}
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);
if (!strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line)))
{
strcpy(msgblk.return_path, cp);
if (!ctl->mda) {
free(line);
continue;
}
}
if (!msgblk.headers)
{
oldlen = strlen(line);
msgblk.headers = xmalloc(oldlen + 1);
(void) strcpy(msgblk.headers, line);
free(line);
line = msgblk.headers;
}
else
{
char *newhdrs;
int newlen;
newlen = oldlen + strlen(line);
newhdrs = (char *) realloc(msgblk.headers, newlen + 1);
if (newhdrs == NULL) {
free(line);
return(PS_IOERR);
}
msgblk.headers = newhdrs;
strcpy(msgblk.headers + oldlen, line);
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, '@'))
sender_offs = (line - msgblk.headers);
else if (!strncasecmp("Resent-Sender:", line, 14) && 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
else if (!MULTIDROP(ctl))
continue;
else 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 (!headers_ok)
{
if (outlevel > O_SILENT)
report(stdout,
_("message delimiter found while scanning headers\n"));
}
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'))
strcpy(msgblk.return_path, ap);
}
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);
}
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,
_("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,
_("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@%s (by default); ",
user, ctl->destaddr);
}
else if (good_addresses == 1)
{
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_ACCEPT)
break;
if (strchr(idp->id, '@'))
#ifdef HAVE_SNPRINTF
snprintf(buf+1, sizeof(buf)-1,
#else
sprintf(buf+1,
#endif
"for %s", idp->id);
else
#ifdef HAVE_SNPRINTF
snprintf(buf+1, sizeof(buf)-1,
#else
sprintf(buf+1,
#endif
"for %s@%s", idp->id, ctl->destaddr);
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, _("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("#", stderr);
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, _("no recipient addresses matched declared local names"));
else
{
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_REJECT)
break;
sprintf(errhd+strlen(errhd), _("recipient address %s didn't match any local name"), idp->id);
}
}
if (has_nuls)
{
if (errhd[sizeof("X-Fetchmail-Warning: ")])
strcat(errhd, "; ");
strcat(errhd, _("message has embedded NULs"));
}
if (bad_addresses)
{
if (errhd[sizeof("X-Fetchmail-Warning: ")])
strcat(errhd, "; ");
strcat(errhd, _("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);
free_str_list(&msgblk.recipients);
return(headers_ok ? PS_SUCCESS : PS_TRUNCATED);
}
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.poll_interval == 0 || nodetach) && !isafile(1)) || run.showdots))
{
fputc('.', stdout);
fflush(stdout);
}
sizeticker -= SIZETICKER;
}
}
len -= linelen;
if (protocol->delimited && *inbufp == '.')
{
if (inbufp[1] == '\r' && inbufp[2] == '\n' && inbufp[3] == '\0')
break;
else if (inbufp[1] == '\n' && inbufp[2] == '\0')
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, _("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;
}
#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), 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)
{
char *cp;
if (shroud[0] && (cp = strstr(buf, shroud)))
{
char *sp;
sp = cp + strlen(shroud);
*cp++ = '*';
while (*sp)
*cp++ = *sp++;
*cp = '\0';
}
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;
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), 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)
{
char *cp;
if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
{
char *sp;
sp = cp + strlen(shroud);
*cp++ = '*';
while (*sp)
*cp++ = *sp++;
*cp = '\0';
}
buf[strlen(buf)-1] = '\0';
report(stdout, "%s> %s\n", protocol->name, buf);
}
ok = (protocol->parse_response)(sock, buf);
phase = oldphase;
return(ok);
}