#include "stdafx.h"

mir_cs lib_cs;

void lib_cs_lock()
{
	mir_cslock lck(lib_cs);
}

MCONTACT find_contact(const char* userid, const char* protocol)
{
	for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
		const char *proto = GetContactProto(hContact);
		if(proto && mir_strcmp(proto, protocol) == 0) {
			char *name = contact_get_id(hContact);
			if(name && mir_strcmp(name, userid) == 0) {
				mir_free(name);
				return hContact;
			}
			mir_free(name);
		}
	}
	
	return 0;
}

/* Look up a connection context by hContact from the given
* OtrlUserState.  If add_if_missing is true, allocate and return a new
* context if one does not currently exist.  In that event, call
* add_app_data(data, context) so that app_data and app_data_free can be
* filled in by the application, and set *addedp to 1. */
ConnContext * otrl_context_find_miranda(OtrlUserState us, MCONTACT hContact)
{
	const char *proto = GetContactProto(hContact);
	char *username = contact_get_id(hContact);
	ConnContext* ret = otrl_context_find(us, username, proto, proto, OTRL_INSTAG_BEST, 0, NULL, NULL, NULL);
	mir_free(username);
	return ret;
}

/* What level of trust do we have in the privacy of this ConnContext? */
TrustLevel otr_context_get_trust(ConnContext *context)
{
	TrustLevel level = TRUST_NOT_PRIVATE;

	if (context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
		if (context->active_fingerprint->trust && context->active_fingerprint->trust[0]) {
			level = TRUST_PRIVATE;
		} else {
			level = TRUST_UNVERIFIED;
		}
	} else if (context && context->msgstate == OTRL_MSGSTATE_FINISHED) {
		level = TRUST_FINISHED;
	}

	return level;
}

/* Set verification of fingerprint */
void VerifyFingerprint(ConnContext *context, bool verify) {
	lib_cs_lock();
	otrl_context_set_trust(context->active_fingerprint, (verify)?"verified":NULL);
	otrl_privkey_write_fingerprints(otr_user_state, _T2A(g_fingerprint_store_filename));
	VerifyFingerprintMessage(context, verify);
}

void VerifyFingerprintMessage(ConnContext *context, bool verify) {
	MCONTACT hContact = (UINT_PTR)context->app_data;
	TCHAR msg[1024];

	mir_sntprintf(msg, (verify)?TranslateT(LANG_FINGERPRINT_VERIFIED):TranslateT(LANG_FINGERPRINT_NOT_VERIFIED), contact_get_nameT(hContact));
	ShowMessage(hContact, msg);
	SetEncryptionStatus(hContact, otr_context_get_trust(context));
}

/* Convert a 20-byte hash value to a 45-byte human-readable value */
void otrl_privkey_hash_to_humanT(TCHAR human[45], const unsigned char hash[20])
{
	int word, byte;
	TCHAR *p = human;

	for(word=0; word<5; ++word) {
	for(byte=0; byte<4; ++byte) {
		_stprintf(p, _T("%02X"), hash[word*4+byte]); //!!!!!!!!!!!!!!
		p += 2;
	}
	*(p++) = ' ';
	}
	/* Change that last ' ' to a '\0' */
	--p;
	*p = '\0';
}

char* contact_get_id(MCONTACT hContact, bool bNameOnError) {
	char* pszUniqueID = NULL;
	CONTACTINFO ci;
	memset(&ci, 0, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = hContact;
	ci.dwFlag = CNF_UNIQUEID;

	if (CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci) == 0)
	{
		if (ci.type == CNFT_ASCIIZ) {   
			pszUniqueID = (char*)ci.pszVal; // MS_CONTACT_GETCONTACTINFO uses mir_alloc
		} else if (ci.type == CNFT_DWORD)  {
			pszUniqueID = (char*)mir_alloc(15);
			if (pszUniqueID) 
				mir_snprintf(pszUniqueID, 15, ("%u"), ci.dVal);
		} else if (ci.type == CNFT_WORD)  {
			pszUniqueID = (char*)mir_alloc(15);
			if (pszUniqueID)
				mir_snprintf(pszUniqueID, 15, ("%u"), ci.wVal);
		} else if (ci.type == CNFT_BYTE)  {
			pszUniqueID = (char*)mir_alloc(15);
			if (pszUniqueID)
				mir_snprintf(pszUniqueID, 15, ("%u"), ci.bVal);
		}
	}
	if (!pszUniqueID && bNameOnError) {
		const TCHAR *name = pcli->pfnGetContactDisplayName(hContact, 0);
		if (name) pszUniqueID = mir_t2a(name);
	}
	return pszUniqueID;
}

