#include "SendMail2.h"
#include "ZString.h"
#include <chrono>
#include <string>
#include <cstdio>
#include <iostream>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <resolv.h>
#include "Log.h"

#define BUFFER_SIZE 1048576

namespace mail {
   
   SendMail2::SendMail2(core::EPoll &ePoll, coreutils::MString from, coreutils::MString recipient, coreutils::MString message)
     : core::TCPSession2(ePoll, "Send Mail Injector"), from(from), recipient(recipient),
     Timer(ePoll, 30.00f), ePoll(ePoll), message(message) {
	coreutils::Log(coreutils::LOG_DEBUG_1) << "SendMail2 constructed.";
     }
   
   int SendMail2::send() {
      
      waiter.lock();
      coreutils::Log(coreutils::LOG_DEBUG_1) << this->recipient;
      this->recipient.split("@");
      coreutils::Log(coreutils::LOG_DEBUG_1) << this->recipient[1];
      
      u_char nsbuff[4096];
      char *domain = this->recipient[1].c_str();
      int len = res_search(domain, C_IN, T_MX, nsbuff, sizeof(nsbuff));
      ns_msg msg;
      
      ns_initparse(nsbuff, len, &msg);
      len = ns_msg_count(msg, ns_s_an);
      
      char dispbuf[4096];
      ns_rr rr;
      for (int i = 0; i < 1; i++) {
	 ns_parserr(&msg, ns_s_an, i, &rr);
	 ns_sprintrr(&msg, &rr, NULL, NULL, dispbuf, sizeof(dispbuf));
      }
      coreutils::Log(coreutils::LOG_DEBUG_1) << "dispbuf: " << dispbuf;
      
      coreutils::ZString  mxArray(dispbuf);
      mxArray.find("MX");
      mxArray.ifNext("MX");
      mxArray.skipWhitespace();
      mxArray.getTokenInclude("0123456789");
      mxArray.skipWhitespace();
      coreutils::Log(coreutils::LOG_DEBUG_1) << "MX: " << mxArray.unparsed();
      core::IPAddress mxAddress(mxArray.unparsed().c_str(), 25);
      coreutils::Log(coreutils::LOG_DEBUG_1) << "IP: " << mxAddress.getClientAddressAndPort();
      connect(mxAddress);
      
      coreutils::Log(coreutils::LOG_DEBUG_1) << "SendMail2 injector initiated...";
      return 0;
   }
   
   SendMail2::SendMail2(const SendMail2 &copy)  : core::TCPSession2(ePoll, "Send Mail Injector"), from(copy.from), recipient(copy.recipient), 
     Timer(ePoll, 30.00f), ePoll(copy.ePoll), message(copy.message) {}
   
   SendMail2::~SendMail2() {
      coreutils::Log(coreutils::LOG_DEBUG_1) << "SendMail destructing...";
   }
   
   void SendMail2::onTimeout() {
      coreutils::Log(coreutils::LOG_DEBUG_1) << "onTimeout..." << state;
      returnValue << "timeout in " << state;
      state = SENT;
      waiter.unlock();
   }
   
   void SendMail2::protocol(coreutils::ZString &data) {
      
      coreutils::Log(coreutils::LOG_DEBUG_1) << "[" << data << "..." << state;
      
      switch (state) {
	 
       case CONNECT:
	 if(data.asInteger() == 220) {
	    out << "EHLO " << "drinkwise.barant.com" << CRLF;
	    coreutils::Log(coreutils::LOG_DEBUG_1) << ">EHLO";
	    state = READY;
	 }
	 break;
	 
       case READY:
	 buffer = data;
	 setTimer(30);
	 stateOnTimeout = READYX;
	 state = READYX;
	 break;
	 
       case READYX:
	 if(buffer.asInteger() == 250) {
	    coreutils::Log(coreutils::LOG_DEBUG_1) << ">MAIL FROM:<" << from << ">";
	    out << "MAIL FROM:<" << from << ">" << CRLF;
	    state = MAIL;
	 }
	 break;
	 
       case MAIL:
	 if(data.asInteger() == 250) {
	    coreutils::Log(coreutils::LOG_DEBUG_1) << ">RCPT TO:<" << recipient << ">";
	    out << "RCPT TO:<" << recipient << ">" << CRLF;
	    state = RCPT;
	 }
	 break;
	 
       case RCPT:
	 if(data.asInteger() == 250) {
	    out << "DATA" << CRLF;
	    state = DATA;
	 }
	 break;
	 
       case DATA:
	 if(data.asInteger() == 354) {
	    out << message << CRLF;
	    out << "." << CRLF;
	    state = SENT;
	 } else if (data.asInteger() == 421) {
            coreutils::Log(coreutils::LOG_DEBUG_1) << "Error 421";
            data.split(" ", 2);
            returnValue = data;
	    state = SENT;
            waiter.unlock();
	 } else if (data.asInteger() == 450) {
            coreutils::Log(coreutils::LOG_DEBUG_1) << "Error 450";
            data.split(" ", 2);
            returnValue = data;
	    state = SENT;
            waiter.unlock();
	 } else if (data.asInteger() == 451) {
            coreutils::Log(coreutils::LOG_DEBUG_1) << "Error 451";
            data.split(" ", 2);
            returnValue = data;
	    state = SENT;
            waiter.unlock();
	 } else if (data.asInteger() == 452) {
            coreutils::Log(coreutils::LOG_DEBUG_1) << "Error 452";
            data.split(" ", 2);
            returnValue = data;
	    state = SENT;
            waiter.unlock();
	 } else if (data.asInteger() == 550) {
            data.split(" ", 2);
            returnValue = data;
	    state = SENT;
            waiter.unlock();
      	} else if (data.asInteger() == 552) {
	   coreutils::Log(coreutils::LOG_DEBUG_1) << "Error 552";
	   data.split(" ", 2);
	   returnValue = data;
	   state = SENT;
	   waiter.unlock();
	}
	 break;
	 
       case SENT:
	 returnValue = data;
	 out << "QUIT" << CRLF;
	 waiter.unlock();
	 break;
	 
      }
      
   }
   
   coreutils::MString SendMail2::wait() {
      waiter.lock();
      waiter.unlock();
      return returnValue;
   }
   
   
   std::vector<coreutils::MString>& SendMail2::extractRecipientList() {
      return recipientList;
   }
   
}
