Ejemplo n.º 1
0
int SMTP_ok(int sock, char smtp_mode, int mintimeout)
/**< returns status of SMTP connection and saves the message in
 * smtp_response, without trailing [CR]LF, but with normalized CRLF
 * between multiple lines of multi-line replies */
{
    SIGHANDLERTYPE alrmsave;
    char reply[MSGBUFSIZE], *i;

    /* set an alarm for smtp ok */
    alrmsave = set_signal_handler(SIGALRM, null_signal_handler);
    set_timeout(mytimeout >= mintimeout ? mytimeout : mintimeout);

    smtp_response[0] = '\0';

    while ((SockRead(sock, reply, sizeof(reply)-1)) != -1)
    {
	size_t n;

	/* restore alarm */
	set_timeout(0);
	set_signal_handler(SIGALRM, alrmsave);

	n = strlen(reply);
	if (n > 0 && reply[n-1] == '\n')
	    reply[--n] = '\0';
	if (n > 0 && reply[n-1] == '\r')
	    reply[--n] = '\0';

	/* stomp over control characters */
	for (i = reply; *i; i++)
	    if (iscntrl((unsigned char)*i))
		*i = '?';

	if (outlevel >= O_MONITOR)
	    report(stdout, "%cMTP< %s\n", smtp_mode, reply);
	/* note that \0 is part of the strchr search string and the
	 * blank after the reply code is optional (RFC 5321 4.2.1) */
	if (n < 3 || !strchr(" -", reply[3]))
	{
	    if (outlevel >= O_MONITOR)
		report(stderr, GT_("smtp listener protocol error\n"));
	    return SM_UNRECOVERABLE;
	}

	last_smtp_ok = time((time_t *) NULL);

	strlcat(smtp_response, reply,  sizeof(smtp_response));

	if (strchr("123", reply[0])
		&& isdigit((unsigned char)reply[1])
		&& isdigit((unsigned char)reply[2])
		&& strchr(" ", reply[3])) /* matches space and \0 */ {
	    return SM_OK;
	} else if (reply[3] != '-')
	    return SM_ERROR;

	strlcat(smtp_response, "\r\n", sizeof(smtp_response));

	/* set an alarm for smtp ok */
	set_signal_handler(SIGALRM, null_signal_handler);
	set_timeout(mytimeout);
    }

    /* restore alarm */
    set_timeout(0);
    set_signal_handler(SIGALRM, alrmsave);

    if (outlevel >= O_MONITOR)
	report(stderr, GT_("smtp listener protocol error\n"));
    return SM_UNRECOVERABLE;
}
Ejemplo n.º 2
0
static int odmr_getrange(int sock, struct query *ctl, const char *id, 
			 int *countp, int *newp, int *bytes)
