/*
 * Enviador de cartas personalizadas
 *
 * nitr0us [nitrousenador.at.gmail.dot.com]
 * 09/08/06
 *
 * Compilacion y ejecucion:
 * [COMPILACION]
 * $gcc mailer.c -o mailer
 * [EJECUCION_EJEMPLO]
 * $./mailer emails.txt carta.html fuente@company.com "Este es el asunto" mail.mysmtpserver.com
 *
 * NOTAS:
 * + El archivo de emails debe tener en cada linea una direccion de correo o una direccion de correo y nombre separado por coma.
 *   Ejemplo: foobar@chiapas.gob.mx,Lic. Alma Madero
 * + En la carta en HTML, debe estar la cadena definida en la constante NOMBRE justo donde quiere sustituirse por el nombre de la persona.
 *   Ejemplo:  "<html><body>Hola #NOMBRE#, le invito a...</body></html>
 *   Resultado: Hola Lic. Alma Madero, le invito a... 
 *
 * !!! EL AUTOR NO SE HACE RESPONSABLE DEL USO QUE PUEDA TENER ESTE CÓDIGO POR TERCEROS !!!
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/times.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<errno.h>

#define NOMBRE	"#NOMBRE#"
#ifndef IPPORT_SMTP
#define IPPORT_SMTP	25
#endif

int EnviaCarta(int, const char *, const char *, const char *, const char *, const char *);
void header()
{
	printf("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");
	printf("*-*-               Enviador de cartas personalizadas                -*-*\n");
	printf("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");
	printf("*-*-*-*-*-*-*-* nitr0us [nitrousenador.at.gmail.dot.com]  *-*-*-*-*-*-*-*\n");
	printf("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n\n");
}

int main(int argc, char **argv)
{
	char			*cartaptr, *nombre, *tmpptr, linea[256], lineatmp[256], emaildestino[128];
	int			fdcarta, sfd, connombre = 1;
	unsigned int		total = 0, cont = 0;
	FILE			*fpmails;
	struct sockaddr_in	mailserver;
	struct hostent		*hostinfo;
	struct stat		fileinfo;

	if(argc != 6){
		header();
		fprintf(stderr, "Forma de Uso:\n%s <archivo_emails> <archivo_carta> <mail_fuente> <asunto> <servidor_email>\n", argv[0]);
		exit(EXIT_SUCCESS);
	}

	if((fpmails = fopen(argv[1], "r")) == NULL){
		perror(argv[1]);
		exit(EXIT_FAILURE);
	}

	if((fdcarta = open(argv[2], O_RDONLY)) == -1){
		perror(argv[2]);
		fclose(fpmails);
		exit(EXIT_FAILURE);
	}

	if((hostinfo = gethostbyname(argv[5])) == NULL){
		herror("gethostbyname()");
		close(fdcarta);
		fclose(fpmails);
		exit(EXIT_FAILURE);
	}

	if(fstat(fdcarta, &fileinfo) == -1){
		perror("fstat()");
		close(fdcarta);
		fclose(fpmails);
		exit(EXIT_FAILURE);
	}

	if((cartaptr = (char *) mmap(0, fileinfo.st_size, PROT_READ, MAP_SHARED, fdcarta, 0)) == (void *)-1){
		perror("mmap()");
		close(fdcarta);
		fclose(fpmails);
		exit(EXIT_FAILURE);
	}

	char	carta_enviar[fileinfo.st_size + 128], cartatmp[fileinfo.st_size + 128];

	memset(&mailserver, 0x00, sizeof(mailserver));
	mailserver.sin_family	= AF_INET;
	mailserver.sin_port	= htons(IPPORT_SMTP);
	mailserver.sin_addr	= *((struct in_addr *)hostinfo->h_addr);

	header();
	printf("Enviando email a:\n");
	while(fgets(linea, 256, fpmails)){
		if(isspace((int) linea[0]))
			continue;

		memset(lineatmp, 0x00, 256);
		memset(emaildestino, 0x00, 128);
		memset(cartatmp, 0x00, fileinfo.st_size + 128);
		memset(carta_enviar, 0x00, fileinfo.st_size + 128);

		/* Parseo de mails y nombres */
		nombre = strchr(linea, (int) ',');
		if(nombre == NULL)
			connombre = 0;
		else{
			connombre = 1;
			nombre++; // Avanzar la coma (,)
			tmpptr = nombre;
			while(*tmpptr != '\n' && *tmpptr != '\r') tmpptr++;
			*tmpptr = '\0';
		}

		if(connombre)
			strncpy(emaildestino, strtok(linea, ","), 127);
		else{
			strncpy(emaildestino, linea, 127);
			tmpptr = emaildestino;
			while(*tmpptr != '\n' && *tmpptr != '\r') tmpptr++;
			*tmpptr = '\0';
		}
		/* Parseo de mails y nombres */

		/* Construccion de la carta */
		if(strstr(cartaptr, NOMBRE) == NULL){
			fprintf(stderr, "No se encontro: %s en el archivo %s... Saliendo\n", NOMBRE, argv[2]);
			close(fdcarta);
			fclose(fpmails);
			exit(EXIT_FAILURE);
		}
		strncpy(cartatmp, cartaptr, fileinfo.st_size);
		tmpptr = strtok(cartatmp, NOMBRE);
		strcpy(carta_enviar, tmpptr);
		if(connombre)
			strcat(carta_enviar, nombre);
		tmpptr = strstr(cartaptr, NOMBRE) + strlen(NOMBRE);
		strcat(carta_enviar, tmpptr);
		/* Construccion de la carta */

		printf("%40s\t", emaildestino);

		if((sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
			perror("socket()");
			fclose(fpmails);
			munmap(cartaptr, fileinfo.st_size);
			exit(EXIT_FAILURE);
		}

		if(connect(sfd, (struct sockaddr *)&mailserver, sizeof(mailserver)) == -1){	
			perror("connect()");
			fclose(fpmails);
			munmap(cartaptr, fileinfo.st_size);
			exit(EXIT_FAILURE);
		}

		if(EnviaCarta(sfd, emaildestino, argv[3], argv[4], carta_enviar, nombre)){
			printf("[OK]\n");
			cont++;
		}
		else
			printf("[FALLO]\n");

		total++;
		close(sfd);
		sleep(1);
	}

	printf("\nProceso terminado. Enviados %d emails correctamente de %d.\n\n", cont, total);

	close(fdcarta);
	fclose(fpmails);
	munmap(cartaptr, fileinfo.st_size);
	return EXIT_SUCCESS;
}

