/******************************************************************************
 *
 * Copyright (c) 1999	TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *	SMTPClient.cpp
 *
 *****************************************************************************/

// SOL++2000 Sample.

// 1999.09.24 Fixed a bug.

#include <sol\Exception.H>
#include <sol\StringTokenizer.h>
#include "SMTPClient.h"


Arg SMTPClient::replyList[] = {
	{"MailServer ready",		SERVER_READY},
	{"Closing a connection",	QUIT_OK},
	{"Command OK",				COMMAND_OK},
	{"User not found",			USER_NOT_FOUND},
	{"UnIdentified usr",		USER_NOT_FOUND},
	{"You can send a data",		DATA_OK},
	{"Server down",				SERVER_DOWN},
	{"MailBox busy",			MAILBOX_BUSY},
	{"Local error",				LOCAL_ERROR},
	{"Disk full",				DISK_FULL},
};


int SMTPClient::SERVER_READY		= 220;
int SMTPClient::QUIT_OK			= 221;
int SMTPClient::COMMAND_OK			= 250;
int SMTPClient::USER_NOT_FOUND		= 251;
int SMTPClient::USER_NOT_IDENTIFIED = 252;
int SMTPClient::DATA_OK			= 354;
int SMTPClient::SERVER_DOWN		= 421;
int SMTPClient::MAILBOX_BUSY		= 450;
int SMTPClient::LOCAL_ERROR		= 451;
int SMTPClient::DISK_FULL			= 452;



SMTPClient::SMTPClient(const char* server1, const char* user1, 
						 Mail& mail1)
						 
	:server(server1),
	 user(user1),
	 mail(mail1),
	 socket(null),
	 result(0)
{

}



SMTPClient::~SMTPClient() 
{
	delete socket;
}



int SMTPClient::connect() 
{
	InetAddress addr((const char*)server, IPPORT_SMTP);
	int rc = socket -> connect(addr);
	if (rc < 0) {
		throw Exception("Connection refused");
	}
	return rc;
}


int SMTPClient::hello(const char* message) 

{
	char text[256];
	sprintf(text, "HELO %s\r\n", message);
	int rc = socket -> sendAll(text, strlen(text), 0);
	if (rc <= 0) {
		throw Exception("start failed");
	}
	return rc;
}


int SMTPClient::sendFrom(const char* from) 
{
	char text[256];
	sprintf(text,"MAIL From: %s\r\n", from);

	int rc = socket -> sendAll(text, strlen(text), 0);
	if (rc <= 0) {
		throw Exception("sendFrom failed");
	}
	return rc;
}


int SMTPClient::sendTo(const char* to) 
{
	char text[256];
	sprintf(text,"RCPT To: %s\r\n", to);
	int rc = socket -> sendAll(text, strlen(text), 0);
	if (rc <= 0) {
		throw Exception("sendTo failed");
	}
	return rc;
}


int SMTPClient::beginData() 
{
	int rc = socket -> sendAll("DATA\r\n");
	if (rc <= 0) {
		throw Exception("beginData failed");
	}
	return rc;
}


int SMTPClient::sendData(char* data, size_t size)
{
	int rc = 0;
	if (data && size > 0) {
		rc = socket -> sendAll(data,  size, 0);
		if (rc <= 0) {
			throw  Exception("sendData failed");
		}
	}
	return rc;
}


int SMTPClient::endData() 
{
	int rc = socket -> sendAll("\r\n.\r\n");
	if (rc <= 0) {
		throw Exception("endData failed");
	}
	return rc;
}


int SMTPClient::quit() 
{
	int rc = socket -> sendAll("QUIT\r\n");
	if (rc <= 0) {
		throw Exception("quit failed");
	}
	return rc;
}


Boolean SMTPClient::recvReply(int command) 
{
	Boolean rc = False;

	StringBuffer buffer;
	int len = socket -> readLine(buffer);

	if(len < 3) {
		throw Exception("recvReply: recv failed");
	}

	//Printf("RECV:[%s]\r\n", buffer.getBuffer());

	// Check reply from SMTP server.
	StringTokenizer tokenizer(buffer);
	String cmd;
	tokenizer.getToken(cmd);
	int	reply = atoi((const char*)cmd);
	if(command == reply) {
		rc = True;
	} else {
		for (int i = 0; i<XtNumber(replyList); i++) {
			if ((int)replyList[i].value == reply) {
				throw Exception(replyList[i].name, atoi(cmd));
			}
		}
	}

	return rc;
}


int SMTPClient::sendContent(Mail& mail) 
{
	int rc = 0;
	StringBuffer& header = mail.getHeader();
	int len = 0;
	len = header.getSize();
	rc += sendData((char*)header.getBuffer(), len);
	
	char* delim ="\r\n";
	rc += sendData(delim, strlen(delim));
	
	StringBuffer& body = mail.getBody();
	len = body.getSize();
	rc += sendData((char*)body.getBuffer(), len);

	return len;
}


// Thread run method
void SMTPClient::run() 
{
	socket = new SocketStream(AF_INET, 0);
	result = 0;	
	try {
		//Printf("SMTPClient::run - connectiong \r\n");
		// Connect to the SMTP server.
		connect();
		// Receive a server-ready message.
		recvReply(SERVER_READY);

		// Send a sender name.
		hello((const char*)user);
		recvReply(COMMAND_OK);

        // Send a mail address of sender.		
		sendFrom((const char*)mail.getSender());
		recvReply(COMMAND_OK);

		// Send a list of mail-receivers.
		StringList& receiver = mail.getReceiver();
		ListEntry* ptr = receiver.getEntry();

		while (ptr) {
			String* string = (String*) ptr -> getObject();
			const char* str = (const char*)(*string);

			// Each receiver name must contain @ character.
			if (string->find("@") != null) {
				char* ptr = (char*)strstr(str, "<");

				// << 1999.09.24 Fixed a bug.
				if (ptr) {
					str = ++ptr;
					ptr = strstr(ptr, ">");
					if (ptr) {
						*ptr = Zero;
					}
				}
				// >>
				Printf(">[%s]\r\n", str);
				sendTo(str);
				recvReply(COMMAND_OK);
				result++;
			}
			ptr = ptr -> getNext();
		}

		// Send DATA.
		beginData();
		recvReply(DATA_OK);

		// Send the content of the mail.
		sendContent(mail);

		// Send END="\r\n.\r\n".
		endData();
		recvReply(COMMAND_OK);
		
		// Send QUIT
		quit();
		recvReply(QUIT_OK);

	} catch (Exception ex) {
		ex.print();
		error = ex.getString();
	}
	if (socket) {
		socket -> close();
	}
	delete socket;
	socket = null;
}