__inline const TCHAR* contact_get_nameT(MCONTACT hContact) {
	return pcli->pfnGetContactDisplayName(hContact, 0);
}

TCHAR* ProtoGetNickname(const char* proto)
{
	CONTACTINFO ci = {sizeof(ci)};
	ci.dwFlag = CNF_TCHAR | CNF_NICK;
	ci.szProto = (char*)proto;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) {
		switch (ci.type) {
		case CNFT_ASCIIZ:
			return ci.pszVal;
		case CNFT_DWORD:
			mir_free(ci.pszVal);
			ci.pszVal=(TCHAR*)mir_alloc(12*sizeof(TCHAR)); // long can only have up to 11 characters (unsigned = 10)
			if(ci.pszVal)
				_ltot(ci.dVal, ci.pszVal, 10);
			return ci.pszVal;
		default:
			mir_free(ci.pszVal);
		}
	}
	return mir_tstrdup(_T(""));
}

void ShowPopup(const TCHAR* line1, const TCHAR* line2, int timeout, const MCONTACT hContact) {
	if(CallService(MS_SYSTEM_TERMINATED, 0, 0)) return;

	if ( !options.bHavePopups) {	
		TCHAR title[256];
		mir_sntprintf(title, _T("%s Message"), _T(MODULENAME));

		if(line1 && line2) {
			int size = int(mir_tstrlen(line1) + mir_tstrlen(line2) + 3);
			TCHAR *message = new TCHAR[size]; // newline and null terminator
			mir_sntprintf(message, size, _T("%s\r\n%s"), line1, line2);
			MessageBox( NULL, message, title, MB_OK | MB_ICONINFORMATION );
			delete[] message;
		} else if(line1) {
			MessageBox( NULL, line1, title, MB_OK | MB_ICONINFORMATION );
		} else if(line2) {
			MessageBox( NULL, line2, title, MB_OK | MB_ICONINFORMATION );
		}
		return;
	}

	POPUPDATAT ppd = {0};
	//memset((void *)&ppd, 0, sizeof(POPUPDATAT));

	ppd.lchContact = hContact;
	ppd.lchIcon = NULL;

	if(line1 && line2) {
		_tcsncpy( ppd.lptzContactName, line1, MAX_CONTACTNAME-1 );
		_tcsncpy( ppd.lptzText, line2, MAX_SECONDLINE-1 );
	} else if(line1)
		_tcsncpy( ppd.lptzText, line1, MAX_SECONDLINE-1 );
	else if(line2)
		_tcsncpy( ppd.lptzText, line2, MAX_SECONDLINE-1 );

	ppd.iSeconds = timeout;

	ppd.PluginWindowProc = NULL;
	ppd.PluginData = NULL;

	PUAddPopupT(&ppd);

}

void ShowWarning(TCHAR *msg) {
	TCHAR buffer[512];
	ErrorDisplay disp = options.err_method;
	// funny logic :) ... try to avoid message boxes
	// if want baloons but no balloons, try popups
	// if want popups but no popups, try baloons
	// if, after that, you want balloons but no balloons, revert to message boxes
	if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP; 
	if(disp == ED_POP && !options.bHavePopups) disp = ED_BAL;
	if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;

	mir_sntprintf(buffer, _T("%s Warning"), _T(MODULENAME));

	
	switch(disp) {
		case ED_POP:
			{
				int size = int(mir_tstrlen(msg) + 515);
				TCHAR *message = new TCHAR[size]; // newline and null terminator
				mir_sntprintf(message, size, _T("%s\r\n%s"), buffer, msg);
				PUShowMessageT(message, SM_WARNING);
				delete[] message;
			}
			break;
		case ED_MB:
			MessageBox(0, msg, buffer, MB_OK | MB_ICONWARNING);
			break;
		case ED_BAL:
			{
				MIRANDASYSTRAYNOTIFY sn = {0};
				sn.cbSize = sizeof(sn);
				sn.szProto= MODULENAME;
				sn.tszInfoTitle = buffer;
				sn.tszInfo = msg;

				sn.dwInfoFlags = NIIF_WARNING | NIIF_INTERN_UNICODE;

				sn.uTimeout = 10;

				CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
			}

			break;
	}
}

