diff options
-rw-r--r-- | driver.c | 716 |
1 files changed, 372 insertions, 344 deletions
@@ -410,21 +410,27 @@ char *realname; /* real name of host */ char *bufp, *headers, *fromhdr,*tohdr,*cchdr,*bcchdr,*received_for,*envto; char *fromptr, *toptr, *ctthdr, *line; int n, oldlen, ch; - int inheaders, sizeticker, delete_ok; + int sizeticker, delete_ok; FILE *sinkfp; RETSIGTYPE (*sigchld)(); #ifdef HAVE_GETHOSTBYNAME char rbuf[HOSTLEN + USERNAMELEN + 4]; #endif /* HAVE_GETHOSTBYNAME */ + char *cp; + struct idlist *idp, *xmit_names; + int good_addresses, bad_addresses; +#ifdef HAVE_RES_SEARCH + int no_local_matches = FALSE; +#endif /* HAVE_RES_SEARCH */ - /* read the message content from the server */ - inheaders = delete_ok = TRUE; - headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = ctthdr = NULL; sizeticker = 0; + delete_ok = TRUE; + + /* read message headers */ + headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = ctthdr = NULL; oldlen = 0; line = (char *)NULL; - while (delimited || len > 0) - { + do { if (line) free(line); line = xmalloc(sizeof(buf)); @@ -438,7 +444,7 @@ char *realname; /* real name of host */ strcat(line, buf); } while /* we may need to grab RFC822 continuations */ - (inheaders && (ch = SockPeek(sockfp)) == ' ' || ch == '\t'); + ((ch = SockPeek(sockfp)) == ' ' || ch == '\t'); /* write the message size dots */ if ((n = strlen(line)) > 0) @@ -451,415 +457,436 @@ char *realname; /* real name of host */ sizeticker -= SIZETICKER; } } + len -= n; bufp = line; - len -= n; - if (bufp[0] == '\r' && bufp[1] == '\n') - inheaders = FALSE; - if (delimited && *bufp == '.') { + if (delimited && *bufp == '.') + { if (bufp[1] == '\r' && bufp[2] == '\n') break; /* end of message */ } - if (inheaders) - { - if (!ctl->no_rewrite) - reply_hack(bufp, realname); + if (!ctl->no_rewrite) + reply_hack(bufp, realname); - if (!headers) - { - oldlen = strlen(bufp); - headers = xmalloc(oldlen + 1); - (void) strcpy(headers, bufp); - bufp = headers; - } - else - { - int newlen; - - newlen = oldlen + strlen(bufp); - headers = realloc(headers, newlen + 1); - if (headers == NULL) - return(PS_IOERR); - strcpy(headers + oldlen, bufp); - bufp = headers + oldlen; - oldlen = newlen; - } + if (!headers) + { + oldlen = strlen(bufp); + headers = xmalloc(oldlen + 1); + (void) strcpy(headers, bufp); + bufp = headers; + } + else + { + int newlen; - if (!fromhdr && !strncasecmp("From:", bufp, 5)) - fromhdr = bufp; - else if (!fromhdr && !strncasecmp("Resent-From:", bufp, 12)) - fromhdr = bufp; - else if (!fromhdr && !strncasecmp("Apparently-From:", bufp, 16)) - fromhdr = bufp; + newlen = oldlen + strlen(bufp); + headers = realloc(headers, newlen + 1); + if (headers == NULL) + return(PS_IOERR); + strcpy(headers + oldlen, bufp); + bufp = headers + oldlen; + oldlen = newlen; + } - else if (!strncasecmp("To:", bufp, 3)) - tohdr = bufp; + if (!fromhdr && !strncasecmp("From:", bufp, 5)) + fromhdr = bufp; + else if (!fromhdr && !strncasecmp("Resent-From:", bufp, 12)) + fromhdr = bufp; + else if (!fromhdr && !strncasecmp("Apparently-From:", bufp, 16)) + fromhdr = bufp; - else if (!envto && !strncasecmp("Apparently-To:", bufp, 14)) - envto = bufp; - else if (!envto && !strncasecmp(ctl->server.envelope, bufp, 14)) - envto = bufp; + else if (!strncasecmp("To:", bufp, 3)) + tohdr = bufp; - else if (!strncasecmp("Cc:", bufp, 3)) - cchdr = bufp; + else if (!envto && !strncasecmp("Apparently-To:", bufp, 14)) + envto = bufp; + else if (!envto && !strncasecmp(ctl->server.envelope, bufp, 14)) + envto = bufp; - else if (!strncasecmp("Bcc:", bufp, 4)) - bcchdr = bufp; + else if (!strncasecmp("Cc:", bufp, 3)) + cchdr = bufp; - else if (!strncasecmp("Content-Transfer-Encoding:", bufp, 26)) - ctthdr = bufp; + else if (!strncasecmp("Bcc:", bufp, 4)) + bcchdr = bufp; + + else if (!strncasecmp("Content-Transfer-Encoding:", bufp, 26)) + ctthdr = bufp; #ifdef HAVE_RES_SEARCH - else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9)) - received_for = parse_received(ctl, bufp); + else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9)) + received_for = parse_received(ctl, bufp); #endif /* HAVE_RES_SEARCH */ + } while + (len > 0 && (bufp[0] != '\r' || bufp[1] != '\n')); - if (len > 0) - continue; - } /* if (inheaders) */ + if (line) + free(line); - if (headers && (!inheaders || len == 0)) /* at end of headers now */ - { - char *cp; - struct idlist *idp, *xmit_names; - int good_addresses, bad_addresses; -#ifdef HAVE_RES_SEARCH - int no_local_matches = FALSE; -#endif /* HAVE_RES_SEARCH */ + /* + * We can now process message headers before reading the text. + * In fact we have to, as this will tell us where to forward to. + */ - /* cons up a list of local recipients */ - xmit_names = (struct idlist *)NULL; - bad_addresses = good_addresses = 0; + /* cons up a list of local recipients */ + xmit_names = (struct idlist *)NULL; + bad_addresses = good_addresses = 0; #ifdef HAVE_RES_SEARCH - /* is this a multidrop box? */ - if (MULTIDROP(ctl)) - { - if (envto) /* We have the actual envelope addressee */ - find_server_names(envto, ctl, &xmit_names); - else if (received_for) - /* - * We have the Received for addressee. - * It has to be a mailserver address, or we - * wouldn't have got here. - */ - map_name(received_for, ctl, &xmit_names); - else - { - /* - * We haven't extracted the envelope address. - * So check all the header addresses. - */ - find_server_names(tohdr, ctl, &xmit_names); - find_server_names(cchdr, ctl, &xmit_names); - find_server_names(bcchdr, ctl, &xmit_names); - } - if (!xmit_names) - { - no_local_matches = TRUE; - save_str(&xmit_names, -1, user); - if (outlevel == O_VERBOSE) - error(0, 0, - "no local matches, forwarding to %s", - user); - } - } - else /* it's a single-drop box, use first localname */ + /* is this a multidrop box? */ + if (MULTIDROP(ctl)) + { + if (envto) /* We have the actual envelope addressee */ + find_server_names(envto, ctl, &xmit_names); + else if (received_for) + /* + * We have the Received for addressee. + * It has to be a mailserver address, or we + * wouldn't have got here. + */ + map_name(received_for, ctl, &xmit_names); + else + { + /* + * We haven't extracted the envelope address. + * So check all the header addresses. + */ + find_server_names(tohdr, ctl, &xmit_names); + find_server_names(cchdr, ctl, &xmit_names); + find_server_names(bcchdr, ctl, &xmit_names); + } + if (!xmit_names) + { + no_local_matches = TRUE; + save_str(&xmit_names, -1, user); + if (outlevel == O_VERBOSE) + error(0, 0, + "no local matches, forwarding to %s", + user); + } + } + else /* it's a single-drop box, use first localname */ #endif /* HAVE_RES_SEARCH */ - save_str(&xmit_names, -1, ctl->localnames->id); + save_str(&xmit_names, -1, ctl->localnames->id); - /* time to address the message */ - if (ctl->mda) /* we have a declared MDA */ - { - int length = 0; - char *names, *cmd; + /* time to address the message */ + if (ctl->mda) /* we have a declared MDA */ + { + int length = 0; + char *names, *cmd; - /* - * We go through this in order to be able to handle very - * long lists of users and (re)implement %s. - */ - for (idp = xmit_names; idp; idp = idp->next) - length += (strlen(idp->id) + 1); - names = (char *)alloca(length); - names[0] = '\0'; - for (idp = xmit_names; idp; idp = idp->next) - { - strcat(names, idp->id); - strcat(names, " "); - } - cmd = (char *)alloca(strlen(ctl->mda) + length); - sprintf(cmd, ctl->mda, names); - if (outlevel == O_VERBOSE) - error(0, 0, "about to deliver with: %s", cmd); + /* + * We go through this in order to be able to handle very + * long lists of users and (re)implement %s. + */ + for (idp = xmit_names; idp; idp = idp->next) + length += (strlen(idp->id) + 1); + names = (char *)alloca(length); + names[0] = '\0'; + for (idp = xmit_names; idp; idp = idp->next) + { + strcat(names, idp->id); + strcat(names, " "); + } + cmd = (char *)alloca(strlen(ctl->mda) + length); + sprintf(cmd, ctl->mda, names); + if (outlevel == O_VERBOSE) + error(0, 0, "about to deliver with: %s", cmd); #ifdef HAVE_SETEUID - /* - * Arrange to run with user's permissions if we're root. - * This will initialize the ownership of any files the - * MDA creates properly. (The seteuid call is available - * under all BSDs and Linux) - */ - seteuid(ctl->uid); + /* + * Arrange to run with user's permissions if we're root. + * This will initialize the ownership of any files the + * MDA creates properly. (The seteuid call is available + * under all BSDs and Linux) + */ + seteuid(ctl->uid); #endif /* HAVE_SETEUID */ - sinkfp = popen(cmd, "w"); + sinkfp = popen(cmd, "w"); #ifdef HAVE_SETEUID - /* this will fail quietly if we didn't start as root */ - seteuid(0); + /* this will fail quietly if we didn't start as root */ + seteuid(0); #endif /* HAVE_SETEUID */ - if (!sinkfp) - { - error(0, 0, "MDA open failed"); - return(PS_IOERR); - } + if (!sinkfp) + { + error(0, 0, "MDA open failed"); + return(PS_IOERR); + } - sigchld = signal(SIGCHLD, SIG_DFL); - } - else - { - char *ap, *ctt, options[MSGBUFSIZE]; - int smtperr; + sigchld = signal(SIGCHLD, SIG_DFL); + } + else + { + char *ap, *ctt, options[MSGBUFSIZE]; + int smtperr; - /* build a connection to the SMTP listener */ - if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL)) - { - free_str_list(&xmit_names); - error(0, 0, "SMTP connect failed"); - return(PS_SMTP); - } + /* build a connection to the SMTP listener */ + if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL)) + { + free_str_list(&xmit_names); + error(0, 0, "SMTP connect failed"); + return(PS_SMTP); + } + + /* + * Compute ESMTP options. It's a kluge to use nxtaddr() + * here because the contents of the Content-Transfer-Encoding + * headers isn't semantically an address. But it has the + * desired tokenizing effect. + */ + options[0] = '\0'; + if ((ctl->server.esmtp_options & ESMTP_8BITMIME) + && ctthdr + && (ctt = nxtaddr(ctthdr))) + if (!strcasecmp(ctt,"7BIT")) + sprintf(options, " BODY=7BIT", ctt); + else if (!strcasecmp(ctt,"8BIT")) + sprintf(options, " BODY=8BITMIME", ctt); + if ((ctl->server.esmtp_options & ESMTP_SIZE) && !delimited) + sprintf(options + strlen(options), " SIZE=%d", len); + + /* + * Try to get the SMTP listener to take the header + * From address as MAIL FROM (this makes the logging + * nicer). If it won't, fall back on the calling-user + * ID. This won't affect replies, which use the header + * From address anyway. + * + * RFC 1123 requires that the domain name part of the + * MAIL FROM address be "canonicalized", that is a + * FQDN or MX but not a CNAME. We'll assume the From + * header is already in this form here (it certainly + * is if rewrite is on). RFC 1123 is silent on whether + * a nonexistent hostname part is considered canonical. + * + * This is a potential problem if the MTAs further + * upstream didn't pass canonicalized From lines, *and* + * the local SMTP listener insists on them. + */ + if (!fromhdr || !(ap = nxtaddr(fromhdr))) + ap = user; + if (SMTP_from(sinkfp, ap, options) != SM_OK) + { + int smtperr = atoi(smtp_response); + if (smtperr >= 400) + error(0, 0, "SMTP error: %s", smtp_response); + + /* + * There'a one problem with this flow of control; + * there's no way to avoid reading the whole message + * off the server, even if the MAIL FROM response + * tells us that it's just to be discarded. We could + * fix this under IMAP by reading headers first, then + * trying to issue the MAIL FROM, and *then* reading + * the body...but POP3 can't do this. + */ + + switch (smtperr) + { + case 571: /* unsolicited email refused */ /* - * Compute ESMTP options. It's a kluge to use nxtaddr() - * here because the contents of the Content-Transfer-Encoding - * headers isn't semantically an address. But it has the - * desired tokenizing effect. + * SMTP listener explicitly refuses to deliver + * mail coming from this address, probably due + * to an anti-spam domain exclusion. Respect + * this. Don't try to ship the message, and + * don't prevent it from being deleted. */ - options[0] = '\0'; - if ((ctl->server.esmtp_options & ESMTP_8BITMIME) - && ctthdr - && (ctt = nxtaddr(ctthdr))) - if (!strcasecmp(ctt,"7BIT")) - sprintf(options, " BODY=7BIT", ctt); - else if (!strcasecmp(ctt,"8BIT")) - sprintf(options, " BODY=8BITMIME", ctt); - if ((ctl->server.esmtp_options & ESMTP_SIZE) && !delimited) - sprintf(options + strlen(options), " SIZE=%d", len); + sinkfp = (FILE *)NULL; + goto skiptext; + case 452: /* insufficient system storage */ /* - * Try to get the SMTP listener to take the header - * From address as MAIL FROM (this makes the logging - * nicer). If it won't, fall back on the calling-user - * ID. This won't affect replies, which use the header - * From address anyway. - * - * RFC 1123 requires that the domain name part of the - * MAIL FROM address be "canonicalized", that is a - * FQDN or MX but not a CNAME. We'll assume the From - * header is already in this form here (it certainly - * is if rewrite is on). RFC 1123 is silent on whether - * a nonexistent hostname part is considered canonical. - * - * This is a potential problem if the MTAs further - * upstream didn't pass canonicalized From lines, *and* - * the local SMTP listener insists on them. + * Temporary out-of-queue-space condition on the + * ESMTP server. Don't try to ship the message, + * and suppress deletion so it can be retried on + * a future retrieval cycle. */ - if (!fromhdr || !(ap = nxtaddr(fromhdr))) - ap = user; - if (SMTP_from(sinkfp, ap, options) != SM_OK) - { - int smtperr = atoi(smtp_response); - - if (smtperr >= 400) - error(0, 0, "SMTP error: %s", smtp_response); - - /* - * There'a one problem with this flow of control; - * there's no way to avoid reading the whole message - * off the server, even if the MAIL FROM response - * tells us that it's just to be discarded. We could - * fix this under IMAP by reading headers first, then - * trying to issue the MAIL FROM, and *then* reading - * the body...but POP3 can't do this. - */ - - switch (smtperr) - { - case 571: /* unsolicited email refused */ - /* - * SMTP listener explicitly refuses to deliver - * mail coming from this address, probably due - * to an anti-spam domain exclusion. Respect - * this. Don't try to ship the message, and - * don't prevent it from being deleted. - */ - sinkfp = (FILE *)NULL; - goto skiptext; - - case 452: /* insufficient system storage */ - /* - * Temporary out-of-queue-space condition on the - * ESMTP server. Don't try to ship the message, - * and suppress deletion so it can be retried on - * a future retrieval cycle. - */ - delete_ok = FALSE; - sinkfp = (FILE *)NULL; - SMTP_rset(sockfp); /* required by RFC1870 */ - goto skiptext; - - case 552: /* message exceeds fixed maximum message size */ - /* - * Permanent no-go condition on the - * ESMTP server. Don't try to ship the message, - * and allow it to be deleted. - */ - sinkfp = (FILE *)NULL; - SMTP_rset(sockfp); /* required by RFC1870 */ - goto skiptext; - - default: /* retry with invoking user's address */ - if (SMTP_from(sinkfp, user, options) != SM_OK) - { - error(0,0,"SMTP error: %s", smtp_response); - return(PS_SMTP); /* should never happen */ - } - } - } + delete_ok = FALSE; + sinkfp = (FILE *)NULL; + SMTP_rset(sockfp); /* required by RFC1870 */ + goto skiptext; + case 552: /* message exceeds fixed maximum message size */ /* - * Now list the recipient addressees - * - * RFC 1123 requires that the domain name part of the - * RCPT TO address be "canonicalized", that is a FQDN - * or MX but not a CNAME. RFC1123 doesn't say whether - * the FQDN part can be null (as it frequently will be - * here), but it's hard to see how this could cause a - * problem. + * Permanent no-go condition on the + * ESMTP server. Don't try to ship the message, + * and allow it to be deleted. */ - for (idp = xmit_names; idp; idp = idp->next) - if (SMTP_rcpt(sinkfp, idp->id) == SM_OK) - good_addresses++; - else - { - bad_addresses++; - idp->val.num = 0; - error(0, 0, - "SMTP listener doesn't like recipient address `%s'", idp->id); - } - if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK) + sinkfp = (FILE *)NULL; + SMTP_rset(sockfp); /* required by RFC1870 */ + goto skiptext; + + default: /* retry with invoking user's address */ + if (SMTP_from(sinkfp, user, options) != SM_OK) { - error(0, 0, - "can't even send to calling user!"); - return(PS_SMTP); + error(0,0,"SMTP error: %s", smtp_response); + return(PS_SMTP); /* should never happen */ } - - /* tell it we're ready to send data */ - SMTP_data(sinkfp); - - skiptext:; } + } - /* write all the headers */ - if (ctl->mda) - n = fwrite(headers, 1, oldlen, sinkfp); - else if (sinkfp) - n = SockWrite(headers, 1, oldlen, sinkfp); - - if (n < 0) + /* + * Now list the recipient addressees + * + * RFC 1123 requires that the domain name part of the + * RCPT TO address be "canonicalized", that is a FQDN + * or MX but not a CNAME. RFC1123 doesn't say whether + * the FQDN part can be null (as it frequently will be + * here), but it's hard to see how this could cause a + * problem. + */ + for (idp = xmit_names; idp; idp = idp->next) + if (SMTP_rcpt(sinkfp, idp->id) == SM_OK) + good_addresses++; + else { - free(headers); - headers = NULL; - error(0, errno, "writing RFC822 headers"); - if (ctl->mda) - { - pclose(sinkfp); - signal(SIGCHLD, sigchld); - } - return(PS_IOERR); + bad_addresses++; + idp->val.num = 0; + error(0, 0, + "SMTP listener doesn't like recipient address `%s'", idp->id); } - else if (outlevel == O_VERBOSE) - fputs("#", stderr); - free(headers); - headers = NULL; + if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK) + { + error(0, 0, + "can't even send to calling user!"); + return(PS_SMTP); + } + + /* tell it we're ready to send data */ + SMTP_data(sinkfp); + + skiptext:; + } + + /* write all the headers */ + if (ctl->mda) + n = fwrite(headers, 1, oldlen, sinkfp); + else if (sinkfp) + n = SockWrite(headers, 1, oldlen, sinkfp); + + if (n < 0) + { + free(headers); + headers = NULL; + error(0, errno, "writing RFC822 headers"); + if (ctl->mda) + { + pclose(sinkfp); + signal(SIGCHLD, sigchld); + } + return(PS_IOERR); + } + else if (outlevel == O_VERBOSE) + fputs("#", stderr); + free(headers); + headers = NULL; - /* write error notifications */ + /* write error notifications */ #ifdef HAVE_RES_SEARCH - if (no_local_matches || bad_addresses) + if (no_local_matches || bad_addresses) #else - if (bad_addresses) + if (bad_addresses) #endif /* HAVE_RES_SEARCH */ - { - int errlen = 0; - char errhd[USERNAMELEN + POPBUFSIZE], *errmsg; + { + int errlen = 0; + char errhd[USERNAMELEN + POPBUFSIZE], *errmsg; - errmsg = errhd; - (void) strcpy(errhd, "X-Fetchmail-Warning: "); + errmsg = errhd; + (void) strcpy(errhd, "X-Fetchmail-Warning: "); #ifdef HAVE_RES_SEARCH - if (no_local_matches) - { - strcat(errhd, "no recipient addresses matched declared local names"); - if (bad_addresses) - strcat(errhd, "; "); - } + if (no_local_matches) + { + strcat(errhd, "no recipient addresses matched declared local names"); + if (bad_addresses) + strcat(errhd, "; "); + } #endif /* HAVE_RES_SEARCH */ - if (bad_addresses) + if (bad_addresses) + { + strcat(errhd, "SMTP listener rejected local recipient addresses: "); + errlen = strlen(errhd); + for (idp = xmit_names; idp; idp = idp->next) + if (!idp->val.num) + errlen += strlen(idp->id) + 2; + + errmsg = alloca(errlen+3); + (void) strcpy(errmsg, errhd); + for (idp = xmit_names; idp; idp = idp->next) + if (!idp->val.num) { - strcat(errhd, "SMTP listener rejected local recipient addresses: "); - errlen = strlen(errhd); - for (idp = xmit_names; idp; idp = idp->next) - if (!idp->val.num) - errlen += strlen(idp->id) + 2; - - errmsg = alloca(errlen+3); - (void) strcpy(errmsg, errhd); - for (idp = xmit_names; idp; idp = idp->next) - if (!idp->val.num) - { - strcat(errmsg, idp->id); - if (idp->next) - strcat(errmsg, ", "); - } + strcat(errmsg, idp->id); + if (idp->next) + strcat(errmsg, ", "); } + } - strcat(errmsg, "\n"); + strcat(errmsg, "\n"); - /* ship out the error line */ - if (ctl->mda) - fwrite(errmsg, 1, strlen(errmsg), sinkfp); - else if (sinkfp) - SockWrite(errmsg, 1, strlen(errmsg), sinkfp); - } + /* ship out the error line */ + if (ctl->mda) + fwrite(errmsg, 1, strlen(errmsg), sinkfp); + else if (sinkfp) + SockWrite(errmsg, 1, strlen(errmsg), sinkfp); + } - free_str_list(&xmit_names); - } /* else if (headers) */ + free_str_list(&xmit_names); + +#ifdef STUFFBLANK + /* output a crlf if zero length message body */ + if (!len) + { + if (ctl->mda[0]) + fputs("\r\n", sinkfp); + else if (sinkfp) + SockWrite("\r\n", 1, 2, sinkfp); + } +#endif - /* output a crlf if zero length message body */ - if (!len && inheaders) + /* + * Body processing starts here + */ + + /* pass through the text lines */ + while (delimited || len > 0) + { + if (!SockGets(buf, sizeof(buf)-1, sockfp)) + return(PS_SOCKET); + vtalarm(ctl->server.timeout); + + /* write the message size dots */ + if ((n = strlen(buf)) > 0) { - if (ctl->mda[0]) - fputs("\r\n", sinkfp); - else if (sinkfp) - SockWrite("\r\n", 1, 2, sinkfp); - continue; + sizeticker += n; + while (sizeticker >= SIZETICKER) + { + if (outlevel > O_SILENT) + error_build("."); + sizeticker -= SIZETICKER; + } } + len -= n; - /* following code is executed on non-header lines only */ + /* check for end of message */ + if (delimited && *buf == '.') + if (buf[1] == '\r' && buf[2] == '\n') + break; /* SMTP byte-stuffing */ - if (*bufp == '.') + if (*buf == '.') if (ctl->mda) fputs(".", sinkfp); else if (sinkfp) - SockWrite(bufp, 1, 1, sinkfp); + SockWrite(buf, 1, 1, sinkfp); /* ship out the text line */ if (ctl->mda) - n = fwrite(bufp, 1, strlen(bufp), sinkfp); + n = fwrite(buf, 1, strlen(buf), sinkfp); else if (sinkfp) - n = SockWrite(bufp, 1, strlen(bufp), sinkfp); + n = SockWrite(buf, 1, strlen(buf), sinkfp); if (n < 0) { @@ -875,8 +902,9 @@ char *realname; /* real name of host */ fputc('*', stderr); } - if (line) - free(line); + /* + * End-of-message processing starts here + */ if (outlevel == O_VERBOSE) fputc('\n', stderr); |