int EnviaCarta(int sfd, const char *para, const char *de, const char *asunto, const char *carta, const char *nombre)
{
	char		sendbuff[strlen(carta) + 512], recvbuff[256];
	fd_set		canread;
	struct timeval	tv;

	tv.tv_sec  = 1; // Segundo para esperar el banner
	tv.tv_usec = 0;

	memset(sendbuff, 0x00, strlen(carta) + 512);
	memset(recvbuff, 0x00, 256);

	do{
		FD_ZERO(&canread);
		FD_SET(sfd, &canread);
		recv(sfd, recvbuff, 255, 0); //Banner
		select(sfd + 1, &canread, NULL, NULL, &tv);
	} while(FD_ISSET(sfd, &canread));

	send(sfd, "helo foo\r\n", strlen("helo foo\r\n"), 0);
	recv(sfd, recvbuff, 255, 0);

	sprintf(sendbuff, "mail from: %s\r\n", de);
	send(sfd, sendbuff, strlen(sendbuff), 0);
	recv(sfd, recvbuff, 255, 0);
	recvbuff[3] = '\0';
	if(strcmp(recvbuff, "250") != 0){
		fprintf(stderr, "mail from fallo - Codigo SMTP recibido: %s\n", recvbuff);
		return 0;
	}

	sprintf(sendbuff, "rcpt to: %s\r\n", para);
	send(sfd, sendbuff, strlen(sendbuff), 0);
	recv(sfd, recvbuff, 255, 0);
	recvbuff[3] = '\0';
	if(strcmp(recvbuff, "250") != 0){
		fprintf(stderr, "rcpt to fallo - Codigo SMTP recibido: %s\n", recvbuff);
		return 0;
	}

	send(sfd, "data\r\n", strlen("data\r\n"), 0);
	recv(sfd, recvbuff, 255, 0);
	recvbuff[3] = '\0';
	if(strcmp(recvbuff, "354") != 0){
		fprintf(stderr, "data fallo - Codigo SMTP recibido: %s\n", recvbuff);
		return 0;
	}

	sprintf(sendbuff, "To: %s <%s>\r\nFrom: <%s>\r\nSubject: %s\r\nContent-Type: text/html; charset=ISO-8859-1\r\nMIME-Version: 1.0\r\n\r\n", nombre, para, de, asunto);
	send(sfd, sendbuff, strlen(sendbuff), 0);

	sprintf(sendbuff, "%s\r\n.\r\n", carta);
	send(sfd, sendbuff, strlen(sendbuff), 0);
	recv(sfd, recvbuff, 255, 0);
	recvbuff[3] = '\0';
	if(strcmp(recvbuff, "250") != 0){
		fprintf(stderr, "Cuerpo del mensaje fallo - Codigo SMTP recibido: %s\n", recvbuff);
		return 0;
	}

	send(sfd, "quit\r\n", strlen("quit\r\n"), 0);

	return 1;
}
