/*
 * $Id: proto.cpp 13497 2011-03-25 04:55:36Z borkra $
 *
 * myYahoo Miranda Plugin
 *
 * Authors: Gennady Feldman (aka Gena01)
 *          Laurent Marechal (aka Peorth)
 *
 * This code is under GPL and is based on AIM, MSN and Miranda source code.
 * I want to thank Robert Rainwater and George Hazan for their code and support
 * and for answering some of my questions during development of this plugin.
 */

#include "yahoo.h"

#include <win2k.h>

#include <m_idle.h>
#include <m_options.h>
#include <m_skin.h>
#include <m_userinfo.h>

#include "resource.h"
#include "file_transfer.h"

#ifdef _MSC_VER
	#pragma warning(disable:4355)
#endif

CYahooProto::CYahooProto( const char* aProtoName, const TCHAR* aUserName ) :
	m_bLoggedIn( FALSE ), 
	poll_loop( 0),
	m_chatrooms(3, ChatRoom::compare) 
{
	m_iVersion = 2;
	m_tszUserName = mir_tstrdup( aUserName );
	m_szModuleName = mir_strdup( aProtoName );

	m_startStatus = ID_STATUS_ONLINE;
	m_connections = NULL;
	m_connection_tags = 0;

	logoff_buddies();

	SkinAddNewSoundExT("mail", m_tszUserName, LPGENT("New E-mail available in Inbox"));

	LoadYahooServices();
	IconsInit();
	InitCustomFolders();
}

CYahooProto::~CYahooProto()
{
	if (m_bLoggedIn)
		logout();

	DebugLog("Logged out");

	DestroyHookableEvent(hYahooNudge);

	MenuUninit();
	
	m_chatrooms.destroy();
	mir_free( m_szModuleName );
	mir_free( m_tszUserName );

	FREE(m_startMsg);
	FREE(m_pw_token);

	Netlib_CloseHandle( m_hNetlibUser );
}

////////////////////////////////////////////////////////////////////////////////////////
// OnModulesLoadedEx - performs hook registration

int CYahooProto::OnModulesLoadedEx( WPARAM, LPARAM )
{
	YHookEvent( ME_USERINFO_INITIALISE, 		&CYahooProto::OnUserInfoInit );
	YHookEvent( ME_IDLE_CHANGED, 				&CYahooProto::OnIdleEvent);
	YHookEvent( ME_CLIST_PREBUILDCONTACTMENU, 	&CYahooProto::OnPrebuildContactMenu );

	TCHAR tModuleDescr[ 100 ];
	mir_sntprintf(tModuleDescr, SIZEOF(tModuleDescr), TranslateT("%s plugin connections"), m_tszUserName);

	NETLIBUSER nlu = {0};
	nlu.cbSize = sizeof(nlu);
#ifdef HTTP_GATEWAY
	nlu.flags = NUF_OUTGOING | NUF_HTTPGATEWAY| NUF_HTTPCONNS | NUF_TCHAR;
#else
  	nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR;
#endif
	nlu.szSettingsModule = m_szModuleName;
	nlu.ptszDescriptiveName = tModuleDescr;

#ifdef HTTP_GATEWAY
	// Here comes the Gateway Code!
	nlu.szHttpGatewayHello = NULL;
	nlu.szHttpGatewayUserAgent = "User-Agent: Mozilla/4.01 [en] (Win95; I)";
 	nlu.pfnHttpGatewayInit = YAHOO_httpGatewayInit;
	nlu.pfnHttpGatewayBegin = NULL;
	nlu.pfnHttpGatewayWrapSend = YAHOO_httpGatewayWrapSend;
	nlu.pfnHttpGatewayUnwrapRecv = YAHOO_httpGatewayUnwrapRecv;
#endif

	m_hNetlibUser = ( HANDLE )CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu );
	MenuContactInit();

	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// AddToList - adds a contact to the contact list

