/*
Exchange notifier plugin for Miranda IM

Copyright � 2006 Cristian Libotean, Attila Vajda

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "emails.h"

CExchangeServer::CExchangeServer()
{
	bConnected = 0; //not connected
	bTryConnect = 1; //try to connect
	cConnections = 0; //first attempt
}

CExchangeServer::~CExchangeServer()
{
	Disconnect();
}

int CExchangeServer::Connect(int bForceConnect)
{
	int maxRetries = db_get_b(NULL, ModuleName, "MaxRetries", MAX_EXCHANGE_CONNECT_RETRIES);
	if (bForceConnect)
	{
		bTryConnect = 1;
		cConnections = 0;
	}
		
	if (cConnections >= maxRetries)
	{
		bTryConnect = 0;
		cConnections = 0;
		_popupUtil("Maximum number of retries reached.\nPlugin will stop trying to connect automatically.");
	}
	if (bTryConnect)
	{
		cConnections++;
	}
		
	if ((bTryConnect) && !IsServerAvailable())
	{
		bTryConnect = 0;
		_popupUtil("Server not available");
	}		
		
	if ((!IsConnected()) && (bTryConnect))
		{
			TCHAR user[1024]; //lovely
			TCHAR password[1024]; //i know
			TCHAR server[1024];
			int port;
			
			GetStringFromDatabase("Username", _T(""), user, _countof(user));
			if (ServiceExists(MS_UTILS_REPLACEVARS))
			{
				TCHAR *tmpUser = Utils_ReplaceVarsT(user);
				
				_tcsncpy(user, tmpUser, _countof(user));
				mir_free(tmpUser);
			}
			
			GetStringFromDatabase("Password", _T(""), password, _countof(password));
			CallService(MS_DB_CRYPT_DECODESTRING, sizeof(password), (LPARAM) password);
			GetStringFromDatabase("Server", _T(""), server, _countof(server));
			port = db_get_dw(NULL, ModuleName, "Port", EXCHANGE_PORT);
			if (_tcslen(server) > 0) //only connect if there's a server to connect to
			{
				return DoConnect(user, password, server, port);			
			}
			else {
				_popupUtil("Server is not configured ...");
			}
		}
	return -1; //0 on success, != 0 otherwise
}

int CExchangeServer::Reconnect()
{
	Disconnect();
	Connect();
	return 0;
}

int CExchangeServer::Disconnect()
{
//	if (IsConnected())
//		{
			return DoDisconnect();
//		}
//	return -1; //0 on success, != 0 otherwise
}

int CExchangeServer::DoConnect(TCHAR *user, TCHAR *password, TCHAR *server, int port)
{
	
	if (bTryConnect)
	{
		bConnected = 0;
#ifndef NO_EXCHANGE_TEST
		if ( InitializeAndLogin( user, password, server )== S_OK)
		{
			bConnected = 1;
			cConnections = 0; //restart connection attempts counter
		}

#endif
	}

	return !bConnected; //0 on success, != 0 otherwise
}

int CExchangeServer::DoDisconnect()
{
#ifndef NO_EXCHANGE_TEST
	LogOFF();
#endif	
	bConnected = 0;
	return bConnected; //0 on success, != 0 otherwise
}

int CExchangeServer::IsConnected()
{
#ifndef NO_EXCHANGE_TEST
	return bConnected;
#else
	return true;
#endif	
}

void InitSocketAddr(sockaddr_in *addrServer, char *szServer)
{
	hostent *hp;
	hp = gethostbyname(szServer);
	addrServer->sin_family = AF_INET;
	if (hp == NULL)
	{
		addrServer->sin_addr.s_addr = inet_addr(szServer);
	}
	else{
		memcpy(&(addrServer->sin_addr), hp->h_addr, hp->h_length);		
	}
	int port = db_get_dw(NULL, ModuleName, "Port", EXCHANGE_PORT);
	addrServer->sin_port = htons(port);
}

int CExchangeServer::IsServerAvailable()
{
	int check = db_get_b(NULL, ModuleName, "UsePortCheck", 1);
	if (check)
	{
		SOCKET sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (sServer == INVALID_SOCKET)
		{
			return 0; //server is not available
		}
		TCHAR szServer[1024];
		GetStringFromDatabase("Server", _T(""), szServer, sizeof(szServer));
		sockaddr_in addrServer;
		InitSocketAddr(&addrServer, mir_t2a(szServer));
		int res = connect(sServer, (sockaddr *) &addrServer, sizeof(addrServer));
		int bAvailable = 0;
		if (!res)
		{//if connected then close smtp connection by sending a quit message
			bAvailable = 1;
			char message[] = "quit\n";
			res = send(sServer, message, strlen(message), 0); 
		}
		res = closesocket(sServer); //close the socket
		return bAvailable;
	}
	else{
		return 1; //if we're not using port check assume the server is available.
	}
}

int CExchangeServer::GetUnreadEmailsCount()
{
	int nCount = -1;

#ifndef NO_EXCHANGE_TEST	
	HRESULT hRes = CheckForNewMails(nCount);

	if (hRes!=S_OK)
	{
		Reconnect();

		if (IsConnected())
		{	
			hRes = CheckForNewMails(nCount);
		}
		else {
			nCount = -1;
		}
	}
#else
	nCount = 3;	
#endif

	return nCount;
}

int CExchangeServer::GetEmailHeader(int iUnreadEmail, TEmailHeader *emailInfo)
{
	if (!IsConnected())
	{
		//Connect();
		return -1;
	}
	if (emailInfo->cbSize != sizeof(TEmailHeader))
	{
		return -1;
	}

#ifndef NO_EXCHANGE_TEST

	if(NULL!=m_HeadersKeeper[iUnreadEmail])
	{
		TCHAR* szSender  = m_HeadersKeeper[iUnreadEmail]->m_szSender;
		TCHAR* szSubject = m_HeadersKeeper[iUnreadEmail]->m_szSubject;

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

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

		emailInfo->szSender  = szSender;
		emailInfo->szSubject = szSubject;
		emailInfo->emailID   = (NULL!=m_HeadersKeeper[iUnreadEmail]->m_szEntryID)?m_HeadersKeeper[iUnreadEmail]->m_szEntryID:"";
		
	}
	else {
		return -1;
	}


#else
	emailInfo->szSender = "<sender>";
	emailInfo->szSubject = "<subject>";
	emailInfo->emailID = "123";
#endif

	return 0;
}

int CExchangeServer::MarkEmailAsRead(TCHAR *emailID)
{
	if (!IsConnected())
	{
		return -1;
	}

#ifndef NO_EXCHANGE_TEST	
	MarkAsRead( emailID );
#endif
	
	return 0;
}

int CExchangeServer::OpenMessage(TCHAR *emailID)
{
	if (!IsConnected())
	{
		return -1;
	}

#ifndef NO_EXCHANGE_TEST	
	OpenTheMessage( emailID );
#endif

	return 0;
}

int CExchangeServer::Check(int bNoEmailsNotify)
{

	int count = -1;
	if (IsConnected())
	{
		count =	GetUnreadEmailsCount();

		if (count==-1)
		{
			Reconnect();	
			if (IsConnected())
			{	
				count = GetUnreadEmailsCount();	
			}
			else {
				return -1;
			}
		}

	}
	else {	
		Reconnect();
		if (IsConnected())
		{	
			count = GetUnreadEmailsCount();	
		}
		else {
			return -1;
		}
		
		if (count==-1)
		{
			return -1;
		}
	}

	if( ( (count > 0) || ((bNoEmailsNotify) && (count >= 0)) )&& (count!=-1))
	{
		TCHAR buffer[1024];
		if (count != 1)
		{
			mir_sntprintf(buffer,_countof(buffer), TranslateT("You have %d unread emails ..."), count);
		}
		else {
			mir_sntprintf(buffer, _countof(buffer),TranslateT("You have one unread email ..."));
		}

		ShowMessage(buffer, count);
	}

	if (count==-1)
	{
		_popupUtil("Cannot connect to Exchange server ...");
	}

	return count;
}

int ShowMessage(TCHAR *message, int cUnreadEmails)
{
	int usePopups = ServiceExists(MS_POPUP_ADDPOPUP) ? db_get_b(NULL, ModuleName, "UsePopups", 0) : 0;
	if (usePopups)
	{
		return ShowPopupMessage(TranslateT("Exchange email"), message, cUnreadEmails);
	}
	else{
		return ShowMessageBoxMessage(TranslateT("Do you want to see the email headers?"), message, cUnreadEmails);
	}
	
	return 0;
}

int ShowPopupMessage(TCHAR *title, TCHAR *message, int cUnreadEmails)
{
	POPUPDATAT popup = {0};
	popup.lchContact = NULL;
	popup.colorBack = NULL;
	popup.colorText = NULL;
	popup.lchIcon = hiMailIcon;
	_tcsncpy(popup.lptzContactName, title,_tcslen(title));
	_tcsncpy(popup.lptzText, message,_tcslen(message));
	popup.PluginWindowProc = (WNDPROC) DlgProcPopup;
	popup.PluginData = (int *) cUnreadEmails;
	return PUAddPopupT(&popup);
}

int ShowMessageBoxMessage(TCHAR *title, TCHAR *message, int cUnreadEmails)
{
	if (MessageBox(0, message, title, MB_YESNO) == IDYES)
	{
		ShowEmailsWindow(cUnreadEmails);
	}
	
	return 0;
}

int ShowEmailsWindow(int cUnreadEmails)
{
	if (cUnreadEmails > 0) //show window only if there are unread emails
	{
		if (!hEmailsDlg)
		{
			hEmailsDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_EMAILS), NULL, (DLGPROC)DlgProcEmails);
		}
		
		SetWindowLong(hEmailsDlg, GWLP_USERDATA, cUnreadEmails);
		if (IsWindowVisible(hEmailsDlg))
		{
			SendMessage(hEmailsDlg, EXM_UPDATE_EMAILS, 0, 0);
		}
		else {
			ShowWindow(hEmailsDlg, SW_SHOW);
		}
	}
	return 0;
}