/*
	in.pop3gwd, a POP3 proxy
	Copyright (C) 1997 Andrea Borgia

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

/* connect_login.c: 	connect to remote host and log in */
/* ------------------------------------------------------ */

#include "pop3-gw.h"



/*
 * open a TCP connection;
 * return socket descriptor if OK, else BAD on error
 */

static int contact_host(char hostname[], int port) {
	struct sockaddr_in	tcp_srv_addr;	/* server's Internet socket addr */
	struct hostent		*host_ptr;	/* from gethostbyname() */
	int remote_fd;		/* on exit, holds descriptor no. or BAD if failed */


	if ((host_ptr = gethostbyname(hostname)) == NULL)
		remote_fd = BAD;
        else
		if ((remote_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
			remote_fd = BAD;
		else {
		        memset(&tcp_srv_addr, 0, sizeof(tcp_srv_addr));
        		tcp_srv_addr.sin_family = AF_INET;
			tcp_srv_addr.sin_port = htons(port);
		        memcpy(&tcp_srv_addr.sin_addr, host_ptr->h_addr_list[0], host_ptr->h_length);
			if (connect(remote_fd, (struct sockaddr *) &tcp_srv_addr, sizeof(tcp_srv_addr)) <0) {
				close(remote_fd);
				remote_fd = BAD;
			}
		}

	return(remote_fd);
}






/*
 * connect to the remote host and login; return code is TRUE if logged in successfully
 * (the remote server's reply has been passed to the proxy user), FALSE if not.
 * function takes care to forward the remote server response (positive or negative,
 * if any) to the proxy user
 */

int connect_login(int first_filedes, int *remote_filedes, int maxlen, int maxwait, 
	char username[], char hostname[], int dest_port, const char termin[], 
	const char pos_re[], const char neg_re[], const char user_c[], 
	int *conn, int *in, int *out) {
	
	char output[MAX_IO_LEN], input[MAX_IO_LEN];
	char to_client[MAX_IO_LEN];
	int result = TRUE;
	int count;
	char *next_tok;
		

	if ((*remote_filedes = contact_host(hostname, dest_port)) == BAD) {
		/* no connection, tell user about it */
		result = FALSE;
		snprintf(to_client, MAX_IO_LEN, "%s host unknown or connection failed", neg_re);
	}
	
	if (result == TRUE) {
		/* server is connected, wait for reply */
		if (readline(*remote_filedes, input, maxlen, maxwait, termin) == BAD) {
			/* server did not respond */
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s no response from server", neg_re);
		}
	}

	if (result == TRUE) {
		/* server greeted us, check if greeting is empty */
		if ((next_tok = strtok(input, " ")) == NULL) {
			/* empty response, POP3 violation */
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s empty response from server", neg_re);
		}
	}

	if (result == TRUE) {
		/* server greeted us, check if +OK */
		if (strncasecmp(next_tok, pos_re, maxlen) != 0) {
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s invalid response from remote server", neg_re);
		}
	}
	
	if (result == TRUE) {
		/* greeting is OK, we may login now */
		snprintf(output, MAX_IO_LEN, "%s %s%s", user_c, username, termin);
		if (writen(*remote_filedes, output, strlen(output), maxwait) != strlen(output)) {
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s could not send USER to remote server", neg_re);
		}
	}
	
	if (result == TRUE) {
		/* now let's see if the remote server replies to our USER cmd */
		if (readline(*remote_filedes, input, MAX_IO_LEN, maxwait, termin) == BAD) {
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s no response to USER", neg_re);
		}
	}
	
	if (result == TRUE) {
		/* server replied, check if reply is empty */
		/* must save response in case it is good */
		(void)strlcpy(to_client, input, MAX_IO_LEN);
		if ((next_tok = strtok(input, " ")) == NULL) {
			/* empty response, POP3 violation */
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s empty response from server", neg_re);
		}
	}

	if (result == TRUE) {
		/* is reply +OK ? */
		if (strncasecmp(next_tok, pos_re, maxlen) != 0) {
			/* server did not like out USER... */
			close(*remote_filedes);
			result = FALSE;
			snprintf(to_client, MAX_IO_LEN, "%s login failed", neg_re);
		}
	}

#ifdef DEBUG
	syslog(LOG_PRIO, "%s", to_client);
#endif

	(void)strlcat(to_client, termin, MAX_IO_LEN);
	if ((count = writen(first_filedes, to_client, strlen(to_client), maxwait)) == strlen(to_client))
		*out += count;
	else
		*conn = FALSE;

	return(result);
}


syntax highlighted by Code2HTML, v. 0.9.1