HANDLE CYahooProto::AddToList( int flags, PROTOSEARCHRESULT* psr )
{
	DebugLog("[YahooAddToList] Flags: %d", flags);

	if (!m_bLoggedIn) {
		DebugLog("[YahooAddToList] WARNING: WE ARE OFFLINE!");
		return 0;
	}

	if (psr == NULL || psr->cbSize != sizeof( PROTOSEARCHRESULT )) {
		DebugLog("[YahooAddToList] Empty data passed?");
		return 0;
	}

	char *id = psr->flags & PSR_UNICODE ? mir_utf8encodeW((wchar_t*)psr->id) : mir_utf8encode((char*)psr->id);
	HANDLE hContact = getbuddyH(id);
	if (hContact != NULL) {
		if (db_get_b(hContact, "CList", "NotOnList", 0)) {
			DebugLog("[YahooAddToList] Temporary Buddy:%s already on our buddy list", id);
			//return 0;
		} else {
			DebugLog("[YahooAddToList] Buddy:%s already on our buddy list", id);
			mir_free(id);
			return 0;
		}
	} else if (flags & PALF_TEMPORARY) { /* not on our list */
		DebugLog("[YahooAddToList] Adding Temporary Buddy:%s ", id);
	}

	int protocol = psr->reserved[0];
	DebugLog("Adding buddy:%s", id);
	hContact = add_buddy(id, id, protocol, flags);
	mir_free(id);
	return hContact;
}

HANDLE __cdecl CYahooProto::AddToListByEvent( int flags, int /*iContact*/, HANDLE hDbEvent )
{
	DebugLog("[YahooAddToListByEvent]");
	if ( !m_bLoggedIn )
		return 0;

	DBEVENTINFO dbei = { sizeof( dbei ) };
	if (( dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, (LPARAM)hDbEvent, 0)) == -1 ) {
		DebugLog("[YahooAddToListByEvent] ERROR: Can't get blob size.");
		return 0;
	}

	DebugLog("[YahooAddToListByEvent] Got blob size: %lu", dbei.cbBlob);
	dbei.pBlob = ( PBYTE )_alloca( dbei.cbBlob );
	if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hDbEvent, (LPARAM)&dbei )) {
		DebugLog("[YahooAddToListByEvent] ERROR: Can't get event.");
		return 0;
	}

	if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) {
		DebugLog("[YahooAddToListByEvent] ERROR: Not an authorization request.");
		return 0;
	}

	if ( strcmp( dbei.szModule, m_szModuleName )) {
		DebugLog("[YahooAddToListByEvent] ERROR: Not Yahoo protocol.");
		return 0;
	}

	HANDLE hContact = DbGetAuthEventContact(&dbei);
	if (hContact != NULL)
		DebugLog("Temp Buddy found at: %p ", hContact);
	else
		DebugLog("hContact NULL???");

	return hContact;
}

////////////////////////////////////////////////////////////////////////////////////////
// AuthAllow - processes the successful authorization

int CYahooProto::Authorize( HANDLE hdbe )
{
	DebugLog("[YahooAuthAllow]");
	if ( !m_bLoggedIn ) {
		DebugLog("[YahooAuthAllow] Not Logged In!");
		return 1;
	}

	DBEVENTINFO dbei = { sizeof(dbei) };
	if (( dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hdbe, 0)) == -1 )
		return 1;

	dbei.pBlob = ( PBYTE )_alloca( dbei.cbBlob );
	if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hdbe, (LPARAM)&dbei ))
		return 1;

	if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
		return 1;

	if ( strcmp(dbei.szModule, m_szModuleName))
		return 1;

	/* Need to remove the buddy from our Miranda Lists */
	HANDLE hContact = DbGetAuthEventContact(&dbei);
	if (hContact != NULL) {
		char *who = DBGetString(hContact, m_szModuleName, YAHOO_LOGINID);
		if (!who) return 0;

		char *myid = DBGetString(hContact, m_szModuleName, "MyIdentity");

		DebugLog("Accepting buddy:%s", who);
		accept(myid, who, GetWord(hContact, "yprotoid", 0));

		mir_free(myid);
		mir_free(who);
	}

	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// AuthDeny - handles the unsuccessful authorization

