#include "CSMTPConnection\stdafx.h"
#include <pbext.h>
#include "pbnismtp.h"
#ifndef __PJNSMTP_H__
#include "CSMTPConnection\PJNSMTP.h"
#endif
#include <tchar.h>

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  reasonForCall,
                       LPVOID lpReserved )
{
	switch( reasonForCall )
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

PBXEXPORT LPCTSTR PBXCALL PBX_GetDescription()
{
	static const TCHAR desc[] =
	{
		_T ( "class n_cpp_smtp from nonvisualobject\n" )
		_T ( "function int Send ( )\n" )
		_T ( "subroutine SetMessage ( string pbmessage )\n" )
		_T ( "subroutine SetMessage ( string pbmessage, boolean pbHTML )\n" )
		_T ( "subroutine SetRecipientEmail ( string pbrecipientemail )\n")
		_T ( "subroutine SetCCRecipientEmail ( string pbCCrecipientemail )\n" )
		_T ( "subroutine SetBCCRecipientEmail ( string pbBCCrecipientemail )\n" )
		_T ( "subroutine SetReplyToEmail ( string pbreplytoemail )\n" )
		_T ( "subroutine SetSenderEmail ( string pbsenderemail )\n" )
		_T ( "subroutine SetSMTPServer ( string pbsmtpserver )\n" )
		_T ( "subroutine SetSubject ( string pbsubject )\n" )
		_T ( "subroutine SetAttachment ( string pbattachment )\n" )
		_T ( "subroutine SetErrorMessagesOn ( )\n" )
		_T ( "subroutine SetErrorMessagesOff ( )\n" )
		_T ( "subroutine SetCharSet ( string pbcharset )\n" )
		_T ( "subroutine SetUsernamePassword ( string pbusername, string pbpassword )\n" )
		_T ( "subroutine SetPort ( integer port )\n" )
		_T ( "subroutine SetAuthMethod ( integer authmethod )\n" )
		_T ( "subroutine SetConnectionType ( integer connecttype )\n" )
		_T ( "function string GetLastErrorMessage ( )\n")
		_T ( "subroutine SetMailerName ( string pbname )\n")
		_T ( "subroutine SetPriority ( integer priority )\n")
		_T ( "subroutine SetPriorityNone ( )\n")
		_T ( "subroutine SetPriorityLow ( )\n")
		_T ( "subroutine SetPriorityNormal ( )\n")
		_T ( "subroutine SetPriorityHigh ( )\n")
		_T ( "subroutine SetReadReceiptRequested ( boolean pbboolean )\n")
		_T ( "function int SmtpConnect ( )\n")
		_T (" function int SmtpSend ( )\n")
		_T (" function int SmtpDisconnect ( )\n")
		_T ( "end class\n" )
	};
	return (LPCTSTR)desc ;
}

PBXEXPORT PBXRESULT PBXCALL PBX_CreateNonVisualObject(
	IPB_Session*			pbsession, 
	pbobject				   pbobj, 
	LPCTSTR					className, 
	IPBX_NonVisualObject	**obj
)
{

	LPCTSTR myclassname = _T ( "n_cpp_smtp" ) ;

	if ( _tcscmp( className, myclassname ) == 0 )
	{
		*obj = new CSMTP() ;
		return PBX_OK ;
	} ;

	*obj = NULL ;
	return PBX_E_NO_SUCH_CLASS ;

}

enum MethodIDs
{
	SEND,
	SETMESSAGE,
	SETMESSAGEHTML,
	SETRECIPIENTEMAIL,
	SETCCRECIPIENTEMAIL,
	SETBCCRECIPIENTEMAIL,
	SETREPLYTOEMAIL,
	SETSENDEREMAIL,
	SETSMTPSERVER,
	SETSUBJECT,
	SETATTACHMENT,
	SETERRORMESSAGESON,
	SETERRORMESSAGESOFF,
	SETMSGCHARSET,
	SETUSERNAMEPASSWORD,
	SETPORT,
	SETAUTHMETHOD,
	SETCONNECTIONTYPE,
	GETLASTERRORMESSAGE,
	SETMAILERNAME,
	SETPRIORITY,
	SETPRIORITYNONE,
	SETPRIORITYLOW,
	SETPRIORITYNORMAL,
	SETPRIORITYHIGH,
	SETREADRECEIPTREQUEST,
	SMTPCONNECT,
	SMTPSEND,
	SMTPDISCONNECT,
	ENTRY_COUNT
};

DWORD CSMTP::m_dwRefCount = 0;

CSMTP::CSMTP()
{	
	WSADATA wd;

	if( ++m_dwRefCount == 1 )
	{
		::WSAStartup( 0x0101, &wd );
	}

	MessageArg = NULL ;
	SenderEmailArg = NULL ;
	RecipientEmailArg = NULL ;
	CCRecipientEmailArg = NULL ;
	BCCRecipientEmailArg = NULL ;
	ReplyToEmailArg = NULL;
	SMTPServerArg = NULL ;
	SubjectArg = NULL ;
	AttachmentArg = NULL ;
	CharSetArg = NULL ;
	UsernameArg = NULL ;
	PasswordArg = NULL ;
	ReadReceiptArg = NULL;

	Message = NULL;  
	SenderEmail = NULL;
	RecipientEmail = NULL;
	CCRecipientEmail = NULL;
	BCCRecipientEmail = NULL;
	ReplyToEmail = NULL;
	SMTPServer = NULL;
	Subject = NULL; 
	Attachment = NULL;
	Username = NULL ;
	Password = NULL ;
	CharSet = _T("iso-8859-1");

	ErrorMessageBoxesOn = FALSE;    /* initialize to off  */	

	HTMLBody = FALSE ;

	Port = 25;
	AuthMethod = 5; /* Default to Auto Detect */
	ConnectType = 0; /* Default to Plain Text */
	Priority = 0; /* Default to No Priority */
	MailerName = _T("PBNISMTP 3.6");
}

CSMTP::~CSMTP(void)
{
	if( --m_dwRefCount == 0 )
	{
		::WSACleanup();
	}
}

int CSMTP::SmtpConnect()
{

	TCHAR	title[] = _T("Debug");
	INT	ReturnCode = UNDEFINEDERR;

	if (SMTPServer == NULL)
	{
		return INVALIDSMTPSERVER;
	}

	try
	{
		// Set the Return Code if Exception is raised for the following calls
		ReturnCode = SMTPCONNECTFAILED;

		// Connect to SMTP server
		iConnection.Connect(SMTPServer, CPJNSMTPConnection::AuthenticationMethod(AuthMethod), Username, Password, Port, CPJNSMTPConnection::ConnectionType(ConnectType));

		// Everything was Successful!
		ReturnCode = SUCCESSFUL;
	}
#ifdef CPJNSMTP_MFC_EXTENSIONS
	catch (CPJNSMTPException* pEx)
	{
		CloseGracefully = FALSE;
		LastErrorMsg = pEx->m_sLastResponse;
		if (LastErrorMsg == "")
		{
			LastErrorMsg = (CString)pEx->GetErrorMessage().operator LPCTSTR();
		}
		if (ErrorMessageBoxesOn == TRUE)
		{
			//Display the error
			CString sMsg;
			sMsg.Format(_T("Could not connect message: Error:%08X\nDescription:%s"), pEx->m_hr, LastErrorMsg);
			MessageBox(NULL, sMsg, title, MB_ICONEXCLAMATION | MB_OK);
		}
		pEx->Delete();
	}
#else
	catch (CPJNSMTPException& e)
	{
		LastErrorMsg = e.m_sLastResponse.c_str();
		if (LastErrorMsg == "")
		{
			TCHAR szError[4096];
			szError[0] = _T('\0');
			e.GetErrorMessage(szError, _countof(szError));
			LastErrorMsg = (CString)szError;
		}
		if (ErrorMessageBoxesOn == TRUE)
		{
			//Display the error
			CString sMsg;
			sMsg.Format(_T("Could not connect message: Error:%08X\nDescription:%s"), e.m_hr, LastErrorMsg);
			MessageBox(NULL, sMsg, title, MB_ICONEXCLAMATION | MB_OK);
		}
	}
#endif

	return ReturnCode;

};

int CSMTP::SmtpSend()
{
	TCHAR	title[] = _T("Debug");
	CPJNSMTPMessage msg;
	INT	ReturnCode = UNDEFINEDERR;

	// Validate the passed in values first
	if (SenderEmail == NULL)
	{
		return INVALIDSENDEREMAIL;
	}

	if (RecipientEmail == NULL && CCRecipientEmail == NULL && BCCRecipientEmail == NULL)
	{
		return INVALIDRECIPIENTEMAIL;
	}

	if (Subject == NULL)
	{
		Subject = _T("");
	}

	if (Message == NULL)
	{
		Message = _T("");
	}

	try
	{
		// Set the Return Code if Exception is raised for the following calls
		ReturnCode = INVALIDRECIPIENTEMAIL;

		// Set the Charset
		msg.SetCharset(CharSet);

		// Set the Sender
		CPJNSMTPAddress address(SenderEmail);
		msg.m_From = address;

		// Set the Recipient
		msg.ParseMultipleRecipients(RecipientEmail, msg.m_To);

		// Set the CC
		if (CCRecipientEmail != NULL)
		{
			msg.ParseMultipleRecipients(CCRecipientEmail, msg.m_CC);
		}
		// Set the BCC
		if (BCCRecipientEmail != NULL)
		{
			msg.ParseMultipleRecipients(BCCRecipientEmail, msg.m_BCC);
		}
		// Set the Reply To
		if (ReplyToEmail != NULL)
		{
			msg.ParseMultipleRecipients(ReplyToEmail, msg.m_ReplyTo);
		}

		// Set Read Receipt header
		if (ReadReceipt == TRUE)
		{
			CString dString;
			dString.Format(_T("Disposition-Notification-To: %s"), SenderEmail);
			msg.m_CustomHeaders.push_back((CPJNSMTPString)dString);

		}

		// set the message priority
		switch (Priority) {
		case 0:
			msg.m_Priority = CPJNSMTPMessage::PRIORITY::None;
			break;
		case 1:
			msg.m_Priority = CPJNSMTPMessage::PRIORITY::Low;
			break;
		case 2:
			msg.m_Priority = CPJNSMTPMessage::PRIORITY::Normal;
			break;
		case 3:
			msg.m_Priority = CPJNSMTPMessage::PRIORITY::High;
			break;
		}

		// Set the Return Code if Exception is raised for the following calls
		ReturnCode = MESSAGEBODYERROR;

		// Set the subject and message
		msg.m_sSubject = (CString)Subject;
		msg.m_sXMailer = MailerName;
		if (HTMLBody)
		{
			msg.SetMime(TRUE);
			msg.AddHTMLBody(Message);
		}
		else
		{
			msg.AddTextBody(Message);
		}

		// Add any attachment
		if (Attachment != NULL)
		{
			msg.AddMultipleAttachments(Attachment);
		}

		// Set the Return Code if Exception is raised for the following calls
		ReturnCode = MESSAGESENDERROR;

		// Now send the message
		iConnection.SendMessage(msg);

		// Everything was Successful!
		ReturnCode = SUCCESSFUL;
}
#ifdef CPJNSMTP_MFC_EXTENSIONS
	catch (CPJNSMTPException* pEx)
	{
		CloseGracefully = FALSE;
		LastErrorMsg = pEx->m_sLastResponse;
		if (LastErrorMsg == "")
		{
			LastErrorMsg = (CString)pEx->GetErrorMessage().operator LPCTSTR();
		}
		if (ErrorMessageBoxesOn == TRUE)
		{
			//Display the error
			CString sMsg;
			sMsg.Format(_T("Could not send message: Error:%08X\nDescription:%s"), pEx->m_hr, LastErrorMsg);
			MessageBox(NULL, sMsg, title, MB_ICONEXCLAMATION | MB_OK);
		}
		pEx->Delete();
	}
#else
	catch (CPJNSMTPException& e)
	{
		LastErrorMsg = e.m_sLastResponse.c_str();
		if (LastErrorMsg == "")
		{
			TCHAR szError[4096];
			szError[0] = _T('\0');
			e.GetErrorMessage(szError, _countof(szError));
			LastErrorMsg = (CString)szError;
		}
		if (ErrorMessageBoxesOn == TRUE)
		{
			//Display the error
			CString sMsg;
			sMsg.Format(_T("Could not send message: Error:%08X\nDescription:%s"), e.m_hr, LastErrorMsg);
			MessageBox(NULL, sMsg, title, MB_ICONEXCLAMATION | MB_OK);
		}
	}
#endif

	return ReturnCode;
};

int CSMTP::SmtpDisconnect()
{
   TCHAR	title[] = _T("Debug");
   BOOLEAN CloseGracefully = TRUE;
   INT	ReturnCode = UNDEFINEDERR;

   // Disconnect from the server
   try
   {
      if (iConnection.IsConnected())
         iConnection.Disconnect(CloseGracefully);
      // Everything was Successful!
      ReturnCode = SUCCESSFUL;
   }
#ifdef CPJNSMTP_MFC_EXTENSIONS
   catch (CPJNSMTPException* pEx)
   {
      pEx->Delete();
   }
#else
   catch (CPJNSMTPException& e)
   {
      LastErrorMsg = e.m_sLastResponse.c_str();
      if (LastErrorMsg == "")
      {
         TCHAR szError[4096];
         szError[0] = _T('\0');
         e.GetErrorMessage(szError, _countof(szError));
         LastErrorMsg = (CString)szError;
      }
   }
#endif

   return ReturnCode;
};

PBXRESULT CSMTP::Invoke(IPB_Session * session, pbobject obj, pbmethodID mid, PBCallInfo * ci)
{
	Session = session ;

	switch( mid )
	{
	case SEND:
		{
		int	rc;

		rc = SmtpConnect();
		if (rc == SUCCESSFUL) {
			rc = SmtpSend();
			SmtpDisconnect();
		}

		ci->returnValue->SetInt((pbint)rc);
		return PBX_OK;
		}
	case SETMESSAGE:
		{
		MessageArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbMessage = MessageArg->GetString() ;
		Message = session->GetString(pbMessage) ;
		return PBX_OK;
		}
	case SETMESSAGEHTML:
		{
		MessageArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbMessage = MessageArg->GetString() ;
		Message = session->GetString(pbMessage) ;
		IPB_Value * HTMLArg = session->AcquireValue ( ci->pArgs->GetAt(1) ) ;
		HTMLBody = (bool)HTMLArg->GetBool() ;
		if (HTMLArg)
		{
			Session->ReleaseValue(HTMLArg);
		}
		return PBX_OK;
		}
	case SETRECIPIENTEMAIL:
		{
		RecipientEmailArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbRecipientEmail = RecipientEmailArg->GetString() ;
		RecipientEmail = session->GetString(pbRecipientEmail) ;
		return PBX_OK;
		}
	case SETCCRECIPIENTEMAIL:
		{
		CCRecipientEmailArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbCCRecipientEmail = CCRecipientEmailArg->GetString() ;
		CCRecipientEmail = session->GetString( pbCCRecipientEmail ) ;
		return PBX_OK;
		}
	case SETBCCRECIPIENTEMAIL:
		{
		BCCRecipientEmailArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbBCCRecipientEmail = BCCRecipientEmailArg->GetString() ;
		BCCRecipientEmail = session->GetString( pbBCCRecipientEmail ) ;
		return PBX_OK;
		}
	case SETREPLYTOEMAIL:
		{
		ReplyToEmailArg = session->AcquireValue ( ci->pArgs->GetAt(0) );
		pbstring pbReplyToEmail = ReplyToEmailArg->GetString();
		ReplyToEmail = session->GetString( pbReplyToEmail );
		return PBX_OK;
		}
	case SETSENDEREMAIL:
		{
		SenderEmailArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbSenderEmail = SenderEmailArg->GetString() ;
		SenderEmail = session->GetString ( pbSenderEmail ) ;
		return PBX_OK;
		}
	case SETSMTPSERVER:
		{
		SMTPServerArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbSMTPServer = SMTPServerArg->GetString() ;
		SMTPServer = session->GetString ( pbSMTPServer ) ;
		return PBX_OK;
		}
	case SETSUBJECT: 
		{
		SubjectArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbSubject = SubjectArg->GetString() ;
		Subject = session->GetString ( pbSubject ) ;
		return PBX_OK;
		}
	case SETATTACHMENT:
		{
		AttachmentArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbAttachment = AttachmentArg->GetString() ;
		Attachment = session->GetString ( pbAttachment ) ;
		return PBX_OK;
		}
	case SETERRORMESSAGESON:
		{
		ErrorMessageBoxesOn = TRUE; 
		return PBX_OK;		
		}
	case SETERRORMESSAGESOFF:
		{
		ErrorMessageBoxesOn = FALSE; 
		return PBX_OK;		
		}
	case SETMSGCHARSET:
		{
		CharSetArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbCharSet = CharSetArg->GetString() ;
		CharSet = session->GetString ( pbCharSet ) ;
		return PBX_OK;
		}
	case SETUSERNAMEPASSWORD:
		{
		UsernameArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		pbstring pbUsername = UsernameArg->GetString() ;
		Username = session->GetString ( pbUsername ) ;
		PasswordArg = session->AcquireValue ( ci->pArgs->GetAt(1) ) ;
		pbstring pbPassword = PasswordArg->GetString() ;
		Password = session->GetString ( pbPassword ) ;
		return PBX_OK;
		}
	case SETPORT:
		{
		IPB_Value * PortArg = session->AcquireValue ( ci->pArgs->GetAt(0) ) ;
		Port = (int)PortArg->GetInt();
		if (PortArg)
		{
			Session->ReleaseValue(PortArg);
		}
		return PBX_OK;
		}
	case SETAUTHMETHOD:
		{
		IPB_Value * AuthArg = session->AcquireValue ( ci->pArgs->GetAt(0) );
		AuthMethod = (int)AuthArg->GetInt();
		if (AuthArg)
		{
			Session->ReleaseValue( AuthArg );
		}
		return PBX_OK;
		}
	case SETCONNECTIONTYPE:
		{
		IPB_Value * ConnectionArg = session->AcquireValue ( ci->pArgs->GetAt(0) );
		ConnectType = (int)ConnectionArg->GetInt();
		if (ConnectionArg)
		{
			Session->ReleaseValue( ConnectionArg );
		}
		return PBX_OK;
		}
	case GETLASTERRORMESSAGE:
		{
		ci->returnValue->SetString(LastErrorMsg);
		return PBX_OK;
		}
	case SETMAILERNAME:
		{
		MailerNameArg = session->AcquireValue(ci->pArgs->GetAt(0));
		pbstring pbMailerName = MailerNameArg->GetString();
		MailerName = session->GetString(pbMailerName);
		return PBX_OK;
		}
	case SETPRIORITY:
		{
		IPB_Value * PriorityArg = session->AcquireValue(ci->pArgs->GetAt(0));
		Priority = (int)PriorityArg->GetInt();
		if (PriorityArg)
		{
			Session->ReleaseValue(PriorityArg);
		}
		return PBX_OK;
		}
	case SETPRIORITYNONE:
		{
		Priority = 0;
		return PBX_OK;
		}
	case SETPRIORITYLOW:
		{
		Priority = 1;
		return PBX_OK;
		}
	case SETPRIORITYNORMAL:
		{
		Priority = 2;
		return PBX_OK;
		}
	case SETPRIORITYHIGH:
		{
		Priority = 3;
		return PBX_OK;
		}
	case SETREADRECEIPTREQUEST:
		{
		IPB_Value * ReadReceiptArg = session->AcquireValue(ci->pArgs->GetAt(0));
		ReadReceipt = (bool)ReadReceiptArg->GetBool();
		if (ReadReceiptArg)
		{
			Session->ReleaseValue(ReadReceiptArg);
		}
		return PBX_OK;
		}
	case SMTPCONNECT:
		{
		int	rc;
		rc = SmtpConnect();
		ci->returnValue->SetInt((pbint)rc);
		return PBX_OK;
		}
	case SMTPSEND:
		{
		int	rc;
		rc = SmtpSend();
		ci->returnValue->SetInt((pbint)rc);
		return PBX_OK;
		}
	case SMTPDISCONNECT:
		{
		int	rc;
		rc = SmtpDisconnect();
		ci->returnValue->SetInt((pbint)rc);
		return PBX_OK;
		}
	return PBX_E_INVOKE_METHOD_AMBIGUOUS;
	}
}

void CSMTP::CleanUp()
{
	//If any of our local IPB_Value pointers are populated
	//we need to release them to avoid a memory leak
	if (MessageArg)
	{
		Session->ReleaseValue ( MessageArg ) ;
	}
	if (SenderEmailArg)
	{
		Session->ReleaseValue ( SenderEmailArg ) ;
	}
	if (RecipientEmailArg)
	{
		Session->ReleaseValue ( RecipientEmailArg ) ;
	}
	if (CCRecipientEmailArg)
	{
		Session->ReleaseValue ( CCRecipientEmailArg ) ;
	}
	if (BCCRecipientEmailArg)
	{
		Session->ReleaseValue ( BCCRecipientEmailArg ) ;
	}
	if (ReplyToEmailArg)
	{
		Session->ReleaseValue( ReplyToEmailArg );
	}
	if (SMTPServerArg)
	{
		Session->ReleaseValue ( SMTPServerArg ) ;
	}
	if (SubjectArg)
	{
		Session->ReleaseValue ( SubjectArg ) ;
	}
	if (AttachmentArg)
	{
		Session->ReleaseValue ( AttachmentArg ) ;
	}
	if (CharSetArg)
	{
		Session->ReleaseValue ( CharSetArg ) ;
	}
	if (UsernameArg)
	{
		Session->ReleaseValue( UsernameArg );
	}
	if (PasswordArg)
	{
		Session->ReleaseValue( PasswordArg );
	}
	if (ReadReceiptArg)
	{
		Session->ReleaseValue( ReadReceiptArg );
	}
}

void CSMTP::Destroy()
{
	//Do cleanup before exiting
	CleanUp();

	delete this ;
}
