/*
Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
Copyright (c) 2012-2013 Miranda NG Team
Copyright (c) 2006-2011 Boris Krasnovskiy.
Copyright (c) 2003-2005 George Hazan.
Copyright (c) 2002-2003 Richard Hughes (original version).
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, see .
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "m_proto_listeningto.h"
#include "m_folders.h"
#include "m_metacontacts.h"
#include "ezxml.h"
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////////////////
//	MSN error codes
#define ERR_SYNTAX_ERROR                 200
#define ERR_INVALID_PARAMETER            201
#define ERR_INVALID_USER                 205
#define ERR_FQDN_MISSING                 206
#define ERR_ALREADY_LOGIN                207
#define ERR_INVALID_USERNAME             208
#define ERR_INVALID_FRIENDLY_NAME        209
#define ERR_LIST_FULL                    210
#define ERR_ALREADY_THERE                215
#define ERR_NOT_ON_LIST                  216
#define ERR_NOT_ONLINE                   217
#define ERR_ALREADY_IN_THE_MODE          218
#define ERR_ALREADY_IN_OPPOSITE_LIST     219
#define ERR_CONTACT_LIST_FAILED          241
#define ERR_SWITCHBOARD_FAILED           280
#define ERR_NOTIFY_XFR_FAILED            281
#define ERR_REQUIRED_FIELDS_MISSING      300
#define ERR_NOT_LOGGED_IN                302
#define ERR_INTERNAL_SERVER              500
#define ERR_DB_SERVER                    501
#define ERR_LIST_UNAVAILABLE             508
#define ERR_FILE_OPERATION               510
#define ERR_MEMORY_ALLOC                 520
#define ERR_SERVER_BUSY                  600
#define ERR_SERVER_UNAVAILABLE           601
#define ERR_PEER_NS_DOWN                 602
#define ERR_DB_CONNECT                   603
#define ERR_SERVER_GOING_DOWN            604
#define ERR_CREATE_CONNECTION            707
#define ERR_INVALID_LOCALE               710
#define ERR_BLOCKING_WRITE               711
#define ERR_SESSION_OVERLOAD             712
#define ERR_USER_TOO_ACTIVE              713
#define ERR_TOO_MANY_SESSIONS            714
#define ERR_NOT_EXPECTED                 715
#define ERR_BAD_FRIEND_FILE              717
#define ERR_AUTHENTICATION_FAILED        911
#define ERR_NOT_ALLOWED_WHEN_OFFLINE     913
#define ERR_NOT_ACCEPTING_NEW_USERS      920
#define ERR_EMAIL_ADDRESS_NOT_VERIFIED   924
/////////////////////////////////////////////////////////////////////////////////////////
//	Global definitions
#define MSN_MAX_EMAIL_LEN        128
#define MSN_GUID_LEN              40
#define MSN_PACKETS_COMBINE         7
#define MSN_DEFAULT_PORT         1863
#define MSN_DEFAULT_GATEWAY_PORT   80
const char MSN_DEFAULT_LOGIN_SERVER[] = "messenger.hotmail.com";
const char MSN_DEFAULT_GATEWAY[] =      "gateway.messenger.hotmail.com";
const char MSN_USER_AGENT[] =           "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1)";
#define MSN_BLOCK        "/BlockCommand"
#define MSN_INVITE       "/InviteCommand"
#define MSN_NETMEETING   "/NetMeeting"
#define MSN_VIEW_PROFILE "/ViewProfile"
#define MS_GOTO_INBOX		"/GotoInbox"
#define MS_EDIT_PROFILE		"/EditProfile"
#define MS_EDIT_ALERTS		"/EditAlerts"
#define MS_SET_NICKNAME_UI  "/SetNicknameUI"
extern const char sttVoidUid[];
/////////////////////////////////////////////////////////////////////////////////////////
//	MSN plugin functions
struct CMsnProto;
#define	MSN_ALLOW_MSGBOX    1
#define	MSN_ALLOW_ENTER	    2
#define	MSN_HOTMAIL_POPUP   4
#define MSN_SHOW_ERROR      8
#define	MSN_ALERT_POPUP	    16
void        HtmlDecode(char* str);
char*       HtmlEncode(const char* str);
bool		txtParseParam (const char* szData, const char* presearch, const char* start, const char* finish, char* param, const int size);
void		stripBBCode(char* src);
void		stripColorCode(char* src);
void		parseWLID(char* wlid, char** net, char** email, char** inst);
char*		GetGlobalIp(void);
template  void UrlDecode(chartype* str);
void		__cdecl MSN_ConnectionProc(HANDLE hNewConnection, DWORD dwRemoteIP, void*);
char*		MSN_GetAvatarHash(char* szContext, char** pszUrl = NULL);
bool		MSN_MsgWndExist(HANDLE hContact);
#define		MSN_SendNickname(a) MSN_SendNicknameUtf(UTF8(a))
unsigned    MSN_GenRandom(void);
void        MSN_InitContactMenu(void);
void        MSN_RemoveContactMenus(void);
HANDLE      GetIconHandle(int iconId);
HICON       LoadIconEx(const char* name, bool big = false);
void        ReleaseIconEx(const char* name, bool big = false);
void        MsnInitIcons(void);
int         sttDivideWords(char* parBuffer, int parMinItems, char** parDest);
void		MSN_MakeDigest(const char* chl, char* dgst);
char*		getNewUuid(void);
TCHAR* EscapeChatTags(const TCHAR* pszText);
TCHAR* UnEscapeChatTags(TCHAR* str_in);
void   overrideStr(TCHAR*& dest, const TCHAR* src, bool unicode, const TCHAR* def = NULL);
char* arrayToHex(BYTE* data, size_t datasz);
inline unsigned short _htons(unsigned short s)
{
	return s>>8|s<<8;
}
inline unsigned long _htonl(unsigned long s)
{
	return s<<24|(s&0xff00)<<8|((s>>8)&0xff00)|s>>24;
}
inline unsigned __int64 _htonl64(unsigned __int64 s)
{
	return (unsigned __int64)_htonl(s & 0xffffffff) << 32 | _htonl(s >> 32);
}
/////////////////////////////////////////////////////////////////////////////////////////
// Popup interface
typedef struct _tag_PopupData
{
	unsigned flags;
	char* url;
	TCHAR* title;
	TCHAR* text;
	CMsnProto* proto;
} PopupData;
struct STRLIST : public LIST
{
	static int compare(const char* p1, const char* p2)
	{ return _stricmp(p1, p2); }
	STRLIST() : LIST(2, compare) {}
	~STRLIST() { destroy(); }
	void destroy( void )
	{
		for (int i=0; i < count; i++)
			mir_free(items[i]);
		List_Destroy((SortedList*)this);
	}
	int insertn(const char* p) { return insert(mir_strdup(p)); }
	int remove(int idx)
	{
		mir_free(items[idx]);
		return List_Remove((SortedList*)this, idx);
	}
	int remove(const char* p)
	{
		int idx;
		return  List_GetIndex((SortedList*)this, (char*)p, &idx) == 1 ? remove(idx) : -1;
	}
};
/////////////////////////////////////////////////////////////////////////////////////////
//	MIME headers processing
class MimeHeaders
{
public:
	MimeHeaders();
	MimeHeaders(unsigned);
	~MimeHeaders();
	void        clear(void);
	char*       decodeMailBody(char* msgBody);
	const char* find(const char* fieldName);
	char*       flipStr(const char* src, size_t len, char* dest);
	size_t      getLength(void);
	char*       readFromBuffer(char* src);
	char*       writeToBuffer(char* dest);
	void        addString(const char* name, const char* szValue, unsigned flags = 0);
	void        addLong(const char* name, long lValue, unsigned flags = 0);
	void        addULong(const char* name, unsigned lValue);
	void	    addBool(const char* name, bool lValue);
	const char* operator[](const char* fieldName) { return find(fieldName); }
	static wchar_t* decode(const char* val);
private:
	typedef struct tag_MimeHeader
	{
		const char* name;
		const char* value;
		unsigned flags;
	} MimeHeader;
	unsigned	mCount;
	unsigned	mAllocCount;
	MimeHeader* mVals;
	unsigned allocSlot(void);
};
/////////////////////////////////////////////////////////////////////////////////////////
//	File transfer helper
struct ThreadData;
struct HReadBuffer
{
	HReadBuffer(ThreadData* info, int iStart = 0);
	~HReadBuffer();
	BYTE* surelyRead(size_t parBytes);
	ThreadData* owner;
	BYTE*			buffer;
	size_t			totalDataSize;
	size_t			startOffset;
};
enum TInfoType
{
	SERVER_NOTIFICATION,
	SERVER_SWITCHBOARD,
	SERVER_FILETRANS,
	SERVER_P2P_DIRECT
};
struct filetransfer
{
	filetransfer(CMsnProto* prt);
	~filetransfer(void);
	void close(void);
	void complete(void);
	int  create(void);
	int openNext(void);
	CMsnProto* proto;
	PROTOFILETRANSFERSTATUS std;
	bool        bCanceled;		// flag to interrupt a transfer
	bool        bCompleted;		// was a FT ever completed?
	bool        bAccepted;		// was a FT ever completed?
	int			fileId;			// handle of file being transferring (r/w)
	HANDLE		hLockHandle;
	ThreadData  *info;
	TInfoType	tType;
	TInfoType	tTypeReq;
	time_t		ts;
	clock_t     nNotify;
	unsigned	cf;
	bool        p2p_waitack;    // wait for ack
	bool        p2p_isV2;       // P2P V2
	unsigned    p2p_sessionid;	// session id
	unsigned    p2p_acksessid;	// acknowledged session id
	unsigned    p2p_sendmsgid;  // send message id
	unsigned    p2p_byemsgid;   // bye message id
	unsigned    p2p_ackID;		// number of ack's state
	unsigned    p2p_appID;		// application id: 1 = avatar, 2 = file transfer
	unsigned    p2p_type;		// application id: 1 = avatar, 2 = file transfer, 3 = custom emoticon
	char*       p2p_branch;		// header Branch: field
	char*       p2p_callID;		// header Call-ID: field
	char*       p2p_dest;		// destination e-mail address
	char*       p2p_object;     // MSN object for a transfer
	//---- receiving a file
	char*       szInvcookie;	// cookie for receiving
	unsigned __int64 lstFilePtr;
};
struct directconnection
{
	directconnection(const char* CallID, const char* Wlid);
	~directconnection();
	char* calcHashedNonce(UUID* nonce);
	char* mNonceToText(void);
	char* mNonceToHash(void) { return calcHashedNonce(mNonce); }
	void  xNonceToBin(UUID* nonce);
	UUID* mNonce;
	char* xNonce;
	char* callId;
	char* wlid;
	time_t ts;
	bool useHashedNonce;
	bool bAccepted;
	CMsnProto* proto;
};
#pragma pack(1)
typedef struct _tag_HFileContext
{
	unsigned len;
	unsigned ver;
	unsigned __int64 dwSize;
	unsigned type;
	wchar_t wszFileName[MAX_PATH];
	char unknown[30];
	unsigned id;
	char unknown2[64];
} HFileContext;
struct P2PB_Header
{
	virtual char* parseMsg(char *buf) = 0;
	virtual char* createMsg(char *buf, const char* wlid, CMsnProto *ppro) = 0;
	virtual bool isV2Hdr(void) = 0;
	virtual void logHeader(CMsnProto *ppro) = 0;
};
struct P2P_Header : P2PB_Header
{
	unsigned          mSessionID;
	unsigned          mID;
	unsigned __int64  mOffset;
	unsigned __int64  mTotalSize;
	unsigned          mPacketLen;
	unsigned          mFlags;
	unsigned          mAckSessionID;
	unsigned          mAckUniqueID;
	unsigned __int64  mAckDataSize;
	P2P_Header() { memset(&mSessionID, 0, 48); }
	P2P_Header(char *buf) { parseMsg(buf); }
	char* parseMsg(char *buf)  { memcpy(&mSessionID, buf, 48); return buf + 48; }
	char* createMsg(char *buf, const char* wlid, CMsnProto *ppro);
	bool isV2Hdr(void) { return false; }
	void logHeader(CMsnProto *ppro);
} ;
struct P2PV2_Header : P2PB_Header
{
	unsigned          mSessionID;
	unsigned          mID;
	const char*       mCap;
	unsigned __int64  mRemSize;
	unsigned          mPacketLen;
	unsigned          mPacketNum;
	unsigned          mAckUniqueID;
	unsigned char     mOpCode;
	unsigned char     mTFCode;
	P2PV2_Header() { memset(&mSessionID, 0, ((char*)&mTFCode - (char*)&mSessionID) + sizeof(mTFCode)); }
	P2PV2_Header(char *buf) { parseMsg(buf); }
	char* parseMsg(char *buf);
	char* createMsg(char *buf, const char* wlid, CMsnProto *ppro);
	bool isV2Hdr(void) { return true; }
	void logHeader(CMsnProto *ppro);
};
#pragma pack()
bool p2p_IsDlFileOk(filetransfer* ft);
/////////////////////////////////////////////////////////////////////////////////////////
//	Thread handling functions and datatypes
#define MSG_DISABLE_HDR      1
#define MSG_REQUIRE_ACK      2
#define MSG_RTL              4
#define MSG_OFFLINE          8
struct CMsnProto;
typedef void (__cdecl CMsnProto::*MsnThreadFunc)(void*);
struct ThreadData
{
	ThreadData();
	~ThreadData();
	STRLIST			mJoinedContactsWLID;
	STRLIST			mJoinedIdentContactsWLID;
	char*			mInitialContactWLID;
	TInfoType		mType;            // thread type
	MsnThreadFunc	mFunc;            // thread entry point
	char			mServer[80];      // server name
	HANDLE			s;					// NetLib connection for the thread
	HANDLE			mIncomingBoundPort; // Netlib listen for the thread
	HANDLE			hWaitEvent;
	WORD			mIncomingPort;
	TCHAR			mChatID[10];
	bool			mIsMainThread;
	clock_t			mWaitPeriod;
	CMsnProto*		proto;
	//----| for gateways |----------------------------------------------------------------
	char			mSessionID[50]; // Gateway session ID
	char			mGatewayIP[80]; // Gateway IP address
	int				mGatewayTimeout;
	bool			sessionClosed;
	bool			termPending;
	bool			gatewayType;
	//----| for switchboard servers only |------------------------------------------------
	bool			firstMsgRecv;
	int				mCaller;
	char			mCookie[130];     // for switchboard servers only
	LONG			mTrid;            // current message ID
	UINT			mTimerId;         // typing notifications timer id
	//----| for file transfers only |-----------------------------------------------------
	filetransfer*	mMsnFtp;          // file transfer block
	bool            mBridgeInit;
	//----| internal data buffer |--------------------------------------------------------
	int				mBytesInData;     // bytes available in data buffer
	char			mData[8192];      // data buffer for connection
	//----| methods |---------------------------------------------------------------------
	void           applyGatewayData(HANDLE hConn, bool isPoll);
	void           getGatewayUrl(char* dest, int destlen, bool isPoll);
	void           processSessionData(const char* xMsgr, const char* xHost);
	void           startThread(MsnThreadFunc , CMsnProto *prt);
	int            send(const char data[], size_t datalen);
	int            recv(char* data, size_t datalen);
	void           resetTimeout(bool term = false);
	bool           isTimeout(void);
	void           sendTerminate(void);
	void           sendCaps(void);
	int            sendMessage(int msgType, const char* email, int netId, const char* msg, int parFlags);
	int            sendRawMessage(int msgType, const char* data, int datLen);
	int            sendPacket(const char* cmd, const char* fmt, ...);
	int            contactJoined(const char* email);
	int            contactLeft(const char* email);
	HANDLE         getContactHandle(void);
};
/////////////////////////////////////////////////////////////////////////////////////////
// MSN P2P session support
#define MSN_APPID_AVATAR		1
#define MSN_APPID_AVATAR2   	12
#define MSN_APPID_FILE			2
#define MSN_APPID_WEBCAM		4
#define MSN_APPID_MEDIA_SHARING	35
#define MSN_APPID_IMAGE			33
#define MSN_APPID_CUSTOMSMILEY  3
#define MSN_APPID_CUSTOMANIMATEDSMILEY  4
#define MSN_TYPEID_FTPREVIEW		0
#define MSN_TYPEID_FTNOPREVIEW		1
#define MSN_TYPEID_CUSTOMSMILEY		2
#define MSN_TYPEID_DISPLAYPICT		3
#define MSN_TYPEID_BKGNDSHARING		4
#define MSN_TYPEID_BKGNDIMG			5
#define MSN_TYPEID_WINK				8
inline bool IsChatHandle(HANDLE hContact) { return (INT_PTR)hContact < 0; }
/////////////////////////////////////////////////////////////////////////////////////////
//	Message queue
#define MSGQUE_RAW	1
struct MsgQueueEntry
{
	char*          wlid;
	char*          message;
	filetransfer*  ft;
	STRLIST*       cont;
	int            msgType;
	int            msgSize;
	int            seq;
	int            allocatedToThread;
	time_t         ts;
	int            flags;
};
/////////////////////////////////////////////////////////////////////////////////////////
//	Avatars' queue
struct AvatarQueueEntry
{
	HANDLE  hContact;
	char*   pszUrl;
	__forceinline AvatarQueueEntry(HANDLE _contact, LPCSTR _url) :
		hContact(_contact),
		pszUrl( mir_strdup(_url))
	{}
	__forceinline ~AvatarQueueEntry()
	{	mir_free(pszUrl);
	}
};
/////////////////////////////////////////////////////////////////////////////////////////
//	User lists
template< class T >  int CompareId(const T* p1, const T* p2)
{
	return _stricmp(p1->id, p2->id);
}
struct ServerGroupItem
{
	char* id;
	char* name; // in UTF8
};
struct MsnPlace
{
	char *id;
	unsigned cap1;
	unsigned cap2;
	unsigned p2pMsgId;
	unsigned short p2pPktNum;
	~MsnPlace() { mir_free(id); }
};
struct MsnContact
{
	char *email;
	char *invite;
	char *nick;
	HANDLE hContact;
	int list;
	int netId;
	int p2pMsgId;
	unsigned cap1;
	unsigned cap2;
	OBJLIST places;
	MsnContact() : places(1, CompareId) {}
	~MsnContact() { mir_free(email); mir_free(nick); mir_free(invite); }
};
#define cap_OnlineViaMobile                 0x00000001
#define cap_OnlineMSN8User                  0x00000002
#define cap_SupportsGifInk                  0x00000004
#define cap_SupportsIsfInk                  0x00000008
#define cap_WebCamDetected                  0x00000010
#define cap_SupportsChunking                0x00000020
#define cap_MobileEnabled                   0x00000040
#define cap_WebWatchEnabled                 0x00000080
#define cap_SupportsActivities              0x00000100
#define cap_OnlineViaWebIM                  0x00000200
#define cap_MobileDevice                    0x00000400
#define cap_OnlineViaTGW                    0x00000800
#define cap_HasSpace                        0x00001000
#define cap_IsMceUser                       0x00002000
#define cap_SupportsDirectIM                0x00004000
#define cap_SupportsWinks                   0x00008000
#define cap_SupportsSharedSearch            0x00010000
#define cap_IsBot                           0x00020000
#define cap_SupportsVoiceIM                 0x00040000
#define cap_SupportsSChannel                0x00080000
#define cap_SupportsSipInvite               0x00100000
#define cap_SupportsMultipartyMedia         0x00200000
#define cap_SupportsSDrive                  0x00400000
#define cap_SupportsPageModeMessaging       0x00800000
#define cap_HasOneCare                      0x01000000
#define cap_SupportsTurn                    0x02000000
#define cap_SupportsP2PBootstrap            0x04000000
#define cap_UsingAlias                      0x08000000
#define capex_IsSmsOnly                     0x00000001
#define capex_SupportsVoiceOverMsnp         0x00000002
#define capex_SupportsUucpSipStack          0x00000004
#define capex_SupportsApplicationMsg        0x00000008
#define capex_RTCVideoEnabled               0x00000010
#define capex_SupportsPeerToPeerV2          0x00000020
#define capex_IsAuthWebIMUser               0x00000040
#define capex_Supports1On1ViaGroup          0x00000080
#define capex_SupportsOfflineIM             0x00000100
#define capex_SupportsSharingVideo          0x00000200
#define capex_SupportsNudges                0x00000400
#define capex_CircleVoiceIMEnabled          0x00000800
#define capex_SharingEnabled                0x00001000
#define capex_MobileSuspendIMFanoutDisable  0x00002000
#define capex_SupportsP2PMixerRelay         0x00008000
#define capex_ConvWindowFileTransfer        0x00020000
#define capex_VideoCallSupports16x9         0x00040000
#define capex_SupportsP2PEnveloping         0x00080000
#define capex_YahooIMDisabled               0x00400000
#define capex_SIPTunnelVersion2             0x00800000
#define capex_VoiceClipSupportsWMAFormat    0x01000000
#define capex_VoiceClipSupportsCircleIM     0x02000000
#define capex_SupportsSocialNewsObjectTypes 0x04000000
#define capex_CustomEmoticonsCapable        0x08000000
#define capex_SupportsUTF8MoodMessages      0x10000000
#define capex_FTURNCapable                  0x20000000
#define capex_SupportsP4Activity            0x40000000
#define capex_SupportsChats                 0x80000000
#define NETID_UNKNOWN	0x0000
#define NETID_MSN		0x0001
#define NETID_LCS		0x0002
#define NETID_MOB		0x0004
#define NETID_MOBNET	0x0008
#define NETID_CIRCLE	0x0009
#define NETID_TMPCIRCLE	0x000A
#define NETID_CID		0x000B
#define NETID_CONNECT	0x000D
#define NETID_REMOTE	0x000E
#define NETID_SMTP		0x0010
#define NETID_YAHOO		0x0020
#define	LIST_FL         0x0001
#define	LIST_AL		    0x0002
#define	LIST_BL		    0x0004
#define	LIST_RL		    0x0008
#define LIST_PL		    0x0010
#define LIST_LL		    0x0080
#define	LIST_REMOVE     0x0100
#define	LIST_REMOVENH   0x0300
/////////////////////////////////////////////////////////////////////////////////////////
//	MSN plugin options
typedef struct _tag_MYOPTIONS
{
	bool		EnableSounds;
	bool		ShowErrorsAsPopups;
	bool		SlowSend;
	bool		ManageServer;
	char		szEmail[MSN_MAX_EMAIL_LEN];
	char		szMachineGuid[MSN_GUID_LEN];
	char		szMachineGuidP2P[MSN_GUID_LEN];
}
MYOPTIONS;
/////////////////////////////////////////////////////////////////////////////////////////
//	Windows error class
struct TWinErrorCode
{
	WINAPI	TWinErrorCode();
	WINAPI	~TWinErrorCode();
	char*		WINAPI getText();
	long		mErrorCode;
	char*		mErrorText;
};
/////////////////////////////////////////////////////////////////////////////////////////
//	External variables
#define MSN_NUM_MODES 9
const char msnProtChallenge[] = "C1BX{V4W}Q3*10SM";
const char msnProductID[] = "PROD0120PW!CCV9@";
const char msnAppID[] = "AAD9B99B-58E6-4F23-B975-D9EC1F9EC24A";
const char msnStoreAppId[] = "Messenger Client 9.0";
const char msnProductVer[] = "14.0.8117.0416";
const char msnProtID[] = "MSNP18";
extern	HINSTANCE	hInst;
extern	bool		msnHaveChatDll;
///////////////////////////////////////////////////////////////////////////////
// UTF8 encode helper
class UTFEncoder
{
private:
	char* m_body;
public:
	UTFEncoder(const char* pSrc) :
		m_body(mir_utf8encode(pSrc)) {}
	UTFEncoder(const wchar_t* pSrc) :
		m_body(mir_utf8encodeW(pSrc)) {}
	~UTFEncoder() {  mir_free(m_body);	}
	const char* str() const { return m_body; }
};
#define UTF8(A) UTFEncoder(A).str()
typedef enum _tag_ConEnum
{
	conUnknown,
	conDirect,
	conUnknownNAT,
	conIPRestrictNAT,
	conPortRestrictNAT,
	conSymmetricNAT,
	conFirewall,
	conISALike
} ConEnum;
#pragma pack(1)
typedef struct _tag_UDPProbePkt
{
	unsigned char  version;
	unsigned char  serviceCode;
	unsigned short clientPort;
	unsigned	   clientIP;
	unsigned short discardPort;
	unsigned short testPort;
	unsigned	   testIP;
	unsigned       trId;
} UDPProbePkt;
#pragma pack()
extern const char* conStr[];
typedef struct _tag_MyConnectionType
{
	unsigned intIP;
	unsigned extIP;
	ConEnum udpConType;
	ConEnum tcpConType;
	unsigned weight;
	bool upnpNAT;
	bool icf;
	const IN_ADDR GetMyExtIP(void) { return *((PIN_ADDR)&extIP); }
	const char* GetMyExtIPStr(void) { return inet_ntoa(GetMyExtIP()); }
	const char* GetMyUdpConStr(void) { return conStr[udpConType]; }
	void SetUdpCon(const char* str);
	void CalculateWeight(void);
} MyConnectionType;
struct chunkedmsg
{
	char* id;
	char* msg;
	size_t size;
	size_t recvsz;
	bool bychunk;
	chunkedmsg(const char* tid, const size_t totsz, const bool bychunk);
	~chunkedmsg();
	void add(const char* msg, size_t offset, size_t portion);
	bool get(char*& tmsg, size_t& tsize);
};
struct DeleteParam
{
	CMsnProto *proto;
	HANDLE hContact;
};
INT_PTR CALLBACK DlgDeleteContactUI(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
struct InviteChatParam
{
	TCHAR* id;
	HANDLE hContact;
	CMsnProto* ppro;
	InviteChatParam(const TCHAR* id, HANDLE hContact, CMsnProto* ppro)
		: id(mir_tstrdup(id)), hContact(hContact), ppro(ppro) {}
	~InviteChatParam()
	{ mir_free(id); }
};
INT_PTR CALLBACK DlgInviteToChat(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);