int CYahooProto::AuthDeny( HANDLE hdbe, const TCHAR* reason )
{
	DebugLog("[YahooAuthDeny]");
	if ( !m_bLoggedIn )
		return 1;

	DBEVENTINFO dbei = { sizeof( dbei ) };
	if (( dbei.cbBlob = CallService( MS_DB_EVENT_GETBLOBSIZE, ( WPARAM )hdbe, 0)) == -1 ) {
		DebugLog("[YahooAuthDeny] ERROR: Can't get blob size");
		return 1;
	}

	dbei.pBlob = ( PBYTE )alloca( dbei.cbBlob );
	if ( CallService( MS_DB_EVENT_GET, ( WPARAM )hdbe, (LPARAM)&dbei )) {
		DebugLog("YahooAuthDeny - Can't get db event!");
		return 1;
	}

	if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) {
		DebugLog("YahooAuthDeny - not Authorization event");
		return 1;
	}

	if ( strcmp( dbei.szModule, m_szModuleName )) {
		DebugLog("YahooAuthDeny - wrong module?");
		return 1;
	}

	/* Need to remove the buddy from our Miranda Lists */
	HANDLE hContact = DbGetAuthEventContact(&dbei);
	if (hContact != NULL) {
		char *who = DBGetString(hContact, m_szModuleName, YAHOO_LOGINID);
		if (!who) return 0;

		char *myid = DBGetString(hContact, m_szModuleName, "MyIdentity");
		char *u_reason = mir_utf8encodeT(reason);

		DebugLog("Rejecting buddy:%s msg: %s", who, u_reason);
		reject(myid, who, GetWord(hContact, "yprotoid", 0), u_reason);
		CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);

		mir_free(u_reason);
		mir_free(myid);
		mir_free(who);
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// PSR_AUTH