/* send ODMR and then run a reverse SMTP session */
{
    int ok, opts, smtp_sock;
    int doing_smtp_data = 0;   /* Are we in SMTP DATA state? */
    char buf [MSGBUFSIZE+1];
    struct idlist *qnp;		/* pointer to Q names */

    (void)id;
    if ((ok = SMTP_ehlo(sock, SMTP_MODE, fetchmailhost, 
			ctl->server.esmtp_name, ctl->server.esmtp_password,
			&opts)))
    {
	report(stderr, GT_("%s's SMTP listener does not support ESMTP\n"),
	      ctl->server.pollname);
	return(ok);
    }
    else if (!(opts & ESMTP_ATRN))
    {
	report(stderr, GT_("%s's SMTP listener does not support ATRN\n"),
	      ctl->server.pollname);
	return(PS_PROTOCOL);
    }

    /* make sure we don't enter the fetch loop */
    *bytes = *countp = *newp = -1;

    /* authenticate via CRAM-MD5 */
    ok = do_cram_md5(sock, "AUTH", ctl, "334 ");
    if (ok)
	return(ok);

    /*
     * By default, the hostlist has a single entry, the fetchmail host's
     * canonical DNS name.
     */
    buf[0] = '\0';
    for (qnp = ctl->domainlist; qnp; qnp = qnp->next)
	if (strlen(buf) + strlen(qnp->id) + 1 >= sizeof(buf))
	    break;
	else
	{
	    strcat(buf, qnp->id);
	    strcat(buf, ",");
	}
    buf[strlen(buf) - 1] = '\0';	/* nuke final comma */

    /* ship the domain list and get turnaround */
    gen_send(sock, "ATRN %s", buf);
    if ((ok = gen_recv(sock, buf, sizeof(buf))))
	return(ok);

    /* this switch includes all response codes described in RFC2645 */
    switch(atoi(buf))
    {
    case 250:	/* OK, turnaround is about to happe */
	if (outlevel > O_SILENT)
	    report(stdout, GT_("Turnaround now...\n"));
	break;

    case 450:	/* ATRN request refused */
	if (outlevel > O_SILENT)
	    report(stdout, GT_("ATRN request refused.\n"));
	return(PS_PROTOCOL);

    case 451:	/* Unable to process ATRN request now */
	report(stderr, GT_("Unable to process ATRN request now\n"));
	return(PS_EXCLUDE);

    case 453:	/* You have no mail */
	if (outlevel > O_SILENT)
	    report(stderr, GT_("You have no mail.\n"));
	return(PS_NOMAIL);

    case 502:	/* Command not implemented */
	report(stderr, GT_("Command not implemented\n"));
	return(PS_PROTOCOL);

    case 530:	/* Authentication required */
	report(stderr, GT_("Authentication required.\n"));
	return(PS_AUTHFAIL);

    default: {
	    char *t = sdump(buf, strlen(buf));
	    report(stderr, GT_("Unknown ODMR error \"%s\"\n"), t);
	    xfree(t);
	    return(PS_PROTOCOL);
	}
    }

    /*
     * OK, if we got here it's time to become a pipe between the ODMR
     * remote server (sending) and the SMTP listener we've designated
     * (receiving).  We're not going to try to be a protocol machine;
     * instead, we'll use select(2) to watch the read sides of both
     * sockets and just throw their data at each other.
     */
    if ((smtp_sock = smtp_setup(ctl)) == -1)
	return(PS_SOCKET);
    else
    {
	int	maxfd = (sock > smtp_sock) ? sock : smtp_sock;

	for (;;)
	{
	    fd_set	readfds;
	    struct timeval timeout;

	    FD_ZERO(&readfds);
	    FD_SET(sock, &readfds);
	    FD_SET(smtp_sock, &readfds);

	    timeout.tv_sec  = ctl->server.timeout;
	    timeout.tv_usec = 0;

	    if (select(maxfd+1, &readfds, NULL, NULL, &timeout) == -1)
		return(PS_PROTOCOL);		/* timeout */

	    if (FD_ISSET(sock, &readfds))
	    {
		int n = SockRead(sock, buf, sizeof(buf));
		if (n <= 0)
		    break;

		SockWrite(smtp_sock, buf, n);
		if (outlevel >= O_MONITOR && !doing_smtp_data)
		    report(stdout, "ODMR< %s", buf);
	    }
	    if (FD_ISSET(smtp_sock, &readfds))
	    {
		int n = SockRead(smtp_sock, buf, sizeof(buf));
		if (n <= 0)
		    break;

		SockWrite(sock, buf, n);
		if (outlevel >= O_MONITOR)
		    report(stdout, "ODMR> %s", buf);

               /* We are about to receive message data if the local MTA
                * sends 354 (after receiving DATA) */
               if (!doing_smtp_data && !strncmp(buf, "354", 3))
               {
                   doing_smtp_data = 1;
		   if (outlevel > O_SILENT)
		       report(stdout, GT_("receiving message data\n"));
               }
               else if (doing_smtp_data)
                   doing_smtp_data = 0;
	    }
	}
	SockClose(smtp_sock);
    }

    return(0);
}