void ShowError(TCHAR *msg) {
	TCHAR buffer[512];
	ErrorDisplay disp = options.err_method;
	// funny logic :) ... try to avoid message boxes
	// if want baloons but no balloons, try popups
	// if want popups but no popups, try baloons
	// if, after that, you want balloons but no balloons, revert to message boxes
	if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP;
	if(disp == ED_POP && !options.bHavePopups) disp = ED_BAL;
	if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;

	mir_sntprintf(buffer, _T("%s Error"), _T(MODULENAME));


	TCHAR *message;
	switch(disp) {
		case ED_POP:
			{
				int size = int(mir_tstrlen(msg) + 515);
				message = new TCHAR[size]; // newline and null terminator
				mir_sntprintf(message, size, _T("%s\r\n%s"), buffer, msg);
				PUShowMessageT(message, SM_WARNING);
				delete[] message;
			}
			break;
		case ED_MB:
			MessageBox(0, msg, buffer, MB_OK | MB_ICONERROR);
			break;
		case ED_BAL:
			{
				MIRANDASYSTRAYNOTIFY sn = {0};
				sn.cbSize = sizeof(sn);
				sn.szProto = MODULENAME;
				sn.tszInfoTitle = buffer;
				sn.tszInfo = msg;

				sn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE;

				sn.uTimeout = 10;

				CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
			}

			break;
	}
}


void ShowPopupUtf(const char* line1, const char* line2, int timeout, const MCONTACT hContact) {
	TCHAR* l1 = (line1) ? mir_utf8decodeT(line1) : NULL;
	TCHAR* l2 = (line2) ? mir_utf8decodeT(line2) : NULL;
	ShowPopup(l1, l2, timeout, hContact);
	if (l1) mir_free(l1);
	if (l2) mir_free(l2);
}

void ShowWarningUtf(char* msg) {
	TCHAR* m = (msg) ? mir_utf8decodeT(msg) : NULL;
	ShowWarning(m);
	if (m) mir_free(m);
}
void ShowErrorUtf(char* msg) {
	TCHAR* m = (msg) ? mir_utf8decodeT(msg) : NULL;
	ShowError(m);
	if (m) mir_free(m);
}

void ShowMessageInline(const MCONTACT hContact, const TCHAR *msg) {
	TCHAR buff[1024];
	mir_sntprintf(buff, _T("%s%s"), _T(LANG_INLINE_PREFIX), msg);
	T2Utf utf(buff);

	PROTORECVEVENT pre = {0};
	pre.timestamp = time(0);
	pre.szMessage = utf;
	pre.flags = PREF_BYPASS_OTR;
	ProtoChainRecvMsg(hContact, &pre);	
}

void ShowMessageInlineUtf(const MCONTACT hContact, const char *msg) {
	char buff[1024];
	mir_snprintf(buff, "%s%s", LANG_INLINE_PREFIX, msg);

	PROTORECVEVENT pre = {0};
	pre.timestamp = time(0);
	pre.szMessage = buff;
	pre.flags = PREF_BYPASS_OTR;
	ProtoChainRecvMsg(hContact, &pre);
}

void ShowMessageUtf(const MCONTACT hContact, const char *msg) {
	if(options.msg_inline)
		ShowMessageInlineUtf(hContact, msg);
	if(options.msg_popup)
		ShowPopupUtf(Translate(LANG_OTR_INFO), msg, 0, hContact);
}

void ShowMessage(const MCONTACT hContact, const TCHAR *msg) {
	if(options.msg_inline)
		ShowMessageInline(hContact, msg);
	if(options.msg_popup)
		ShowPopup(TranslateT(LANG_OTR_INFO), msg, 0, hContact);
}

const TCHAR *policy_to_string(OtrlPolicy policy) {
	switch (policy) {
		case OTRL_POLICY_NEVER:
			return TranslateT(LANG_POLICY_NEVER);
		case OTRL_POLICY_OPPORTUNISTIC:
			return TranslateT(LANG_POLICY_OPP);
		case OTRL_POLICY_MANUAL:
		case OTRL_POLICY_MANUAL_MOD:
			return TranslateT(LANG_POLICY_MANUAL);
		case OTRL_POLICY_ALWAYS:
			return TranslateT(LANG_POLICY_ALWAYS);
		default:
			return TranslateT(LANG_POLICY_DEFAULT);
	}
}

OtrlPolicy policy_from_string(const TCHAR *polstring) {
	if (mir_tstrcmp(polstring, TranslateT(LANG_POLICY_NEVER)) == 0)
		return OTRL_POLICY_NEVER;
	else if (mir_tstrcmp(polstring, TranslateT(LANG_POLICY_OPP)) == 0)
		return OTRL_POLICY_OPPORTUNISTIC;
	else if (mir_tstrcmp(polstring, TranslateT(LANG_POLICY_MANUAL)) == 0)
		return OTRL_POLICY_MANUAL_MOD;
	else if (mir_tstrcmp(polstring, TranslateT(LANG_POLICY_ALWAYS)) == 0)
		return OTRL_POLICY_ALWAYS;
	else 
		return CONTACT_DEFAULT_POLICY;
}