int __cdecl CYahooProto::AuthRecv(HANDLE hContact, PROTORECVEVENT* pre)
{
	DebugLog("[YahooRecvAuth] ");
	db_unset(hContact,"CList","Hidden");

	Proto_AuthRecv(m_szModuleName, pre);
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// PSS_AUTHREQUEST

int __cdecl CYahooProto::AuthRequest( HANDLE hContact, const TCHAR* msg )
{
	DebugLog("[YahooSendAuthRequest]");

	if (hContact && m_bLoggedIn) {
		AddBuddy(hContact, "miranda", msg);
		return 0; // Success
	}

	return 1; // Failure
}

////////////////////////////////////////////////////////////////////////////////////////
// ChangeInfo

HANDLE __cdecl CYahooProto::ChangeInfo( int /*iInfoType*/, void* )
{
	return NULL;
}

////////////////////////////////////////////////////////////////////////////////////////
// GetCaps - return protocol capabilities bits

DWORD_PTR __cdecl CYahooProto::GetCaps( int type, HANDLE /*hContact*/ )
{
	switch ( type ) {
	case PFLAGNUM_1:
		return PF1_IM  | PF1_ADDED | PF1_AUTHREQ | PF1_MODEMSGRECV | PF1_MODEMSGSEND |  PF1_BASICSEARCH |
			PF1_EXTSEARCH | PF1_FILESEND  | PF1_FILERECV| PF1_VISLIST | PF1_SERVERCLIST;

	case PFLAGNUM_2:
		return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_ONTHEPHONE |
			PF2_OUTTOLUNCH | PF2_INVISIBLE | PF2_LIGHTDND /*| PF2_HEAVYDND*/;

	case PFLAGNUM_3:
		return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_ONTHEPHONE |
			PF2_OUTTOLUNCH | PF2_LIGHTDND ;

	case PFLAGNUM_4:
		return PF4_FORCEAUTH | PF4_FORCEADDED | PF4_SUPPORTTYPING | PF4_SUPPORTIDLE
			|PF4_AVATARS | PF4_OFFLINEFILES | PF4_IMSENDUTF | PF4_IMSENDOFFLINE /* for Meta plugin*/;
	case PFLAG_UNIQUEIDTEXT:
		return (DWORD_PTR) Translate("ID");
	case PFLAG_UNIQUEIDSETTING:
		return (DWORD_PTR) YAHOO_LOGINID;
	case PFLAG_MAXLENOFMESSAGE:
		return 800; /* STUPID YAHOO!!! */
	default:
		return 0;
	}
}

////////////////////////////////////////////////////////////////////////////////////////
// GetIcon - loads an icon for the contact list

HICON __cdecl CYahooProto::GetIcon( int iconIndex )
{
	if (LOWORD(iconIndex) == PLI_PROTOCOL)
	{
		if (iconIndex & PLIF_ICOLIBHANDLE)
			return (HICON)GetIconHandle(IDI_YAHOO);

		bool big = (iconIndex & PLIF_SMALL) == 0;
		HICON hIcon = LoadIconEx("yahoo", big);

		if (iconIndex & PLIF_ICOLIB)
			return hIcon;

		hIcon = CopyIcon(hIcon);
		ReleaseIconEx("yahoo", big);
		return hIcon;
	}
	return NULL;
}

////////////////////////////////////////////////////////////////////////////////////////
// GetInfo - retrieves a contact info

void __cdecl CYahooProto::get_info_thread(HANDLE hContact)
{
	SleepEx(500, TRUE);
	ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
}

int __cdecl CYahooProto::GetInfo( HANDLE hContact, int /*infoType*/ )
{
	YForkThread(&CYahooProto::get_info_thread, hContact);
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// SearchByEmail - searches the contact by its e-mail

HANDLE __cdecl CYahooProto::SearchByEmail( const PROTOCHAR* email )
{
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// SearchByName - searches the contact by its first or last name, or by a nickname

HANDLE __cdecl CYahooProto::SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName )
{
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// RecvContacts

int __cdecl CYahooProto::RecvContacts( HANDLE /*hContact*/, PROTORECVEVENT* )
{
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// RecvFile

int __cdecl CYahooProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt )
{
	db_unset(hContact, "CList", "Hidden");

	return Proto_RecvFile(hContact, evt);
}

////////////////////////////////////////////////////////////////////////////////////////
// RecvUrl

int __cdecl CYahooProto::RecvUrl( HANDLE /*hContact*/, PROTORECVEVENT* )
{
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// SendContacts

int __cdecl CYahooProto::SendContacts( HANDLE /*hContact*/, int /*flags*/, int /*nContacts*/, HANDLE* /*hContactsList*/ )
{
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// SendUrl

int __cdecl CYahooProto::SendUrl( HANDLE /*hContact*/, int /*flags*/, const char* /*url*/ )
{
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// SetApparentMode - sets the visibility status

int __cdecl CYahooProto::SetApparentMode( HANDLE hContact, int mode )
{
	if (mode && mode != ID_STATUS_OFFLINE)
		return 1;

	int oldMode = GetWord(hContact, "ApparentMode", 0);
	if (mode != oldMode)
		SetWord(hContact, "ApparentMode", mode);
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// SetStatus - sets the protocol status

int __cdecl CYahooProto::SetStatus( int iNewStatus )
{
	LOG(("[SetStatus] New status %s", (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iNewStatus, 0)));

	if (iNewStatus == ID_STATUS_OFFLINE) {

		logout();

	} else if (!m_bLoggedIn) {
		DBVARIANT dbv;
		int err = 0;
		char errmsg[80];

		if (m_iStatus == ID_STATUS_CONNECTING)
			return 0;

		YAHOO_utils_logversion();

		/*
		* Load Yahoo ID from the database.
		*/
		if (!GetString(YAHOO_LOGINID, &dbv)) {
			if (lstrlenA(dbv.pszVal) > 0) {
				lstrcpynA(m_yahoo_id, dbv.pszVal, 255);
			} else
				err++;
			DBFreeVariant(&dbv);
		} else {
			ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID);
			err++;
		}

		if (err) {
			lstrcpynA(errmsg, Translate("Please enter your yahoo id in Options/Network/Yahoo"), 80);
		} else {
			if (!GetString(YAHOO_PASSWORD, &dbv)) {
				CallService(MS_DB_CRYPT_DECODESTRING, lstrlenA(dbv.pszVal) + 1, (LPARAM) dbv.pszVal);
				if (lstrlenA(dbv.pszVal) > 0) {
					lstrcpynA(m_password, dbv.pszVal, 255);
				} else
					err++;

				DBFreeVariant(&dbv);
			}  else  {
				ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
				err++;
			}

			if (err)
				lstrcpynA(errmsg, Translate("Please enter your yahoo password in Options/Network/Yahoo"), 80);
		}

		if (err != 0) {
			BroadcastStatus(ID_STATUS_OFFLINE);

			ShowError( TranslateT("Yahoo Login Error"), _A2T(errmsg));
			return 0;
		}

		if (iNewStatus == ID_STATUS_OFFLINE)
			iNewStatus = ID_STATUS_ONLINE;

		FREE(m_pw_token); // No Token yet.

		if (!GetString(YAHOO_PWTOKEN, &dbv)) {
			if (lstrlenA(dbv.pszVal) > 0) {
				m_pw_token = strdup(dbv.pszVal);
			}

			DBFreeVariant(&dbv);
		}

		//db_get_w(NULL, m_szModuleName, "StartupStatus", status);
		m_startStatus = iNewStatus;

		//reset the unread email count. We'll get a new packet since we are connecting.
		m_unreadMessages = 0;

		BroadcastStatus(ID_STATUS_CONNECTING);

		iNewStatus = (iNewStatus == ID_STATUS_INVISIBLE) ? YAHOO_STATUS_INVISIBLE: YAHOO_STATUS_AVAILABLE;
		YForkThread(&CYahooProto::server_main, (void *)iNewStatus);
	}
	else if (iNewStatus == ID_STATUS_INVISIBLE) { /* other normal away statuses are set via setaway */
		BroadcastStatus(iNewStatus);
		set_status(m_iStatus,NULL,(m_iStatus != ID_STATUS_ONLINE) ? 1 : 0);
	}
	else {
		/* clear out our message just in case, STUPID AA! */
		FREE(m_startMsg);

		/* now tell miranda that we are Online, don't tell Yahoo server yet though! */
		BroadcastStatus(iNewStatus);
	}

	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// GetAwayMsg - returns a contact's away message

void __cdecl CYahooProto::get_status_thread(HANDLE hContact)
{
	int l;
	DBVARIANT dbv;
	char *gm = NULL, *sm = NULL, *fm;

	Sleep( 150 );

	/* Check Yahoo Games Message */
	if (!GetString(hContact, "YGMsg", &dbv)) {
		gm = strdup(dbv.pszVal);

		DBFreeVariant( &dbv );
	}

	if (! DBGetContactSettingString(hContact, "CList", "StatusMsg", &dbv )) {
		if (lstrlenA(dbv.pszVal) >= 1)
			sm = strdup(dbv.pszVal);

		DBFreeVariant( &dbv );
	} else {
		WORD status = GetWord(hContact, "YStatus", YAHOO_STATUS_OFFLINE);
		sm = yahoo_status_code( yahoo_status( status ));
		if (sm) sm = strdup(sm); /* we need this to go global FREE later */
	}

	l = 0;
	if (gm)
		l += lstrlenA(gm) + 3;

	l += lstrlenA(sm) + 1;
	fm = (char *) malloc(l);

	fm[0] ='\0';
	if (gm && lstrlenA(gm) > 0) {
		/* BAH YAHOO SUCKS! WHAT A PAIN!
		find first carriage return add status message then add the rest */
		char *c = strchr(gm, '\r');

		if (c != NULL) {
			lstrcpynA(fm,gm, c - gm + 1);
			fm[c - gm + 1] = '\0';
		} else
			lstrcpyA(fm, gm);

		if (sm) {
			lstrcatA(fm, ": ");
			lstrcatA(fm, sm);
		}

		if (c != NULL)
			lstrcatA(fm, c);
	} else if (sm) {
		lstrcatA(fm, sm);
	}

	FREE(sm);

	SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, (LPARAM)( TCHAR* )_A2T(fm));
}

HANDLE __cdecl CYahooProto::GetAwayMsg( HANDLE hContact )
{
	DebugLog("[YahooGetAwayMessage] ");

	if (hContact && m_bLoggedIn) {
		if (GetWord(hContact, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE)
			return 0; /* user offline, what Status message? */

		YForkThread(&CYahooProto::get_status_thread, hContact);
		return (HANDLE)1; //Success
	}

	return 0; // Failure
}

////////////////////////////////////////////////////////////////////////////////////////
// PSR_AWAYMSG

int __cdecl CYahooProto::RecvAwayMsg( HANDLE /*hContact*/, int /*statusMode*/, PROTORECVEVENT* )
{
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// PSS_AWAYMSG

int __cdecl CYahooProto::SendAwayMsg( HANDLE /*hContact*/, HANDLE /*hProcess*/, const char* )
{
	return 1;
}

////////////////////////////////////////////////////////////////////////////////////////
// SetAwayMsg - sets the away status message

int __cdecl CYahooProto::SetAwayMsg( int status, const PROTOCHAR* msg )
{
	char *c = msg && msg[0] ? mir_utf8encodeT(msg) : NULL;

	DebugLog("[YahooSetAwayMessage] Status: %s, Msg: %s",(char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, 0), (char*) c);

    if (!m_bLoggedIn) {
		if (m_iStatus == ID_STATUS_OFFLINE) {
			DebugLog("[YahooSetAwayMessage] WARNING: WE ARE OFFLINE!");
			mir_free(c);
			return 1;
		} else {
			if (m_startMsg) free(m_startMsg);

			m_startMsg = c ? strdup(c) : NULL;

			mir_free(c);
			return 0;
		}
	}

	/* need to tell ALL plugins that we are changing status */
	BroadcastStatus(status);

	if (m_startMsg) free(m_startMsg);

	/* now decide what we tell the server */
	if (c != 0) {
		m_startMsg = strdup(c);
		if (status == ID_STATUS_ONLINE) {
			set_status(YAHOO_CUSTOM_STATUS, c, 0);
		} else if (status != ID_STATUS_INVISIBLE) {
			set_status(YAHOO_CUSTOM_STATUS, c, 1);
		}
    } else {
		set_status(status, NULL, 0);
		m_startMsg = NULL;
	}

	mir_free(c);
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////
// PS_GETMYAWAYMSG

INT_PTR __cdecl CYahooProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam)
{
	if (!m_bLoggedIn || ! m_startMsg)
		return 0;

	if (lParam & SGMA_UNICODE)  {
		return (INT_PTR) mir_utf8decodeW(m_startMsg);
	} else {
		return (INT_PTR) mir_utf8decodeA(m_startMsg);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
// UserIsTyping - sends a UTN notification

int __cdecl CYahooProto::UserIsTyping( HANDLE hContact, int type )
{
	if (!m_bLoggedIn)
		return 0;

	char *szProto = GetContactProto(hContact);
	if (szProto==NULL || strcmp(szProto, m_szModuleName))
		return 0;

	DBVARIANT dbv;
	if (!GetString(hContact, YAHOO_LOGINID, &dbv)) {
		if (type == PROTOTYPE_SELFTYPING_OFF || type == PROTOTYPE_SELFTYPING_ON) {
			sendtyping(dbv.pszVal, GetWord(hContact, "yprotoid", 0), type == PROTOTYPE_SELFTYPING_ON?1:0);
		}
		DBFreeVariant(&dbv);
	}
	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////
// OnEvent - maintain protocol events

int __cdecl CYahooProto::OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam )
{
	switch( eventType ) {
		case EV_PROTO_ONLOAD:    return OnModulesLoadedEx( 0, 0);
		//case EV_PROTO_ONEXIT:    return OnPreShutdown( 0, 0);
		case EV_PROTO_ONOPTIONS: return OnOptionsInit( wParam, lParam );

		case EV_PROTO_ONMENU:
			MenuMainInit();
			break;

		case EV_PROTO_ONRENAME:
			if ( mainMenuRoot ) {
				CLISTMENUITEM mi = { sizeof(mi) };
				mi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
				mi.ptszName = m_tszUserName;
				CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)mainMenuRoot, (LPARAM)&mi );
			}
			break;

		case EV_PROTO_ONCONTACTDELETED:
			return OnContactDeleted(wParam, lParam);

		case EV_PROTO_DBSETTINGSCHANGED:
			return OnSettingChanged(wParam, lParam);
	}
	return 1;
}

INT_PTR CALLBACK first_run_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_INITDIALOG:
		{
			TranslateDialogDefault(hwndDlg);

			CYahooProto* ppro = (CYahooProto*)lParam;
			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);

			DBVARIANT dbv;
			if ( !ppro->GetString(YAHOO_LOGINID, &dbv))
			{
				SetDlgItemTextA(hwndDlg, IDC_HANDLE, dbv.pszVal);
				DBFreeVariant(&dbv);
			}

			if ( !ppro->GetString(YAHOO_PASSWORD, &dbv))
			{
				CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM) dbv.pszVal);
				SetDlgItemTextA(hwndDlg, IDC_PASSWORD, dbv.pszVal);
				DBFreeVariant(&dbv);
			}

			SetButtonCheck( hwndDlg, IDC_YAHOO_JAPAN, ppro->GetByte("YahooJapan", 0));
			return TRUE;
		}

	case WM_COMMAND:
		if ( LOWORD( wParam ) == IDC_NEWYAHOOACCOUNTLINK ) {
			CallService( MS_UTILS_OPENURL,
							1,
							(( BYTE )IsDlgButtonChecked( hwndDlg, IDC_YAHOO_JAPAN ) == 1) ?
							(LPARAM) "http://edit.yahoo.co.jp/config/eval_register" :
							(LPARAM) "http://edit.yahoo.com/config/eval_register"
						);
			return TRUE;
		}

		if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus())
		{
			switch( LOWORD( wParam )) {
			case IDC_HANDLE:
			case IDC_PASSWORD:
			case IDC_YAHOO_JAPAN:
				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
			}
		}
		break;

	case WM_NOTIFY:
		if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY )
		{
			CYahooProto* ppro = (CYahooProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
			char str[128];
			DBVARIANT dbv;
			BOOL reconnectRequired = FALSE;

			GetDlgItemTextA(hwndDlg, IDC_HANDLE, str, sizeof(str));

			dbv.pszVal = NULL;

			if ( ppro->GetString( YAHOO_LOGINID, &dbv ) || lstrcmpA( str, dbv.pszVal ))
				reconnectRequired = TRUE;

			if ( dbv.pszVal != NULL)
				DBFreeVariant( &dbv );

			ppro->SetString(YAHOO_LOGINID, str);
			GetDlgItemTextA(hwndDlg, IDC_PASSWORD, str, sizeof(str));

			dbv.pszVal = NULL;
			if ( ppro->GetString( YAHOO_PASSWORD, &dbv ) || lstrcmpA( str, dbv.pszVal ))
				reconnectRequired = TRUE;
			if ( dbv.pszVal != NULL)
				DBFreeVariant( &dbv );

			if (reconnectRequired ) {
				db_unset(NULL, ppro->m_szModuleName, YAHOO_PWTOKEN);
			}

			CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), (LPARAM) str);
			ppro->SetString(YAHOO_PASSWORD, str);
			ppro->SetByte("YahooJapan", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_YAHOO_JAPAN ));

			if ( reconnectRequired && ppro->m_bLoggedIn )
				MessageBoxA( hwndDlg, Translate("The changes you have made require you to reconnect to the Yahoo network before they take effect"), Translate("YAHOO Options"), MB_OK );

			return TRUE;
		}
		break;
	}

	return FALSE;
}


INT_PTR CYahooProto::SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam)
{
	return (INT_PTR)CreateDialogParam (hInstance, MAKEINTRESOURCE( IDD_YAHOOACCOUNT ),
		 (HWND)lParam, first_run_dialog, (LPARAM)this );
}