From 3b55a62fdcb1f8222de3c2c8fbed530792c419a0 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Fri, 12 Oct 2012 14:53:57 +0000 Subject: GTalkExt, ICQ, IRC, Jabber: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1890 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/IRCG/src/MString.cpp | 201 +++ protocols/IRCG/src/MString.h | 2300 ++++++++++++++++++++++++++++++ protocols/IRCG/src/clist.cpp | 247 ++++ protocols/IRCG/src/commandmonitor.cpp | 2508 +++++++++++++++++++++++++++++++++ protocols/IRCG/src/commandmonitor.h | 22 + protocols/IRCG/src/input.cpp | 936 ++++++++++++ protocols/IRCG/src/irc.h | 725 ++++++++++ protocols/IRCG/src/irc_dlg.h | 329 +++++ protocols/IRCG/src/irclib.cpp | 1505 ++++++++++++++++++++ protocols/IRCG/src/irclib.h | 175 +++ protocols/IRCG/src/ircproto.cpp | 1076 ++++++++++++++ protocols/IRCG/src/main.cpp | 122 ++ protocols/IRCG/src/options.cpp | 1962 ++++++++++++++++++++++++++ protocols/IRCG/src/output.cpp | 158 +++ protocols/IRCG/src/resource.h | 253 ++++ protocols/IRCG/src/scripting.cpp | 265 ++++ protocols/IRCG/src/services.cpp | 1254 +++++++++++++++++ protocols/IRCG/src/tools.cpp | 905 ++++++++++++ protocols/IRCG/src/ui_utils.cpp | 1820 ++++++++++++++++++++++++ protocols/IRCG/src/ui_utils.h | 1108 +++++++++++++++ protocols/IRCG/src/userinfo.cpp | 224 +++ protocols/IRCG/src/version.h | 12 + protocols/IRCG/src/windows.cpp | 1406 ++++++++++++++++++ 23 files changed, 19513 insertions(+) create mode 100644 protocols/IRCG/src/MString.cpp create mode 100644 protocols/IRCG/src/MString.h create mode 100644 protocols/IRCG/src/clist.cpp create mode 100644 protocols/IRCG/src/commandmonitor.cpp create mode 100644 protocols/IRCG/src/commandmonitor.h create mode 100644 protocols/IRCG/src/input.cpp create mode 100644 protocols/IRCG/src/irc.h create mode 100644 protocols/IRCG/src/irc_dlg.h create mode 100644 protocols/IRCG/src/irclib.cpp create mode 100644 protocols/IRCG/src/irclib.h create mode 100644 protocols/IRCG/src/ircproto.cpp create mode 100644 protocols/IRCG/src/main.cpp create mode 100644 protocols/IRCG/src/options.cpp create mode 100644 protocols/IRCG/src/output.cpp create mode 100644 protocols/IRCG/src/resource.h create mode 100644 protocols/IRCG/src/scripting.cpp create mode 100644 protocols/IRCG/src/services.cpp create mode 100644 protocols/IRCG/src/tools.cpp create mode 100644 protocols/IRCG/src/ui_utils.cpp create mode 100644 protocols/IRCG/src/ui_utils.h create mode 100644 protocols/IRCG/src/userinfo.cpp create mode 100644 protocols/IRCG/src/version.h create mode 100644 protocols/IRCG/src/windows.cpp (limited to 'protocols/IRCG/src') diff --git a/protocols/IRCG/src/MString.cpp b/protocols/IRCG/src/MString.cpp new file mode 100644 index 0000000000..70016e427e --- /dev/null +++ b/protocols/IRCG/src/MString.cpp @@ -0,0 +1,201 @@ +#include "irc.h" +#include "MString.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +CNilMStringData CMBaseString::m_nil; + +CMStringData* CMBaseString::Allocate( int nChars, int nCharSize ) +{ + CMStringData* pData; + nChars++; // nil char + size_t nDataBytes = nCharSize * nChars; + size_t nTotalSize = nDataBytes + sizeof(CMStringData); + + pData = static_cast(malloc(nTotalSize)); + if (pData == NULL) + return NULL; + + pData->nRefs = 1; + pData->nAllocLength = nChars - 1; + pData->nDataLength = 0; + return pData; +} + +void CMBaseString::Free(CMStringData* pData) +{ + free(pData); +} + +CMStringData* CMBaseString::Realloc(CMStringData* pData, int nChars, int nCharSize) +{ + CMStringData* pNewData; + nChars++; // nil char + ULONG nDataBytes = nCharSize * nChars; + ULONG nTotalSize = nDataBytes + sizeof(CMStringData); + + pNewData = static_cast(realloc(pData, nTotalSize)); + if (pNewData == NULL) + return NULL; + + pNewData->nAllocLength = nChars - 1; + return pNewData; +} + +CMStringData* CMBaseString::GetNilString() +{ + m_nil.AddRef(); + return &m_nil; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CMStringData + +void* CMStringData::data() +{ + return (this + 1); +} + +void CMStringData::AddRef() +{ + InterlockedIncrement(&nRefs); +} + +bool CMStringData::IsLocked() const +{ + return nRefs < 0; +} + +bool CMStringData::IsShared() const +{ + return (nRefs > 1); +} + +void CMStringData::Lock() +{ + nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary + if ( nRefs == 0 ) + nRefs = -1; +} + +void CMStringData::Release() +{ + if (InterlockedDecrement(&nRefs) <= 0) + CMBaseString::Free(this); +} + +void CMStringData::Unlock() +{ + if (IsLocked()) + { + nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary + if (nRefs == 0) + nRefs = 1; + } +} + +CNilMStringData::CNilMStringData() +{ + nRefs = 2; // Never gets freed + nDataLength = 0; + nAllocLength = 0; + achNil[0] = 0; + achNil[1] = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ChTraitsCRT + +#if _MSC_VER < 1400 +static HINSTANCE hCrt = NULL; + +typedef int ( __cdecl *_vscprintf_func )( LPCSTR pszFormat, va_list args ); +static _vscprintf_func _vscprintf_ptr = NULL; + +typedef int ( __cdecl *_vscwprintf_func )( LPCWSTR pszFormat, va_list args ); +static _vscwprintf_func _vscwprintf_ptr = NULL; + +typedef int ( __cdecl *_vsnprintf_func )( char*, size_t, const char*, va_list ); +static _vsnprintf_func _vsnprintf_ptr = NULL; + +typedef int ( __cdecl *_vsnwprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); +static _vsnwprintf_func _vsnwprintf_ptr = NULL; + +typedef int ( __cdecl *vswprintf_func )( wchar_t *, size_t, const wchar_t *, va_list ); +static vswprintf_func vswprintf_ptr = NULL; + +typedef int ( __cdecl *vsprintf_func )( char*, size_t, const char*, va_list ); +static vsprintf_func vsprintf_ptr = NULL; + +static void checkCrt( void ) +{ + if ( hCrt == NULL ) { + hCrt = GetModuleHandleA( "msvcrt.dll" ); + _vscprintf_ptr = (_vscprintf_func)GetProcAddress( hCrt, "_vscprintf" ); + _vscwprintf_ptr = (_vscwprintf_func)GetProcAddress( hCrt, "_vscwprintf" ); + _vsnprintf_ptr = (_vsnprintf_func)GetProcAddress( hCrt, "_vsnprintf" ); + _vsnwprintf_ptr = (_vsnwprintf_func)GetProcAddress( hCrt, "_vsnwprintf" ); + vswprintf_ptr = (vswprintf_func)GetProcAddress( hCrt, "vswprintf" ); + vsprintf_ptr = (vsprintf_func)GetProcAddress( hCrt, "vsprintf" ); +} } +#endif + +int __stdcall ChTraitsCRT::GetFormattedLength( LPCWSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vscwprintf_ptr != NULL ) + return _vscwprintf_ptr( pszFormat, args ); + + WCHAR buf[ 4000 ]; + return vswprintf_ptr( buf, SIZEOF(buf), pszFormat, args ); + #else + return _vscwprintf( pszFormat, args ); + #endif +} + +int __stdcall ChTraitsCRT::Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vsnwprintf_ptr != NULL ) + return _vsnwprintf_ptr( pszBuffer, nLength, pszFormat, args ); + + return vswprintf_ptr( pszBuffer, nLength, pszFormat, args ); + #else + return _vsnwprintf( pszBuffer, nLength, pszFormat, args ); + #endif +} + +///////////////////////////////////////////////////////////////////////////////////////// +// ChTraitsCRT + +int __stdcall ChTraitsCRT::GetFormattedLength( LPCSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + if ( _vscprintf_ptr != NULL ) + return _vscprintf_ptr( pszFormat, args ); + + char buf[4000]; + return vsprintf_ptr( buf, sizeof(buf), pszFormat, args ); + #else + return _vscprintf( pszFormat, args ); + #endif +} + +int __stdcall ChTraitsCRT::Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ) +{ + #if _MSC_VER < 1400 + checkCrt(); + + return _vsnprintf( pszBuffer, nlength, pszFormat, args ); + #else + return vsprintf_s( pszBuffer, nlength, pszFormat, args ); + #endif +} + diff --git a/protocols/IRCG/src/MString.h b/protocols/IRCG/src/MString.h new file mode 100644 index 0000000000..7cc16ff4a3 --- /dev/null +++ b/protocols/IRCG/src/MString.h @@ -0,0 +1,2300 @@ +#pragma once + +#include +#include +#include + +#ifdef __MINGW32__ +#include + +__inline size_t strnlen(const char *string, size_t maxlen) +{ + const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} +__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) +{ + const wchar_t *end = wmemchr (string, L'\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} + +/* FIXME: This may be wrong assumption about _AtlGetConversionACP */ +#define _AtlGetConversionACP() CP_THREAD_ACP +/* FIXME: This is unsafe */ +#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) +/* FIXME: This is quite silly implementation of _mbsstr */ +#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) +#define __max(x,y) (((x)<(y))?(y):(x)) +#endif /* __MINGW32__ */ + +struct CMStringData +{ + int nDataLength; // Length of currently used data in XCHARs (not including terminating null) + int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) + long nRefs; // Reference count: negative == locked + // XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data + void* data(); + void AddRef(); + bool IsLocked() const; + bool IsShared() const; + void Lock(); + void Release(); + void Unlock(); +}; + +class CNilMStringData : public CMStringData +{ +public: + CNilMStringData(); + +public: + wchar_t achNil[2]; +}; + +template< typename BaseType = char > +class ChTraitsBase +{ +public: + typedef char XCHAR; + typedef LPSTR PXSTR; + typedef LPCSTR PCXSTR; + typedef wchar_t YCHAR; + typedef LPWSTR PYSTR; + typedef LPCWSTR PCYSTR; +}; + +template<> +class ChTraitsBase< wchar_t > +{ +public: + typedef wchar_t XCHAR; + typedef LPWSTR PXSTR; + typedef LPCWSTR PCXSTR; + typedef char YCHAR; + typedef LPSTR PYSTR; + typedef LPCSTR PCYSTR; +}; + +class CMBaseString +{ +public: + static CMStringData* Allocate(int nChars, int nCharSize); + static void Free(CMStringData* pData); + static CMStringData* Realloc(CMStringData* pData, int nChars, int nCharSize); + +protected: + static CMStringData* GetNilString(); + static CNilMStringData m_nil; +}; + +template< typename BaseType > +class CMSimpleStringT : public CMBaseString +{ +public: + typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; + typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; + typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; + typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; + typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; + typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; + +public: + explicit CMSimpleStringT() + { + CMStringData* pData = GetNilString(); + Attach(pData); + } + + CMSimpleStringT(const CMSimpleStringT& strSrc) + { + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pNewData = CloneData( pSrcData ); + Attach( pNewData ); + } + + CMSimpleStringT(PCXSTR pszSrc) + { + int nLength = StringLength( pszSrc ); + CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); + if (pData != NULL) + { + Attach( pData ); + SetLength( nLength ); + CopyChars( m_pszData, nLength, pszSrc, nLength ); + } + } + CMSimpleStringT(const XCHAR* pchSrc, int nLength) + { + CMStringData* pData = Allocate( nLength, sizeof( XCHAR )); + if ( pData != NULL ) + { + Attach( pData ); + SetLength( nLength ); + CopyChars( m_pszData, nLength, pchSrc, nLength ); + } + } + ~CMSimpleStringT() + { + CMStringData* pData = GetData(); + pData->Release(); + } + + operator CMSimpleStringT&() + { + return *(CMSimpleStringT*)this; + } + + CMSimpleStringT& operator=(const CMSimpleStringT& strSrc ) + { + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pOldData = GetData(); + if ( pSrcData != pOldData) + { + if ( pOldData->IsLocked()) + SetString( strSrc.GetString(), strSrc.GetLength()); + else + { + CMStringData* pNewData = CloneData( pSrcData ); + pOldData->Release(); + Attach( pNewData ); + } + } + + return *this; + } + + CMSimpleStringT& operator=(PCXSTR pszSrc) + { + SetString( pszSrc ); + return *this; + } + + CMSimpleStringT& operator+=( const CMSimpleStringT& strSrc ) + { + Append( strSrc ); + + return *this; + } + + CMSimpleStringT& operator+=( PCXSTR pszSrc ) + { + Append( pszSrc ); + + return *this; + } + CMSimpleStringT& operator+=( char ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + CMSimpleStringT& operator+=( unsigned char ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + CMSimpleStringT& operator+=( wchar_t ch ) + { + AppendChar(XCHAR(ch)); + + return *this; + } + + XCHAR operator[]( int iChar ) const + { + return m_pszData[iChar]; + } + + operator PCXSTR() const + { + return m_pszData; + } + + PCXSTR c_str() const + { + return m_pszData; + } + + void Append( PCXSTR pszSrc ) + { + Append( pszSrc, StringLength( pszSrc )); + } + void Append( PCXSTR pszSrc, int nLength ) + { + // See comment in SetString() about why we do this + UINT_PTR nOffset = pszSrc - GetString(); + + UINT nOldLength = GetLength(); + if (nOldLength < 0) + { + // protects from underflow + nOldLength = 0; + } + + //Make sure we don't read pass end of the terminating NULL + int nSrcLength = StringLength(pszSrc); + nLength = nLength > nSrcLength ? nSrcLength: nLength; + + int nNewLength = nOldLength+nLength; + PXSTR pszBuffer = GetBuffer( nNewLength ); + if ( nOffset <= nOldLength ) + { + pszSrc = pszBuffer+nOffset; + // No need to call CopyCharsOverlapped, since the destination is + // beyond the end of the original buffer + } + CopyChars( pszBuffer+nOldLength, nLength, pszSrc, nLength ); + ReleaseBufferSetLength( nNewLength ); + } + void AppendChar( XCHAR ch ) + { + UINT nOldLength = GetLength(); + int nNewLength = nOldLength+1; + PXSTR pszBuffer = GetBuffer( nNewLength ); + pszBuffer[nOldLength] = ch; + ReleaseBufferSetLength( nNewLength ); + } + void Append( const CMSimpleStringT& strSrc ) + { + Append( strSrc.GetString(), strSrc.GetLength()); + } + void Empty() + { + CMStringData* pOldData = GetData(); + if ( pOldData->nDataLength == 0 ) + return; + + if ( pOldData->IsLocked()) + { + // Don't reallocate a locked buffer that's shrinking + SetLength( 0 ); + } + else + { + pOldData->Release(); + CMStringData* pNewData = GetNilString(); + Attach( pNewData ); + } + } + void FreeExtra() + { + CMStringData* pOldData = GetData(); + int nLength = pOldData->nDataLength; + if ( pOldData->nAllocLength == nLength ) + return; + + if ( !pOldData->IsLocked()) // Don't reallocate a locked buffer that's shrinking + { + CMStringData* pNewData = Allocate( nLength, sizeof( XCHAR )); + if ( pNewData == NULL ) { + SetLength( nLength ); + return; + } + + CopyChars( PXSTR( pNewData->data()), nLength, PCXSTR( pOldData->data()), nLength ); + + pOldData->Release(); + Attach( pNewData ); + SetLength( nLength ); + } + } + + int GetAllocLength() const + { + return GetData()->nAllocLength; + } + XCHAR GetAt( int iChar ) const + { + return m_pszData[iChar]; + } + PXSTR GetBuffer() + { + CMStringData* pData = GetData(); + if ( pData->IsShared()) + Fork( pData->nDataLength ); + + return m_pszData; + } + PXSTR GetBuffer( int nMinBufferLength ) + { + return PrepareWrite( nMinBufferLength ); + } + PXSTR GetBufferSetLength( int nLength ) + { + PXSTR pszBuffer = GetBuffer( nLength ); + SetLength( nLength ); + + return pszBuffer; + } + int GetLength() const + { + return GetData()->nDataLength; + } + + PCXSTR GetString() const + { + return m_pszData; + } + bool IsEmpty() const + { + return GetLength() == 0; + } + PXSTR LockBuffer() + { + CMStringData* pData = GetData(); + if ( pData->IsShared()) + { + Fork( pData->nDataLength ); + pData = GetData(); // Do it again, because the fork might have changed it + } + pData->Lock(); + + return m_pszData; + } + void UnlockBuffer() + { + CMStringData* pData = GetData(); + pData->Unlock(); + } + void Preallocate( int nLength ) + { + PrepareWrite( nLength ); + } + void ReleaseBuffer( int nNewLength = -1 ) + { + if ( nNewLength == -1 ) + { + int nAlloc = GetData()->nAllocLength; + nNewLength = StringLengthN( m_pszData, nAlloc); + } + SetLength( nNewLength ); + } + void ReleaseBufferSetLength( int nNewLength ) + { + SetLength( nNewLength ); + } + void Truncate( int nNewLength ) + { + GetBuffer( nNewLength ); + ReleaseBufferSetLength( nNewLength ); + } + void SetAt( int iChar, XCHAR ch ) + { + int nLength = GetLength(); + PXSTR pszBuffer = GetBuffer(); + pszBuffer[iChar] = ch; + ReleaseBufferSetLength( nLength ); + + } + void SetString( PCXSTR pszSrc ) + { + SetString( pszSrc, StringLength( pszSrc )); + } + void SetString( PCXSTR pszSrc, int nLength ) + { + if ( nLength == 0 ) + { + Empty(); + } + else + { + + UINT nOldLength = GetLength(); + UINT_PTR nOffset = pszSrc - GetString(); + + PXSTR pszBuffer = GetBuffer( nLength ); + if ( nOffset <= nOldLength ) + { + CopyCharsOverlapped( pszBuffer, GetAllocLength(), + pszBuffer+nOffset, nLength ); + } + else + { + CopyChars( pszBuffer, GetAllocLength(), pszSrc, nLength ); + } + ReleaseBufferSetLength( nLength ); + } + } +public: + friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) + { + CMSimpleStringT s; + + Concatenate( s, str1, str1.GetLength(), str2, str2.GetLength()); + + return s; + } + + friend CMSimpleStringT __stdcall operator+(const CMSimpleStringT& str1, PCXSTR psz2) + { + CMSimpleStringT s; + + Concatenate( s, str1, str1.GetLength(), psz2, StringLength( psz2 )); + + return s; + } + + friend CMSimpleStringT __stdcall operator+(PCXSTR psz1, const CMSimpleStringT& str2) + { + CMSimpleStringT s; + + Concatenate( s, psz1, StringLength( psz1 ), str2, str2.GetLength()); + + return s; + } + + static void __stdcall CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); +#pragma warning (pop) + } + static void __stdcall CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars ) + { + #if _MSC_VER >= 1400 + memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); + #else + memcpy(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); + #endif + } + + static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); +#pragma warning (pop) + } + static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) + { + #if _MSC_VER >= 1400 + memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); + #else + memmove(pchDest, pchSrc, nDestLen * sizeof(XCHAR)); + #endif + } + static int __stdcall StringLength(const char* psz) + { + if (psz == NULL) + { + return(0); + } + return (int(strlen(psz))); + } + static int __stdcall StringLength(const wchar_t* psz) + { + if (psz == NULL) + return 0; + + return int(wcslen(psz)); + } + static int __stdcall StringLengthN(const char* psz, size_t sizeInXChar ) + { + if ( psz == NULL ) + return 0; + + return int( strnlen( psz, sizeInXChar )); + } + static int __stdcall StringLengthN(const wchar_t* psz, size_t sizeInXChar ) + { + if ( psz == NULL ) + return 0; + + return int( wcsnlen( psz, sizeInXChar )); + } +protected: + static void __stdcall Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) + { + int nNewLength = nLength1+nLength2; + PXSTR pszBuffer = strResult.GetBuffer(nNewLength); + CopyChars(pszBuffer, nLength1, psz1, nLength1 ); + CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); + strResult.ReleaseBufferSetLength(nNewLength); + } + // Implementation +private: + void Attach(CMStringData* pData) + { + m_pszData = static_cast(pData->data()); + } + void Fork(int nLength) + { + CMStringData* pOldData = GetData(); + int nOldLength = pOldData->nDataLength; + CMStringData* pNewData = Allocate(nLength, sizeof(XCHAR)); + if (pNewData != NULL) + { + int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength)+1; // Copy '\0' + CopyChars( PXSTR( pNewData->data()), nCharsToCopy, PCXSTR( pOldData->data()), nCharsToCopy ); + pNewData->nDataLength = nOldLength; + pOldData->Release(); + Attach(pNewData); + } + } + CMStringData* GetData() const + { + return (reinterpret_cast(m_pszData) - 1); + } + PXSTR PrepareWrite( int nLength ) + { + CMStringData* pOldData = GetData(); + int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false + int nTooShort = pOldData->nAllocLength-nLength; // nTooShort < 0 means true, >= 0 means false + if ((nShared | nTooShort) < 0 ) // If either sign bit is set (i.e. either is less than zero), we need to copy data + PrepareWrite2(nLength); + + return m_pszData; + } + void PrepareWrite2(int nLength) + { + CMStringData* pOldData = GetData(); + if (pOldData->nDataLength > nLength) + nLength = pOldData->nDataLength; + + if (pOldData->IsShared()) + { + Fork(nLength); + } + else if (pOldData->nAllocLength < nLength) + { + // Grow exponentially, until we hit 1K. + int nNewLength = pOldData->nAllocLength; + if ( nNewLength > 1024 ) + nNewLength += 1024; + else + nNewLength *= 2; + + if ( nNewLength < nLength ) + nNewLength = nLength; + + Reallocate( nNewLength ); + } + } + void Reallocate( int nLength ) + { + CMStringData* pOldData = GetData(); + if ( pOldData->nAllocLength >= nLength || nLength <= 0) + return; + + CMStringData* pNewData = Realloc( pOldData, nLength, sizeof( XCHAR )); + if ( pNewData != NULL ) + Attach( pNewData ); + } + + void SetLength( int nLength ) + { + GetData()->nDataLength = nLength; + m_pszData[nLength] = 0; + } + + static CMStringData* __stdcall CloneData(CMStringData* pData) + { + CMStringData* pNewData = NULL; + + if (!pData->IsLocked()) { + pNewData = pData; + pNewData->AddRef(); + } + + return pNewData; + } + +public : + // typedef CStrBufT CStrBuf; +private: + PXSTR m_pszData; +}; + + +template< typename _CharType = char > +class ChTraitsCRT : public ChTraitsBase< _CharType > +{ +public: + static char* __stdcall CharNext( const char* p ) + { + return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ))); + } + + static int __stdcall IsDigit( char ch ) + { + return _ismbcdigit( ch ); + } + + static int __stdcall IsSpace( char ch ) + { + return _ismbcspace( ch ); + } + + static int __stdcall StringCompare( LPCSTR pszA, LPCSTR pszB ) + { + return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) + { + return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCollate( LPCSTR pszA, LPCSTR pszB ) + { + return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static int __stdcall StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) + { + return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB )); + } + + static LPCSTR __stdcall StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) + { + return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ), + reinterpret_cast< const unsigned char* >( pszMatch ))); + } + + static LPSTR __stdcall StringFindString( LPSTR pszBlock, LPCSTR pszMatch ) + { + return const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch )); + } + + static LPCSTR __stdcall StringFindChar( LPCSTR pszBlock, char chMatch ) + { + return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch )); + } + + static LPCSTR __stdcall StringFindCharRev( LPCSTR psz, char ch ) + { + return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch )); + } + + static LPCSTR __stdcall StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) + { + return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ), + reinterpret_cast< const unsigned char* >( pszMatch ))); + } + + static int __stdcall StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) + { + return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); + } + + static int __stdcall StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) + { + return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet )); + } + + static LPSTR __stdcall StringUppercase( LPSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz )) ); +#pragma warning (pop) + } + + static LPSTR __stdcall StringLowercase( LPSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz )) ); +#pragma warning (pop) + } + + static LPSTR __stdcall StringUppercase( LPSTR psz, size_t size ) + { + #if _MSC_VER >= 1400 + _mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size); + #else + _mbsupr(reinterpret_cast< unsigned char* >( psz )); + #endif + return psz; + } + + static LPSTR __stdcall StringLowercase( LPSTR psz, size_t size ) + { + #if _MSC_VER >= 1400 + _mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size ); + #else + _mbslwr(reinterpret_cast< unsigned char* >( psz )); + #endif + return psz; + } + + static LPSTR __stdcall StringReverse( LPSTR psz ) + { + return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz )) ); + } + + static int __stdcall GetFormattedLength( LPCSTR pszFormat, va_list args ); + + static int __stdcall Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return vsprintf( pszBuffer, pszFormat, args ); +#pragma warning (pop) + + } + + static int __stdcall Format( LPSTR pszBuffer, size_t nlength, LPCSTR pszFormat, va_list args ); + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) + { + // Returns required buffer length in XCHARs + return int( strlen( pszSrc )); + } + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) + { + (void)pszSrc; + // Returns required buffer length in XCHARs + return nLength; + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSource ) + { + // Returns required buffer length in XCHARs + return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1; + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSource, int nLength ) + { + // Returns required buffer length in XCHARs + return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL ); + } + + static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1 ) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in XCHARs + memcpy_s( pszDest, nDestLength*sizeof( char ), + pszSrc, nSrcLength*sizeof( char )); + } + + static void __stdcall ConvertToBaseType( LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) + { + // nLen is in XCHARs + ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL ); + } + + static void ConvertToOem( _CharType* pstrString) + { + BOOL fSuccess=::CharToOemA(pstrString, pstrString); + } + + static void ConvertToAnsi( _CharType* pstrString) + { + BOOL fSuccess=::OemToCharA(pstrString, pstrString); + } + + static void ConvertToOem( _CharType* pstrString, size_t size) + { + if(size>UINT_MAX) + { + return; + } + DWORD dwSize=static_cast(size); + BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize); + } + + static void ConvertToAnsi( _CharType* pstrString, size_t size) + { + if(size>UINT_MAX) + return; + + DWORD dwSize=static_cast(size); + BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize); + } + + static void __stdcall FloodCharacters( char ch, int nLength, char* pch ) + { + // nLength is in XCHARs + memset( pch, ch, nLength ); + } + + static BSTR __stdcall AllocSysString( const char* pchData, int nDataLength ) + { + int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); + BSTR bstr = ::SysAllocStringLen( NULL, nLen ); + if ( bstr != NULL ) + ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, bstr, nLen ); + + return bstr; + } + + static BOOL __stdcall ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) + { + int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL ); + BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen ); + if ( bSuccess ) + ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen ); + + return bSuccess; + } + + static int __stdcall SafeStringLen( LPCSTR psz ) + { + // returns length in bytes + return (psz != NULL) ? int( strlen( psz )) : 0; + } + + static int __stdcall SafeStringLen( LPCWSTR psz ) + { + // returns length in wchar_ts + return (psz != NULL) ? int( wcslen( psz )) : 0; + } + + static int __stdcall GetCharLen( const wchar_t* pch ) + { + // returns char length + return 1; + } + + static int __stdcall GetCharLen( const char* pch ) + { + // returns char length + return int( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); + } + + static DWORD __stdcall GetEnvironmentVariable( LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize ) + { + return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize ); + } +}; + +// specialization for wchar_t +template<> +class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > +{ + static DWORD __stdcall _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) + { + return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize ); + } + +public: + static LPWSTR __stdcall CharNext( LPCWSTR psz ) + { + return const_cast< LPWSTR >( psz+1 ); + } + + static int __stdcall IsDigit( wchar_t ch ) + { + return iswdigit( static_cast(ch)); + } + + static int __stdcall IsSpace( wchar_t ch ) + { + return iswspace( static_cast(ch)); + } + + static int __stdcall StringCompare( LPCWSTR pszA, LPCWSTR pszB ) + { + return wcscmp( pszA, pszB ); + } + + static int __stdcall StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) + { + return _wcsicmp( pszA, pszB ); + } + + static int __stdcall StringCollate( LPCWSTR pszA, LPCWSTR pszB ) + { + return wcscoll( pszA, pszB ); + } + + static int __stdcall StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) + { + return _wcsicoll( pszA, pszB ); + } + + static LPCWSTR __stdcall StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) + { + return wcsstr( pszBlock, pszMatch ); + } + + static LPWSTR __stdcall StringFindString( LPWSTR pszBlock, LPCWSTR pszMatch ) + { + return const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch )); + } + + static LPCWSTR __stdcall StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) + { + return wcschr( pszBlock, chMatch ); + } + + static LPCWSTR __stdcall StringFindCharRev( LPCWSTR psz, wchar_t ch ) + { + return wcsrchr( psz, ch ); + } + + static LPCWSTR __stdcall StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) + { + return wcspbrk( pszBlock, pszMatch ); + } + + static int __stdcall StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) + { + return (int)wcsspn( pszBlock, pszSet ); + } + + static int __stdcall StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) + { + return (int)wcscspn( pszBlock, pszSet ); + } + + static LPWSTR __stdcall StringUppercase( LPWSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return _wcsupr( psz ); +#pragma warning (pop) + } + + static LPWSTR __stdcall StringLowercase( LPWSTR psz ) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return _wcslwr( psz ); +#pragma warning (pop) + } + + static LPWSTR __stdcall StringUppercase( LPWSTR psz, size_t ) + { + return _wcsupr( psz ); + } + + static LPWSTR __stdcall StringLowercase( LPWSTR psz, size_t ) + { + return _wcslwr( psz ); + } + + static LPWSTR __stdcall StringReverse( LPWSTR psz ) + { + return _wcsrev( psz ); + } + + static int __stdcall GetFormattedLength( LPCWSTR pszFormat, va_list args); + + static int __stdcall Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) + { +#pragma warning (push) +#pragma warning(disable : 4996) + return vswprintf( pszBuffer, pszFormat, args ); +#pragma warning (pop) + } + + static int __stdcall Format( LPWSTR pszBuffer, size_t nLength, LPCWSTR pszFormat, va_list args); + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc ) + { + // Returns required buffer size in wchar_ts + return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, -1, NULL, 0 )-1; + } + + static int __stdcall GetBaseTypeLength( LPCSTR pszSrc, int nLength ) + { + // Returns required buffer size in wchar_ts + return ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nLength, NULL, 0 ); + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc ) + { + // Returns required buffer size in wchar_ts + return (int)wcslen( pszSrc ); + } + + static int __stdcall GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) + { + (void)pszSrc; + // Returns required buffer size in wchar_ts + return nLength; + } + + static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) + { + // nLen is in wchar_ts + ::MultiByteToWideChar( CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength ); + } + + static void __stdcall ConvertToBaseType( LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1 ) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in wchar_ts + #if _MSC_VER >= 1400 + wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); + #else + wmemcpy(pszDest, pszSrc, nDestLength); + #endif + } + + static void __stdcall FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) + { + // nLength is in XCHARs + for ( int i = 0; i < nLength; i++ ) + { + psz[i] = ch; + } + } + + static BSTR __stdcall AllocSysString( const wchar_t* pchData, int nDataLength ) + { + return ::SysAllocStringLen( pchData, nDataLength ); + } + + static BOOL __stdcall ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) + { + return ::SysReAllocStringLen( pbstr, pchData, nDataLength ); + } + + static int __stdcall SafeStringLen( LPCSTR psz ) + { + // returns length in bytes + return (psz != NULL) ? (int)strlen( psz ) : 0; + } + + static int __stdcall SafeStringLen( LPCWSTR psz ) + { + // returns length in wchar_ts + return (psz != NULL) ? (int)wcslen( psz ) : 0; + } + + static int __stdcall GetCharLen( const wchar_t* pch ) + { + (void)pch; + // returns char length + return 1; + } + + static int __stdcall GetCharLen( const char* pch ) + { + // returns char length + return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch )) ); + } + + static DWORD __stdcall GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) + { + return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize ); + } + + static void __stdcall ConvertToOem( LPWSTR /*psz*/ ) + { + } + + static void __stdcall ConvertToAnsi( LPWSTR /*psz*/ ) + { + } + + static void __stdcall ConvertToOem( LPWSTR /*psz*/, size_t ) + { + } + + static void __stdcall ConvertToAnsi( LPWSTR /*psz*/, size_t ) + { + } +}; + +template< typename BaseType, class StringTraits > +class CMStringT : public CMSimpleStringT< BaseType > +{ +public: + typedef CMSimpleStringT< BaseType> CThisSimpleString; + typedef typename CThisSimpleString::XCHAR XCHAR; + typedef typename CThisSimpleString::PXSTR PXSTR; + typedef typename CThisSimpleString::PCXSTR PCXSTR; + typedef typename CThisSimpleString::YCHAR YCHAR; + typedef typename CThisSimpleString::PYSTR PYSTR; + typedef typename CThisSimpleString::PCYSTR PCYSTR; + +public: + CMStringT() : CThisSimpleString() + { + } + + static void __stdcall Construct( CMStringT* pString ) + { + new( pString ) CMStringT; + } + + // Copy constructor + CMStringT( const CMStringT& strSrc ) : + CThisSimpleString( strSrc ) + { + } + + CMStringT( const XCHAR* pszSrc ) : + CThisSimpleString() + { + // nDestLength is in XCHARs + *this = pszSrc; + } + + CMStringT( const YCHAR* pszSrc ) : + CThisSimpleString() + { + *this = pszSrc; + } + + + CMStringT( const unsigned char* pszSrc ) : + CThisSimpleString() + { + *this = reinterpret_cast< const char* >( pszSrc ); + } + + CMStringT( char ch, int nLength = 1 ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer ); + this->ReleaseBufferSetLength( nLength ); + } + } + + CMStringT( wchar_t ch, int nLength = 1 ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + //Convert ch to the BaseType + wchar_t pszCh[2] = { ch , 0 }; + int nBaseTypeCharLen = 1; + + if(ch != L'\0') + { + nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); + } + + XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; + StringTraits::ConvertToBaseType( buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1 ); + //Allocate enough characters in String and flood (replicate) with the (converted character)*nLength + PXSTR pszBuffer = this->GetBuffer( nLength*nBaseTypeCharLen ); + if (nBaseTypeCharLen == 1) + { //Optimization for a common case - wide char translates to 1 ansi/wide char. + StringTraits::FloodCharacters( buffBaseTypeChar[0], nLength, pszBuffer ); + } else + { + XCHAR* p=pszBuffer; + for (int i=0 ; i < nLength ;++i) + { + for (int j=0 ; j < nBaseTypeCharLen ;++j) + { + *p=buffBaseTypeChar[j]; + ++p; + } + } + } + this->ReleaseBufferSetLength( nLength*nBaseTypeCharLen ); + delete [] buffBaseTypeChar; + } + } + + CMStringT( const XCHAR* pch, int nLength ) : + CThisSimpleString( pch, nLength ) + { + } + + CMStringT( const YCHAR* pch, int nLength ) : + CThisSimpleString() + { + if ( nLength > 0 ) + { + int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength ); + PXSTR pszBuffer = this->GetBuffer( nDestLength ); + StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength ); + this->ReleaseBufferSetLength( nDestLength ); + } + } + + // Destructor + ~CMStringT() + { + } + + // Assignment operators + CMStringT& operator=( const CMStringT& strSrc ) + { + CThisSimpleString::operator=( strSrc ); + + return *this; + } + + CMStringT& operator=( PCXSTR pszSrc ) + { + CThisSimpleString::operator=( pszSrc ); + + return *this; + } + + CMStringT& operator=( PCYSTR pszSrc ) + { + // nDestLength is in XCHARs + int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0; + if ( nDestLength > 0 ) + { + PXSTR pszBuffer = this->GetBuffer( nDestLength ); + StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc); + this->ReleaseBufferSetLength( nDestLength ); + } + else + { + this->Empty(); + } + + return *this; + } + + CMStringT& operator=( const unsigned char* pszSrc ) + { + return operator=( reinterpret_cast< const char* >( pszSrc )); + } + + CMStringT& operator=( char ch ) + { + char ach[2] = { ch, 0 }; + + return operator=( ach ); + } + + CMStringT& operator=( wchar_t ch ) + { + wchar_t ach[2] = { ch, 0 }; + + return operator=( ach ); + } + +// CMStringT& operator=( const VARIANT& var ); + + CMStringT& operator+=( const CMStringT& str ) + { + CThisSimpleString::operator+=( str ); + return *this; + } + + CMStringT& operator+=( const CThisSimpleString& str ) + { + CThisSimpleString::operator+=( str ); + return *this; + } + + CMStringT& operator+=( PCXSTR pszSrc ) + { + CThisSimpleString::operator+=( pszSrc ); + return *this; + } +// template< int t_nSize > +// CMStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc ) +// { +// CThisSimpleString::operator+=( strSrc ); +// +// return *this; +// } + CMStringT& operator+=( PCYSTR pszSrc ) + { + CMStringT str( pszSrc ); + + return operator+=( str ); + } + + CMStringT& operator+=( char ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + CMStringT& operator+=( unsigned char ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + CMStringT& operator+=( wchar_t ch ) + { + CThisSimpleString::operator+=( ch ); + + return *this; + } + + // Comparison + + int Compare( PCXSTR psz ) const + { + return StringTraits::StringCompare( this->GetString(), psz ); + } + + int CompareNoCase( PCXSTR psz ) const + { + return StringTraits::StringCompareIgnore( this->GetString(), psz ); + } + + int Collate( PCXSTR psz ) const + { + return StringTraits::StringCollate( this->GetString(), psz ); + } + + int CollateNoCase( PCXSTR psz ) const + { + return StringTraits::StringCollateIgnore( this->GetString(), psz ); + } + + // Advanced manipulation + + // Delete 'nCount' characters, starting at index 'iIndex' + int Delete( int iIndex, int nCount = 1 ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( nCount < 0 ) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount + iIndex > nLength ) + { + nCount = nLength-iIndex; + } + if ( nCount > 0 ) + { + int nNewLength = nLength-nCount; + int nXCHARsToCopy = nLength-(iIndex+nCount)+1; + PXSTR pszBuffer = this->GetBuffer(); + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex, nXCHARsToCopy*sizeof( XCHAR ), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR )); + #endif + this->ReleaseBufferSetLength( nNewLength ); + } + + return this->GetLength(); + } + + // Insert character 'ch' before index 'iIndex' + int Insert( int iIndex, XCHAR ch ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( iIndex > this->GetLength()) + iIndex = this->GetLength(); + + int nNewLength = this->GetLength()+1; + + PXSTR pszBuffer = this->GetBuffer( nNewLength ); + + // move existing bytes down + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR )); + #endif + pszBuffer[iIndex] = ch; + + this->ReleaseBufferSetLength( nNewLength ); + return nNewLength; + } + + // Insert string 'psz' before index 'iIndex' + int Insert( int iIndex, PCXSTR psz ) + { + if ( iIndex < 0 ) + iIndex = 0; + + if ( iIndex > this->GetLength()) + { + iIndex = this->GetLength(); + } + + // nInsertLength and nNewLength are in XCHARs + int nInsertLength = StringTraits::SafeStringLen( psz ); + int nNewLength = this->GetLength(); + if ( nInsertLength > 0 ) + { + nNewLength += nInsertLength; + + PXSTR pszBuffer = this->GetBuffer( nNewLength ); + // move existing bytes down + #if _MSC_VER >= 1400 + memmove_s( pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); + memcpy_s( pszBuffer+iIndex, nInsertLength*sizeof( XCHAR ), psz, nInsertLength*sizeof( XCHAR )); + #else + memmove( pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR )); + memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR )); + #endif + this->ReleaseBufferSetLength( nNewLength ); + } + + return nNewLength; + } + + // Replace all occurrences of character 'chOld' with character 'chNew' + int Replace( XCHAR chOld, XCHAR chNew ) + { + int nCount = 0; + + // short-circuit the nop case + if ( chOld != chNew ) + { + // otherwise modify each character that matches in the string + bool bCopied = false; + PXSTR pszBuffer = const_cast< PXSTR >( this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). + + int nLength = this->GetLength(); + int iChar = 0; + while( iChar < nLength ) + { + // replace instances of the specified character only + if ( pszBuffer[iChar] == chOld ) + { + if ( !bCopied ) + { + bCopied = true; + pszBuffer = this->GetBuffer( nLength ); + } + pszBuffer[iChar] = chNew; + nCount++; + } + iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer ); + } + if ( bCopied ) + { + this->ReleaseBufferSetLength( nLength ); + } + } + + return nCount; + } + + // Replace all occurrences of string 'pszOld' with string 'pszNew' + int Replace( PCXSTR pszOld, PCXSTR pszNew ) + { + // can't have empty or NULL lpszOld + + // nSourceLen is in XCHARs + int nSourceLen = StringTraits::SafeStringLen( pszOld ); + if ( nSourceLen == 0 ) + return 0; + // nReplacementLen is in XCHARs + int nReplacementLen = StringTraits::SafeStringLen( pszNew ); + + // loop once to figure out the size of the result string + int nCount = 0; + { + PCXSTR pszStart = this->GetString(); + PCXSTR pszEnd = pszStart+this->GetLength(); + while( pszStart < pszEnd ) + { + PCXSTR pszTarget; + while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL) + { + nCount++; + pszStart = pszTarget+nSourceLen; + } + pszStart += StringTraits::SafeStringLen( pszStart )+1; + } + } + + // if any changes were made, make them + if ( nCount > 0 ) + { + // if the buffer is too small, just + // allocate a new buffer (slow but sure) + int nOldLength = this->GetLength(); + int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; + + PXSTR pszBuffer = this->GetBuffer( __max( nNewLength, nOldLength )); + + PXSTR pszStart = pszBuffer; + PXSTR pszEnd = pszStart+nOldLength; + + // loop again to actually do the work + while( pszStart < pszEnd ) + { + PXSTR pszTarget; + while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld )) != NULL ) + { + int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); + memmove_s( pszTarget+nReplacementLen, nBalance*sizeof( XCHAR ), + pszTarget+nSourceLen, nBalance*sizeof( XCHAR )); + memcpy_s( pszTarget, nReplacementLen*sizeof( XCHAR ), + pszNew, nReplacementLen*sizeof( XCHAR )); + pszStart = pszTarget+nReplacementLen; + pszTarget[nReplacementLen+nBalance] = 0; + nOldLength += (nReplacementLen-nSourceLen); + } + pszStart += StringTraits::SafeStringLen( pszStart )+1; + } + this->ReleaseBufferSetLength( nNewLength ); + } + + return nCount; + } + + // Remove all occurrences of character 'chRemove' + int Remove( XCHAR chRemove ) + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + + PXSTR pszSource = pszBuffer; + PXSTR pszDest = pszBuffer; + PXSTR pszEnd = pszBuffer+nLength; + + while( pszSource < pszEnd ) + { + PXSTR pszNewSource = StringTraits::CharNext( pszSource ); + if ( *pszSource != chRemove ) + { + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + size_t NewSourceGap = (pszNewSource-pszSource); + PXSTR pszNewDest = pszDest + NewSourceGap; + size_t i = 0; + for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) + { + *pszDest = *pszSource; + pszSource++; + pszDest++; + } + } + pszSource = pszNewSource; + } + *pszDest = 0; + int nCount = int( pszSource-pszDest ); + this->ReleaseBufferSetLength( nLength-nCount ); + + return nCount; + } + + CMStringT Tokenize( PCXSTR pszTokens, int& iStart ) const + { + if ( (pszTokens == NULL) || (*pszTokens == (XCHAR)0)) + { + if (iStart < this->GetLength()) + return CMStringT( this->GetString()+iStart ); + } + else + { + PCXSTR pszPlace = this->GetString()+iStart; + PCXSTR pszEnd = this->GetString()+this->GetLength(); + if ( pszPlace < pszEnd ) + { + int nIncluding = StringTraits::StringSpanIncluding( pszPlace, pszTokens ); + + if ( (pszPlace+nIncluding) < pszEnd ) + { + pszPlace += nIncluding; + int nExcluding = StringTraits::StringSpanExcluding( pszPlace, pszTokens ); + + int iFrom = iStart+nIncluding; + int nUntil = nExcluding; + iStart = iFrom+nUntil+1; + + return Mid( iFrom, nUntil ); + } + } + } + + // return empty string, done tokenizing + iStart = -1; + + return CMStringT(); + } + + // find routines + + // Find the first occurrence of character 'ch', starting at index 'iStart' + int Find( XCHAR ch, int iStart = 0 ) const + { + // nLength is in XCHARs + int nLength = this->GetLength(); + if ( iStart < 0 || iStart >= nLength) + return -1; + + // find first single character + PCXSTR psz = StringTraits::StringFindChar( this->GetString()+iStart, ch ); + + // return -1 if not found and index otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // look for a specific sub-string + + // Find the first occurrence of string 'pszSub', starting at index 'iStart' + int Find( PCXSTR pszSub, int iStart = 0 ) const + { + // iStart is in XCHARs + if(pszSub == NULL) + return -1; + + // nLength is in XCHARs + int nLength = this->GetLength(); + if ( iStart < 0 || iStart > nLength ) + return -1; + + // find first matching substring + PCXSTR psz = StringTraits::StringFindString( this->GetString()+iStart, pszSub ); + + // return -1 for not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // Find the first occurrence of any of the characters in string 'pszCharSet' + int FindOneOf( PCXSTR pszCharSet ) const + { + PCXSTR psz = StringTraits::StringScanSet( this->GetString(), pszCharSet ); + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // Find the last occurrence of character 'ch' + int ReverseFind( XCHAR ch ) const + { + // find last single character + PCXSTR psz = StringTraits::StringFindCharRev( this->GetString(), ch ); + + // return -1 if not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int( psz-this->GetString()); + } + + // manipulation + + // Convert the string to uppercase + CMStringT& MakeUpper() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringUppercase( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // Convert the string to lowercase + CMStringT& MakeLower() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringLowercase( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // Reverse the string + CMStringT& MakeReverse() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::StringReverse( pszBuffer ); + this->ReleaseBufferSetLength( nLength ); + + return *this; + } + + // trimming + + // Remove all trailing whitespace + CMStringT& TrimRight() + { + // find beginning of trailing spaces by starting + // at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( StringTraits::IsSpace( *psz )) + { + if ( pszLast == NULL ) + pszLast = psz; + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at trailing space start + int iLast = int( pszLast-this->GetString()); + + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all leading whitespace + CMStringT& TrimLeft() + { + // find first non-space character + + PCXSTR psz = this->GetString(); + + while( StringTraits::IsSpace( *psz )) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Remove all leading and trailing whitespace + CMStringT& Trim() + { + return TrimRight().TrimLeft(); + } + + // Remove all leading and trailing occurrences of character 'chTarget' + CMStringT& Trim( XCHAR chTarget ) + { + return TrimRight( chTarget ).TrimLeft( chTarget ); + } + + // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' + CMStringT& Trim( PCXSTR pszTargets ) + { + return TrimRight( pszTargets ).TrimLeft( pszTargets ); + } + + // trimming anything (either side) + + // Remove all trailing occurrences of character 'chTarget' + CMStringT& TrimRight( XCHAR chTarget ) + { + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( *psz == chTarget ) + { + if ( pszLast == NULL ) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at left-most matching character + int iLast = int( pszLast-this->GetString()); + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all trailing occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimRight( PCXSTR pszTargets ) + { + // if we're not trimming anything, we're not doing any work + if ( (pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } + + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; + + while( *psz != 0 ) + { + if ( StringTraits::StringFindChar( pszTargets, *psz ) != NULL ) + { + if ( pszLast == NULL ) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext( psz ); + } + + if ( pszLast != NULL ) + { + // truncate at left-most matching character + int iLast = int( pszLast-this->GetString()); + this->Truncate( iLast ); + } + + return *this; + } + + // Remove all leading occurrences of character 'chTarget' + CMStringT& TrimLeft( XCHAR chTarget ) + { + // find first non-matching character + PCXSTR psz = this->GetString(); + + while( chTarget == *psz ) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Remove all leading occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimLeft( PCXSTR pszTargets ) + { + // if we're not trimming anything, we're not doing any work + if ( (pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } + + PCXSTR psz = this->GetString(); + while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL)) + { + psz = StringTraits::CharNext( psz ); + } + + if ( psz != this->GetString()) + { + // fix up data and length + int iFirst = int( psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer( this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s( pszBuffer, (this->GetLength()+1)*sizeof( XCHAR ), + psz, (nDataLength+1)*sizeof( XCHAR )); + this->ReleaseBufferSetLength( nDataLength ); + } + + return *this; + } + + // Convert the string to the OEM character set + void AnsiToOem() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::ConvertToOem( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + } + + // Convert the string to the ANSI character set + void OemToAnsi() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::ConvertToAnsi( pszBuffer, nLength+1 ); + this->ReleaseBufferSetLength( nLength ); + } + + // Very simple sub-string extraction + + // Return the substring starting at index 'iFirst' + CMStringT Mid( int iFirst ) const + { + return Mid( iFirst, this->GetLength()-iFirst ); + } + + // Return the substring starting at index 'iFirst', with length 'nCount' + CMStringT Mid( int iFirst, int nCount ) const + { + // nCount is in XCHARs + + // out-of-bounds requests return sensible things + if (iFirst < 0) + iFirst = 0; + if (nCount < 0) + nCount = 0; + + if ( (iFirst + nCount) > this->GetLength()) + nCount = this->GetLength()-iFirst; + + if ( iFirst > this->GetLength()) + nCount = 0; + + // optimize case of returning entire string + if ( (iFirst == 0) && ((iFirst+nCount) == this->GetLength())) + return *this; + + return CMStringT( this->GetString()+iFirst, nCount ); + } + + // Return the substring consisting of the rightmost 'nCount' characters + CMStringT Right( int nCount ) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount >= nLength ) + { + return *this; + } + + return CMStringT( this->GetString()+nLength-nCount, nCount ); + } + + // Return the substring consisting of the leftmost 'nCount' characters + CMStringT Left( int nCount ) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if ( nCount >= nLength ) + return *this; + + return CMStringT( this->GetString(), nCount ); + } + + // Return the substring consisting of the leftmost characters in the set 'pszCharSet' + CMStringT SpanIncluding( PCXSTR pszCharSet ) const + { + return Left( StringTraits::StringSpanIncluding( this->GetString(), pszCharSet )); + } + + // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' + CMStringT SpanExcluding( PCXSTR pszCharSet ) const + { + return Left( StringTraits::StringSpanExcluding( this->GetString(), pszCharSet )); + } + + // Format data using format string 'pszFormat' + void Format( PCXSTR pszFormat, ... ); + + // Append formatted data using format string 'pszFormat' + void AppendFormat( PCXSTR pszFormat, ... ); + + void AppendFormatV( PCXSTR pszFormat, va_list args ) + { + int nCurrentLength = this->GetLength(); + int nAppendLength = StringTraits::GetFormattedLength( pszFormat, args ); + PXSTR pszBuffer = this->GetBuffer( nCurrentLength+nAppendLength ); + StringTraits::Format( pszBuffer+nCurrentLength, + nAppendLength+1, pszFormat, args ); + this->ReleaseBufferSetLength( nCurrentLength+nAppendLength ); + } + + void FormatV( PCXSTR pszFormat, va_list args ) + { + int nLength = StringTraits::GetFormattedLength( pszFormat, args ); + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::Format( pszBuffer, nLength+1, pszFormat, args ); + this->ReleaseBufferSetLength( nLength ); + } + + // OLE BSTR support + + // Allocate a BSTR containing a copy of the string + BSTR AllocSysString() const + { + BSTR bstrResult = StringTraits::AllocSysString( this->GetString(), this->GetLength()); + return bstrResult; + } + + BSTR SetSysString( BSTR* pbstr ) const + { + StringTraits::ReAllocSysString( this->GetString(), pbstr, this->GetLength()); + return *pbstr; + } + + // Set the string to the value of environment variable 'pszVar' + BOOL GetEnvironmentVariable( PCXSTR pszVar ) + { + ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 ); + BOOL bRetVal = FALSE; + + if ( nLength == 0 ) + { + this->Empty(); + } + else + { + PXSTR pszBuffer = this->GetBuffer( nLength ); + StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength ); + this->ReleaseBuffer(); + bRetVal = TRUE; + } + + return bRetVal; + } + + // Load the string from resource 'nID' + BOOL LoadString( UINT nID ) + { + HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID ); + if ( hInst == NULL ) + return FALSE; + + return LoadString( hInst, nID ); + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, const CMStringT& str2 ) + { + CMStringT strResult; + + Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, PCXSTR psz2 ) + { + CMStringT strResult; + + Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 )); + + return strResult; + } + + friend CMStringT __stdcall operator+( PCXSTR psz1, const CMStringT& str2 ) + { + CMStringT strResult; + + Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, wchar_t ch2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch2 ); + + Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); + + return strResult; + } + + friend CMStringT __stdcall operator+( const CMStringT& str1, char ch2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch2 ); + + Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 ); + + return strResult; + } + + friend CMStringT __stdcall operator+( wchar_t ch1, const CMStringT& str2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch1 ); + + Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+( char ch1, const CMStringT& str2 ) + { + CMStringT strResult; + XCHAR chTemp = XCHAR( ch1 ); + + Concatenate( strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend bool __stdcall operator==( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) == 0; + } + + friend bool __stdcall operator==( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) == 0; + } + + friend bool __stdcall operator==( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) == 0; + } + + friend bool __stdcall operator==( const CMStringT& str1, PCYSTR psz2 ) + { + CMStringT str2( psz2 ); + + return str1 == str2; + } + + friend bool __stdcall operator==( PCYSTR psz1, const CMStringT& str2 ) + { + CMStringT str1( psz1 ); + + return str1 == str2; + } + + friend bool __stdcall operator!=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) != 0; + } + + friend bool __stdcall operator!=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) != 0; + } + + friend bool __stdcall operator!=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) != 0; + } + + friend bool __stdcall operator!=( const CMStringT& str1, PCYSTR psz2 ) + { + CMStringT str2( psz2 ); + + return str1 != str2; + } + + friend bool __stdcall operator!=( PCYSTR psz1, const CMStringT& str2 ) + { + CMStringT str1( psz1 ); + + return str1 != str2; + } + + friend bool __stdcall operator<( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) < 0; + } + + friend bool __stdcall operator<( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) < 0; + } + + friend bool __stdcall operator<( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) > 0; + } + + friend bool __stdcall operator>( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) > 0; + } + + friend bool __stdcall operator>( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) > 0; + } + + friend bool __stdcall operator>( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) < 0; + } + + friend bool __stdcall operator<=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) <= 0; + } + + friend bool __stdcall operator<=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) <= 0; + } + + friend bool __stdcall operator<=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) >= 0; + } + + friend bool __stdcall operator>=( const CMStringT& str1, const CMStringT& str2 ) + { + return str1.Compare( str2 ) >= 0; + } + + friend bool __stdcall operator>=( const CMStringT& str1, PCXSTR psz2 ) + { + return str1.Compare( psz2 ) >= 0; + } + + friend bool __stdcall operator>=( PCXSTR psz1, const CMStringT& str2 ) + { + return str2.Compare( psz1 ) <= 0; + } + + friend bool __stdcall operator==( XCHAR ch1, const CMStringT& str2 ) + { + return (str2.GetLength() == 1) && (str2[0] == ch1); + } + + friend bool __stdcall operator==( const CMStringT& str1, XCHAR ch2 ) + { + return (str1.GetLength() == 1) && (str1[0] == ch2); + } + + friend bool __stdcall operator!=( XCHAR ch1, const CMStringT& str2 ) + { + return (str2.GetLength() != 1) || (str2[0] != ch1); + } + + friend bool __stdcall operator!=( const CMStringT& str1, XCHAR ch2 ) + { + return (str1.GetLength() != 1) || (str1[0] != ch2); + } +}; + +template< typename BaseType, class StringTraits > +inline void CMStringT::Format(PCXSTR pszFormat, ... ) +{ + va_list argList; + va_start( argList, pszFormat ); + FormatV( pszFormat, argList ); + va_end( argList ); +} + +template< typename BaseType, class StringTraits > +inline void CMStringT::AppendFormat(PCXSTR pszFormat, ... ) +{ + va_list argList; + va_start( argList, pszFormat ); + AppendFormatV( pszFormat, argList ); + va_end( argList ); +} + +typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; +typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; +typedef CMStringT< TCHAR, ChTraitsCRT< TCHAR > > CMString; diff --git a/protocols/IRCG/src/clist.cpp b/protocols/IRCG/src/clist.cpp new file mode 100644 index 0000000000..94bb460db9 --- /dev/null +++ b/protocols/IRCG/src/clist.cpp @@ -0,0 +1,247 @@ + +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +BOOL CIrcProto::CList_AddDCCChat(const CMString& name, const CMString& hostmask, unsigned long adr, int port) +{ + HANDLE hContact; + HANDLE hc; + TCHAR szNick[256]; + char szService[256]; + bool bFlag = false; + + CONTACT usertemp = { (TCHAR*)name.c_str(), NULL, NULL, false, false, true}; + hc = CList_FindContact( &usertemp ); + if ( hc && DBGetContactSettingByte( hc, "CList", "NotOnList", 0) == 0 + && DBGetContactSettingByte(hc,"CList", "Hidden", 0) == 0) + { + bFlag = true; + } + + CMString contactname = name; contactname += _T(DCCSTRING); + + CONTACT user = { (TCHAR*)contactname.c_str(), NULL, NULL, false, false, true}; + hContact = CList_AddContact(&user, false, false); + setByte(hContact, "DCC", 1); + + DCCINFO* pdci = new DCCINFO; + pdci->sHostmask = hostmask; + pdci->hContact = hContact; + pdci->dwAdr = (DWORD) adr; + pdci->iPort = port; + pdci->iType = DCC_CHAT; + pdci->bSender = false; + pdci->sContactName = name; + + if ( m_DCCChatAccept == 3 || m_DCCChatAccept == 2 && bFlag ) { + CDccSession* dcc = new CDccSession( this, pdci ); + + CDccSession* olddcc = FindDCCSession(hContact); + if ( olddcc ) + olddcc->Disconnect(); + + AddDCCSession(hContact, dcc); + dcc->Connect(); + if (getByte( "MirVerAutoRequest", 1)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), name.c_str()); + } + else { + CLISTEVENT cle = {0}; + cle.cbSize = sizeof(cle); + cle.hContact = (HANDLE)hContact; + cle.hDbEvent = (HANDLE)"dccchat"; + cle.flags = CLEF_TCHAR; + cle.hIcon = LoadIconEx(IDI_DCC); + mir_snprintf( szService, sizeof(szService),"%s/DblClickEvent", m_szModuleName); + cle.pszService = szService ; + mir_sntprintf( szNick, SIZEOF(szNick), TranslateT("CTCP chat request from %s"), name.c_str()); + cle.ptszTooltip = szNick; + cle.lParam = (LPARAM)pdci; + + if ( CallService( MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0)) + CallService( MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)"dccchat"); + CallService( MS_CLIST_ADDEVENT,(WPARAM) hContact,(LPARAM) &cle); + } + return TRUE; +} + +HANDLE CIrcProto::CList_AddContact(CONTACT * user, bool InList, bool SetOnline) +{ + if (user->name == NULL) + return 0; + + HANDLE hContact = CList_FindContact(user); + if ( hContact ) { + if ( InList ) + DBDeleteContactSetting( hContact, "CList", "NotOnList" ); + setTString(hContact, "Nick", user->name); + DBDeleteContactSetting(hContact, "CList", "Hidden"); + if (SetOnline && getWord(hContact, "Status", ID_STATUS_OFFLINE)== ID_STATUS_OFFLINE) + setWord(hContact, "Status", ID_STATUS_ONLINE); + return hContact; + } + + // here we create a new one since no one is to be found + hContact = (HANDLE) CallService( MS_DB_CONTACT_ADD, 0, 0); + if ( hContact ) { + CallService( MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM)m_szModuleName ); + + if ( InList ) + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + else + DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1); + DBDeleteContactSetting(hContact, "CList", "Hidden"); + setTString(hContact, "Nick", user->name); + setTString(hContact, "Default", user->name); + setWord(hContact, "Status", SetOnline ? ID_STATUS_ONLINE:ID_STATUS_OFFLINE); + if ( !InList && getByte( "MirVerAutoRequestTemp", 0)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), user->name); + return hContact; + } + return false; +} + +HANDLE CIrcProto::CList_SetOffline(struct CONTACT * user) +{ + DBVARIANT dbv; + HANDLE hContact = CList_FindContact(user); + if ( hContact ) { + if ( !getTString( hContact, "Default", &dbv )) { + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + setTString(hContact, "Nick", dbv.ptszVal); + setWord(hContact, "Status", ID_STATUS_OFFLINE); + DBFreeVariant(&dbv); + return hContact; + } } + + return 0; +} + +bool CIrcProto::CList_SetAllOffline(BYTE ChatsToo) +{ + DBVARIANT dbv; + + DisconnectAllDCCSessions(false); + + HANDLE hContact = db_find_first(); + while ( hContact ) { + char* szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0 ); + if ( szProto != NULL && !lstrcmpiA( szProto, m_szModuleName )) { + if ( getByte( hContact, "ChatRoom", 0 ) == 0 ) { + if ( getByte(hContact, "DCC", 0 ) != 0 ) { + if ( ChatsToo ) + setWord(hContact, "Status", ID_STATUS_OFFLINE); + } + else if ( !getTString( hContact, "Default", &dbv )) { + setTString( hContact, "Nick", dbv.ptszVal); + setWord( hContact, "Status", ID_STATUS_OFFLINE ); + DBFreeVariant( &dbv ); + } + DBDeleteContactSetting( hContact, m_szModuleName, "IP" ); + setString( hContact, "User", "" ); + setString( hContact, "Host", "" ); + } } + + hContact = db_find_next(hContact); + } + return true; +} + +HANDLE CIrcProto::CList_FindContact (CONTACT* user) +{ + if ( !user || !user->name ) + return 0; + + TCHAR* lowercasename = mir_tstrdup( user->name ); + CharLower(lowercasename); + + char *szProto; + DBVARIANT dbv1; + DBVARIANT dbv2; + DBVARIANT dbv3; + DBVARIANT dbv4; + DBVARIANT dbv5; + HANDLE hContact = db_find_first(); + while (hContact) { + szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto != NULL && !lstrcmpiA( szProto, m_szModuleName )) { + if ( getByte( hContact, "ChatRoom", 0) == 0) { + HANDLE hContact_temp = NULL; + TCHAR* DBDefault = NULL; + TCHAR* DBNick = NULL; + TCHAR* DBWildcard = NULL; + TCHAR* DBUser = NULL; + TCHAR* DBHost = NULL; + if ( !getTString(hContact, "Default", &dbv1)) DBDefault = dbv1.ptszVal; + if ( !getTString(hContact, "Nick", &dbv2)) DBNick = dbv2.ptszVal; + if ( !getTString(hContact, "UWildcard", &dbv3)) DBWildcard = dbv3.ptszVal; + if ( !getTString(hContact, "UUser", &dbv4)) DBUser = dbv4.ptszVal; + if ( !getTString(hContact, "UHost", &dbv5)) DBHost = dbv5.ptszVal; + + if ( DBWildcard ) + CharLower( DBWildcard ); + if ( IsChannel( user->name )) { + if ( DBDefault && !lstrcmpi( DBDefault, user->name )) + hContact_temp = (HANDLE)-1; + } + else if ( user->ExactNick && DBNick && !lstrcmpi( DBNick, user->name )) + hContact_temp = hContact; + + else if ( user->ExactOnly && DBDefault && !lstrcmpi( DBDefault, user->name )) + hContact_temp = hContact; + + else if ( user->ExactWCOnly ) { + if ( DBWildcard && !lstrcmpi( DBWildcard, lowercasename ) + || ( DBWildcard && !lstrcmpi( DBNick, lowercasename ) && !WCCmp( DBWildcard, lowercasename )) + || ( !DBWildcard && !lstrcmpi(DBNick, lowercasename))) + { + hContact_temp = hContact; + } + } + else if ( _tcschr(user->name, ' ' ) == 0 ) { + if (( DBDefault && !lstrcmpi(DBDefault, user->name) || DBNick && !lstrcmpi(DBNick, user->name) || + DBWildcard && WCCmp( DBWildcard, lowercasename )) + && ( WCCmp(DBUser, user->user) && WCCmp(DBHost, user->host))) + { + hContact_temp = hContact; + } } + + if ( DBDefault ) DBFreeVariant(&dbv1); + if ( DBNick ) DBFreeVariant(&dbv2); + if ( DBWildcard ) DBFreeVariant(&dbv3); + if ( DBUser ) DBFreeVariant(&dbv4); + if ( DBHost ) DBFreeVariant(&dbv5); + + if ( hContact_temp != NULL ) { + mir_free(lowercasename); + if ( hContact_temp != (HANDLE)-1 ) + return hContact_temp; + return 0; + } } } + + hContact = db_find_next(hContact); + } + mir_free(lowercasename); + return 0; +} diff --git a/protocols/IRCG/src/commandmonitor.cpp b/protocols/IRCG/src/commandmonitor.cpp new file mode 100644 index 0000000000..79d4579ae6 --- /dev/null +++ b/protocols/IRCG/src/commandmonitor.cpp @@ -0,0 +1,2508 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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. +*/ + +// This file holds functions that are called upon receiving +// certain commands from the server. + +#include "irc.h" + +using namespace irc; + +VOID CALLBACK IdentTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + ppro->KillChatTimer( ppro->IdentTimer ); + if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING ) + return; + + if ( ppro->IsConnected() && ppro->m_identTimer ) + ppro->KillIdent(); +} + +VOID CALLBACK TimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + ppro->KillChatTimer( ppro->InitTimer ); + if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING ) + return; + + if ( ppro->m_forceVisible ) + ppro->PostIrcMessage( _T("/MODE %s -i"), ppro->m_info.sNick.c_str()); + + if ( lstrlenA( ppro->m_myHost ) == 0 && ppro->IsConnected()) + ppro->DoUserhostWithReason(2, (_T("S") + ppro->m_info.sNick).c_str(), true, _T("%s"), ppro->m_info.sNick.c_str()); +} + +VOID CALLBACK KeepAliveTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( !ppro->m_sendKeepAlive || ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING )) { + ppro->KillChatTimer( ppro->KeepAliveTimer ); + return; + } + + TCHAR temp2[270]; + if ( !ppro->m_info.sServerName.IsEmpty()) + mir_sntprintf(temp2, SIZEOF(temp2), _T("PING %s"), ppro->m_info.sServerName.c_str()); + else + mir_sntprintf(temp2, SIZEOF(temp2), _T("PING %u"), time(0)); + + if ( ppro->IsConnected()) + ppro->SendIrcMessage( temp2, false ); +} + +VOID CALLBACK OnlineNotifTimerProc3( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( !ppro->m_channelAwayNotification || + ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING || + ( !ppro->m_autoOnlineNotification && !ppro->bTempForceCheck) || ppro->bTempDisableCheck ) { + ppro->KillChatTimer( ppro->OnlineNotifTimer3 ); + ppro->m_channelsToWho = _T(""); + return; + } + + CMString name = GetWord( ppro->m_channelsToWho.c_str(), 0 ); + if ( name.IsEmpty()) { + ppro->m_channelsToWho = _T(""); + int count = (int)CallServiceSync(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)ppro->m_szModuleName); + for ( int i = 0; i < count; i++ ) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX | NAME | TYPE | COUNT; + gci.iItem = i; + gci.pszModule = ppro->m_szModuleName; + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) + if ( gci.iCount <= ppro->m_onlineNotificationLimit ) + ppro->m_channelsToWho += CMString(gci.pszName) + _T(" "); + } } + + if ( ppro->m_channelsToWho.IsEmpty()) { + ppro->SetChatTimer( ppro->OnlineNotifTimer3, 60*1000, OnlineNotifTimerProc3 ); + return; + } + + name = GetWord( ppro->m_channelsToWho.c_str(), 0 ); + ppro->DoUserhostWithReason(2, _T("S") + name, true, _T("%s"), name.c_str()); + CMString temp = GetWordAddress( ppro->m_channelsToWho.c_str(), 1 ); + ppro->m_channelsToWho = temp; + if ( ppro->m_iTempCheckTime ) + ppro->SetChatTimer( ppro->OnlineNotifTimer3, ppro->m_iTempCheckTime*1000, OnlineNotifTimerProc3 ); + else + ppro->SetChatTimer( ppro->OnlineNotifTimer3, ppro->m_onlineNotificationTime*1000, OnlineNotifTimerProc3 ); +} + +VOID CALLBACK OnlineNotifTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( ppro->m_iStatus == ID_STATUS_OFFLINE || ppro->m_iStatus == ID_STATUS_CONNECTING || + ( !ppro->m_autoOnlineNotification && !ppro->bTempForceCheck) || ppro->bTempDisableCheck ) { + ppro->KillChatTimer( ppro->OnlineNotifTimer ); + ppro->m_namesToWho = _T(""); + return; + } + + CMString name = GetWord( ppro->m_namesToWho.c_str(), 0); + CMString name2 = GetWord( ppro->m_namesToUserhost.c_str(), 0); + + if ( name.IsEmpty() && name2.IsEmpty()) { + DBVARIANT dbv; + char* szProto; + + HANDLE hContact = db_find_first(); + while ( hContact ) { + szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto != NULL && !lstrcmpiA( szProto, ppro->m_szModuleName )) { + BYTE bRoom = ppro->getByte(hContact, "ChatRoom", 0); + if ( bRoom == 0 ) { + BYTE bDCC = ppro->getByte(hContact, "DCC", 0); + BYTE bHidden = DBGetContactSettingByte(hContact,"CList", "Hidden", 0); + if ( bDCC == 0 && bHidden == 0 ) { + if ( !ppro->getTString( hContact, "Default", &dbv )) { + BYTE bAdvanced = ppro->getByte(hContact, "AdvancedMode", 0) ; + if ( !bAdvanced ) { + DBFreeVariant( &dbv ); + if ( !ppro->getTString( hContact, "Nick", &dbv )) { + ppro->m_namesToUserhost += CMString(dbv.ptszVal) + _T(" "); + DBFreeVariant( &dbv ); + } + } + else { + DBFreeVariant( &dbv ); + DBVARIANT dbv2; + + TCHAR* DBNick = NULL; + TCHAR* DBWildcard = NULL; + if ( !ppro->getTString( hContact, "Nick", &dbv )) + DBNick = dbv.ptszVal; + if ( !ppro->getTString( hContact, "UWildcard", &dbv2 )) + DBWildcard = dbv2.ptszVal; + + if ( DBNick && ( !DBWildcard || !WCCmp(CharLower(DBWildcard), CharLower(DBNick)))) + ppro->m_namesToWho += CMString(DBNick) + _T(" "); + else if ( DBWildcard ) + ppro->m_namesToWho += CMString(DBWildcard) + _T(" "); + + if ( DBNick ) DBFreeVariant(&dbv); + if ( DBWildcard ) DBFreeVariant(&dbv2); + } } } } } + + hContact = db_find_next(hContact); + } } + + if ( ppro->m_namesToWho.IsEmpty() && ppro->m_namesToUserhost.IsEmpty()) { + ppro->SetChatTimer( ppro->OnlineNotifTimer, 60*1000, OnlineNotifTimerProc ); + return; + } + + name = GetWord( ppro->m_namesToWho.c_str(), 0); + name2 = GetWord( ppro->m_namesToUserhost.c_str(), 0); + CMString temp; + if ( !name.IsEmpty()) { + ppro->DoUserhostWithReason(2, _T("S") + name, true, _T("%s"), name.c_str()); + temp = GetWordAddress( ppro->m_namesToWho.c_str(), 1 ); + ppro->m_namesToWho = temp; + } + + if ( !name2.IsEmpty()) { + CMString params; + for ( int i = 0; i < 3; i++ ) { + params = _T(""); + for ( int j = 0; j < 5; j++ ) + params += GetWord( ppro->m_namesToUserhost, i *5 + j) + _T(" "); + + if ( params[0] != ' ' ) + ppro->DoUserhostWithReason(1, CMString(_T("S")) + params, true, params); + } + temp = GetWordAddress( ppro->m_namesToUserhost.c_str(), 15 ); + ppro->m_namesToUserhost = temp; + } + + if ( ppro->m_iTempCheckTime ) + ppro->SetChatTimer( ppro->OnlineNotifTimer, ppro->m_iTempCheckTime*1000, OnlineNotifTimerProc ); + else + ppro->SetChatTimer( ppro->OnlineNotifTimer, ppro->m_onlineNotificationTime*1000, OnlineNotifTimerProc ); +} + +int CIrcProto::AddOutgoingMessageToDB(HANDLE hContact, TCHAR* msg) +{ + if ( m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_CONNECTING ) + return 0; + + CMString S = DoColorCodes( msg, TRUE, FALSE ); + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.timestamp = (DWORD)time(NULL); + dbei.flags = DBEF_SENT + DBEF_UTF; + dbei.pBlob = ( PBYTE )mir_utf8encodeW( S.c_str()); + dbei.cbBlob = (DWORD)strlen(( char* )dbei.pBlob) + 1; + CallService( MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) & dbei); + mir_free( dbei.pBlob ); + return 1; +} + +void __cdecl CIrcProto::ResolveIPThread(LPVOID di) +{ + IPRESOLVE* ipr = (IPRESOLVE *) di; + + EnterCriticalSection( &m_resolve); + + if ( ipr != NULL && (ipr->iType == IP_AUTO && lstrlenA(m_myHost) == 0 || ipr->iType == IP_MANUAL )) { + hostent* myhost = gethostbyname( ipr->sAddr.c_str()); + if ( myhost ) { + IN_ADDR in; + memcpy( &in, myhost->h_addr, 4 ); + if ( ipr->iType == IP_AUTO ) + mir_snprintf( m_myHost, sizeof( m_myHost ), "%s", inet_ntoa( in )); + else + mir_snprintf( m_mySpecifiedHostIP, sizeof( m_mySpecifiedHostIP ), "%s", inet_ntoa( in )); + } } + + LeaveCriticalSection( &m_resolve ); + delete ipr; +} + +bool CIrcProto::OnIrc_PING(const CIrcMessage* pmsg) +{ + TCHAR szResponse[100]; + mir_sntprintf(szResponse, SIZEOF(szResponse), _T("PONG %s"), pmsg->parameters[0].c_str()); + SendIrcMessage( szResponse ); + return false; +} + +bool CIrcProto::OnIrc_WELCOME( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters[0] != m_info.sNick ) + m_info.sNick = pmsg->parameters[0]; + + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + static TCHAR host[1024]; + int i = 0; + CMString word = GetWord( pmsg->parameters[1].c_str(), i ); + while ( !word.IsEmpty()) { + if ( _tcschr( word.c_str(), '!') && _tcschr( word.c_str(), '@' )) { + lstrcpyn( host, word.c_str(), SIZEOF(host)); + TCHAR* p1 = _tcschr( host, '@' ); + if ( p1 ) + ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( _T2A(p1+1), IP_AUTO )); + } + + word = GetWord(pmsg->parameters[1].c_str(), ++i); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOTOOLONG( const CIrcMessage* pmsg ) +{ + CMString command = GetNextUserhostReason(2); + if ( command[0] == 'U' ) + ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_BACKFROMAWAY( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + int Temp = m_iStatus; + m_iStatus = m_iDesiredStatus = ID_STATUS_ONLINE; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_ONLINE); + + if ( m_perform ) + DoPerform( "Event: Available" ); + } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_SETAWAY( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + int Temp = m_iDesiredStatus; + m_iStatus = m_iDesiredStatus = ID_STATUS_AWAY; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_AWAY); + + if ( m_perform ) { + switch ( m_iStatus ) { + case ID_STATUS_AWAY: + DoPerform( "Event: Away" ); + break; + case ID_STATUS_NA: + DoPerform( "Event: N/A" ); + break; + case ID_STATUS_DND: + DoPerform( "Event: DND" ); + break; + case ID_STATUS_OCCUPIED: + DoPerform( "Event: Occupied" ); + break; + case ID_STATUS_OUTTOLUNCH: + DoPerform( "Event: Out for lunch" ); + break; + case ID_STATUS_ONTHEPHONE: + DoPerform( "Event: On the phone" ); + break; + default: + m_iStatus = ID_STATUS_AWAY; + DoPerform( "Event: Away" ); + break; + } } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_JOIN( const CIrcMessage* pmsg ) +{ + if (pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming && pmsg->prefix.sNick != m_info.sNick) { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_JOIN, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), NULL, _T("Normal"), host.c_str(), NULL, true, false); + DoEvent(GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[0].c_str(),pmsg->prefix.sNick.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE); + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_QUIT( const CIrcMessage* pmsg ) +{ + if (pmsg->m_bIncoming) + { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_QUIT, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters.getCount()>0?pmsg->parameters[0].c_str():NULL, NULL, host.c_str(), NULL, true, false); + struct CONTACT user = { (LPTSTR)pmsg->prefix.sNick.c_str(), (LPTSTR)pmsg->prefix.sUser.c_str(), (LPTSTR)pmsg->prefix.sHost.c_str(), false, false, false}; + CList_SetOffline( &user ); + if ( pmsg->prefix.sNick == m_info.sNick ) { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gce.cbSize = sizeof(GCEVENT); + gcd.pszID = NULL; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_PART( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 0 && pmsg->m_bIncoming ) { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_PART, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), pmsg->parameters.getCount()>1?pmsg->parameters[1].c_str():NULL, NULL, host.c_str(), NULL, true, false); + if ( pmsg->prefix.sNick == m_info.sNick ) { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + CMString S = MakeWndID( pmsg->parameters[0].c_str()); + gce.cbSize = sizeof(GCEVENT); + gcd.ptszID = ( TCHAR* )S.c_str(); + gce.dwFlags = GC_TCHAR; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_KICK( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) + DoEvent( GC_EVENT_KICK, pmsg->parameters[0].c_str(), pmsg->parameters[1].c_str(), pmsg->parameters.getCount()>2?pmsg->parameters[2].c_str():NULL, pmsg->prefix.sNick.c_str(), NULL, NULL, true, false); + else + ShowMessage( pmsg ); + + if ( pmsg->parameters[1] == m_info.sNick ) { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + CMString S = MakeWndID( pmsg->parameters[0].c_str()); + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gcd.ptszID = ( TCHAR* )S.c_str(); + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + + if ( m_rejoinIfKicked ) { + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi && wi->pszPassword ) + PostIrcMessage( _T("/JOIN %s %s"), pmsg->parameters[0].c_str(), wi->pszPassword); + else + PostIrcMessage( _T("/JOIN %s"), pmsg->parameters[0].c_str()); + } } + + return true; +} + +bool CIrcProto::OnIrc_MODEQUERY( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 2 && pmsg->m_bIncoming && IsChannel( pmsg->parameters[1] )) { + CMString sPassword = _T(""); + CMString sLimit = _T(""); + bool bAdd = false; + int iParametercount = 3; + + LPCTSTR p1 = pmsg->parameters[2].c_str(); + while ( *p1 != '\0' ) { + if ( *p1 == '+' ) + bAdd = true; + if ( *p1 == '-' ) + bAdd = false; + if ( *p1 == 'l' && bAdd ) { + if (( int )pmsg->parameters.getCount() > iParametercount ) + sLimit = pmsg->parameters[ iParametercount ]; + iParametercount++; + } + if ( *p1 == 'k' && bAdd ) { + if (( int )pmsg->parameters.getCount() > iParametercount ) + sPassword = pmsg->parameters[ iParametercount ]; + iParametercount++; + } + + p1++; + } + + AddWindowItemData( pmsg->parameters[1].c_str(), sLimit.IsEmpty() ? 0 : sLimit.c_str(), pmsg->parameters[2].c_str(), sPassword.IsEmpty() ? 0 : sPassword.c_str(), 0 ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_MODE( const CIrcMessage* pmsg ) +{ + bool flag = false; + bool bContainsValidModes = false; + CMString sModes = _T(""); + CMString sParams = _T(""); + + if ( pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming ) { + if ( IsChannel( pmsg->parameters[0] )) { + bool bAdd = false; + int iParametercount = 2; + LPCTSTR p1 = pmsg->parameters[1].c_str(); + + while ( *p1 != '\0' ) { + if ( *p1 == '+' ) { + bAdd = true; + sModes += _T("+"); + } + if ( *p1 == '-' ) { + bAdd = false; + sModes += _T("-"); + } + if ( *p1 == 'l' && bAdd && iParametercount < (int)pmsg->parameters.getCount()) { + bContainsValidModes = true; + sModes += _T("l"); + sParams += _T(" ") + pmsg->parameters[iParametercount]; + iParametercount++; + } + if ( *p1 == 'b' || *p1 == 'k' && iParametercount < (int)pmsg->parameters.getCount()) { + bContainsValidModes = true; + sModes += *p1; + sParams += _T(" ") + pmsg->parameters[iParametercount]; + iParametercount++; + } + if ( strchr( sUserModes.c_str(), (char)*p1 )) { + CMString sStatus = ModeToStatus( *p1 ); + if (( int )pmsg->parameters.getCount() > iParametercount ) { + if ( !_tcscmp(pmsg->parameters[2].c_str(), m_info.sNick.c_str())) { + char cModeBit = -1; + CHANNELINFO* wi = (CHANNELINFO *)DoEvent( GC_EVENT_GETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, NULL, false, false, 0 ); + switch (*p1) { + case 'v': cModeBit = 0; break; + case 'h': cModeBit = 1; break; + case 'o': cModeBit = 2; break; + case 'a': cModeBit = 3; break; + case 'q': cModeBit = 4; break; + } + + // set bit for own mode on this channel (voice/hop/op/admin/owner) + if ( bAdd && cModeBit >= 0 ) + wi->OwnMode |= ( 1 << cModeBit ); + else + wi->OwnMode &= ~( 1 << cModeBit ); + + DoEvent( GC_EVENT_SETITEMDATA, pmsg->parameters[0].c_str(), NULL, NULL, NULL, NULL, (DWORD_PTR)wi, false, false, 0 ); + } + DoEvent( bAdd ? GC_EVENT_ADDSTATUS : GC_EVENT_REMOVESTATUS, pmsg->parameters[0].c_str(), pmsg->parameters[iParametercount].c_str(), pmsg->prefix.sNick.c_str(), sStatus.c_str(), NULL, NULL, m_oldStyleModes?false:true, false); + iParametercount++; + } + } + else if (*p1 != 'b' && *p1 != ' ' && *p1 != '+' && *p1 != '-' ) { + bContainsValidModes = true; + if (*p1 != 'l' && *p1 != 'k') + sModes += *p1; + flag = true; + } + + p1++; + } + + if ( m_oldStyleModes ) { + TCHAR temp[256]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("%s sets mode %s"), + pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); + + CMString sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += _T(" ") + pmsg->parameters[i]; + + DoEvent( GC_EVENT_INFORMATION, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), sMessage.c_str(), NULL, NULL, NULL, true, false ); + } + else if ( bContainsValidModes ) { + for ( int i = iParametercount; i < (int)pmsg->parameters.getCount(); i++ ) + sParams += _T(" ") + pmsg->parameters[i]; + + TCHAR temp[4000]; + mir_sntprintf( temp, 3999, TranslateT( "%s sets mode %s%s" ), pmsg->prefix.sNick.c_str(), sModes.c_str(), sParams.c_str()); + DoEvent(GC_EVENT_INFORMATION, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + } + + if ( flag ) + PostIrcMessage( _T("/MODE %s"), pmsg->parameters[0].c_str()); + } + else { + TCHAR temp[256]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("%s sets mode %s"), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); + + CMString sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += _T(" ") + pmsg->parameters[i]; + + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, pmsg->prefix.sNick.c_str(), sMessage.c_str(), NULL, NULL, NULL, true, false); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_NICK( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { + bool bIsMe = pmsg->prefix.sNick.c_str() == m_info.sNick ? true : false; + + if ( m_info.sNick == pmsg->prefix.sNick && pmsg->parameters.getCount() > 0 ) { + m_info.sNick = pmsg->parameters[0]; + setTString("Nick", m_info.sNick.c_str()); + } + + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + DoEvent(GC_EVENT_NICK, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters[0].c_str(), NULL, host.c_str(), NULL, true, bIsMe); + DoEvent(GC_EVENT_CHUID, NULL, pmsg->prefix.sNick.c_str(), pmsg->parameters[0].c_str(), NULL, NULL, NULL, true, false); + + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + HANDLE hContact = CList_FindContact(&user); + if (hContact) { + if ( getWord(hContact, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) + setWord(hContact, "Status", ID_STATUS_ONLINE); + setTString(hContact, "Nick", pmsg->parameters[0].c_str()); + setTString(hContact, "User", pmsg->prefix.sUser.c_str()); + setTString(hContact, "Host", pmsg->prefix.sHost.c_str()); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_NOTICE( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + if ( IsCTCP( pmsg )) + return true; + + if ( !m_ignore || !IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'n' )) { + CMString S; + CMString S2; + CMString S3; + if ( pmsg->prefix.sNick.GetLength() > 0 ) + S = pmsg->prefix.sNick; + else + S = m_info.sNetwork; + S3 = m_info.sNetwork; + if ( IsChannel( pmsg->parameters[0] )) + S2 = pmsg->parameters[0].c_str(); + else { + GC_INFO gci = {0}; + gci.Flags = BYID | TYPE; + gci.pszModule = m_szModuleName; + + CMString S3 = GetWord( pmsg->parameters[1].c_str(), 0); + if ( S3[0] == '[' && S3[1] == '#' && S3[S3.GetLength()-1] == ']' ) { + S3.Delete(S3.GetLength()-1, 1); + S3.Delete(0,1); + CMString Wnd = MakeWndID( S3.c_str()); + gci.pszID = ( TCHAR* )Wnd.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) + S2 = GetWord( gci.pszID, 0 ); + else + S2 = _T(""); + } + else S2 = _T(""); + } + DoEvent(GC_EVENT_NOTICE, S2.IsEmpty() ? 0 : S2.c_str(), S.c_str(), pmsg->parameters[1].c_str(), NULL, S3.c_str(), NULL, true, false); + } + } + else ShowMessage( pmsg ); + + return true; +} + +bool CIrcProto::OnIrc_YOURHOST( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + static const TCHAR* lpszFmt = _T("Your host is %99[^ \x5b,], running version %99s"); + TCHAR szHostName[100], szVersion[100]; + if ( _stscanf(pmsg->parameters[1].c_str(), lpszFmt, &szHostName, &szVersion) > 0 ) + m_info.sServerName = szHostName; + if ( pmsg->parameters[0] != m_info.sNick) + m_info.sNick = pmsg->parameters[0]; + } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_INVITE( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && ( m_ignore && IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'i' ))) + return true; + + if ( pmsg->m_bIncoming && m_joinOnInvite && pmsg->parameters.getCount() >1 && lstrcmpi(pmsg->parameters[0].c_str(), m_info.sNick.c_str()) == 0 ) + PostIrcMessage( _T("/JOIN %s"), pmsg->parameters[1].c_str()); + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_PINGPONG( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->sCommand == _T("PING")) { + TCHAR szResponse[100]; + mir_sntprintf(szResponse, SIZEOF(szResponse), _T("PONG %s"), pmsg->parameters[0].c_str()); + SendIrcMessage( szResponse ); + } + + return true; +} + +bool CIrcProto::OnIrc_PRIVMSG( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 1 ) { + if ( IsCTCP( pmsg )) + return true; + + CMString mess = pmsg->parameters[1]; + bool bIsChannel = IsChannel(pmsg->parameters[0]); + + if ( pmsg->m_bIncoming && !bIsChannel ) { + CCSDATA ccs = {0}; + PROTORECVEVENT pre; + + mess = DoColorCodes( mess.c_str(), TRUE, FALSE ); + ccs.szProtoService = PSR_MESSAGE; + + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + + if ( CallService( MS_IGNORE_ISIGNORED, NULL, IGNOREEVENT_MESSAGE )) + if ( !CList_FindContact( &user )) + return true; + + if (( m_ignore && IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'q' ))) { + HANDLE hContact = CList_FindContact( &user ); + if ( !hContact || ( hContact && DBGetContactSettingByte( hContact,"CList", "Hidden", 0) == 1 )) + return true; + } + + ccs.hContact = CList_AddContact( &user, false, true ); + ccs.lParam = (LPARAM)⪯ + pre.timestamp = (DWORD)time(NULL); + pre.flags = PREF_UTF; + pre.szMessage = mir_utf8encodeW( mess.c_str()); + setTString(ccs.hContact, "User", pmsg->prefix.sUser.c_str()); + setTString(ccs.hContact, "Host", pmsg->prefix.sHost.c_str()); + CallService( MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs); + mir_free( pre.szMessage ); + return true; + } + + if ( bIsChannel ) { + if ( !(pmsg->m_bIncoming && m_ignore && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'm' ))) { + if ( !pmsg->m_bIncoming ) + ReplaceString( mess, _T("%%"), _T("%")); + DoEvent(GC_EVENT_MESSAGE, pmsg->parameters[0].c_str(), pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); + } + return true; + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::IsCTCP( const CIrcMessage* pmsg ) +{ + // is it a ctcp command, i e is the first and last characer of a PRIVMSG or NOTICE text ASCII 1 + CMString mess = pmsg->parameters[1]; + if ( !( mess.GetLength() > 3 && mess[0] == 1 && mess[ mess.GetLength()-1] == 1 )) + return false; + + // set mess to contain the ctcp command, excluding the leading and trailing ASCII 1 + mess.Delete(0,1); + mess.Delete(mess.GetLength()-1,1); + + // exploit??? + if ( mess.Find(1) != -1 || mess.Find( _T("%newl")) != -1 ) { + TCHAR temp[4096]; + mir_sntprintf(temp, SIZEOF(temp), TranslateT( "CTCP ERROR: Malformed CTCP command received from %s!%s@%s. Possible attempt to take control of your irc client registered"), pmsg->prefix.sNick.c_str(), pmsg->prefix.sUser.c_str(), pmsg->prefix.sHost.c_str()); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + return true; + } + + // extract the type of ctcp command + CMString ocommand = GetWord(mess.c_str(), 0); + CMString command = GetWord(mess.c_str(), 0); + command.MakeLower(); + + // should it be ignored? + if ( m_ignore ) { + if ( IsChannel( pmsg->parameters[0] )) { + if ( command == _T("action") && IsIgnored(pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'm')) + return true; + } + else { + if ( command == _T("action")) { + if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'q' )) + return true; + } + else if ( command == _T("dcc")) { + if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'd' )) + return true; + } + else if ( IsIgnored( pmsg->prefix.sNick, pmsg->prefix.sUser, pmsg->prefix.sHost, 'c' )) + return true; + } } + + if ( pmsg->sCommand == _T("PRIVMSG")) { + // incoming ACTION + if ( command == _T("action")) { + mess.Delete(0,6); + + if ( IsChannel( pmsg->parameters[0] )) { + if ( mess.GetLength() > 1 ) { + mess.Delete(0,1); + if ( !pmsg->m_bIncoming ) + ReplaceString(mess, _T("%%"), _T("%")); + + DoEvent(GC_EVENT_ACTION, pmsg->parameters[0].c_str(), pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); + } + } + else if (pmsg->m_bIncoming) + { + mess.Insert(0, pmsg->prefix.sNick.c_str()); + mess.Insert(0, _T("* ")); + mess.Insert(mess.GetLength(), _T(" *")); + CIrcMessage msg = *pmsg; + msg.parameters[1] = mess; + OnIrc_PRIVMSG(&msg); + } + } + // incoming FINGER + else if (pmsg->m_bIncoming && command == _T("finger")) { + PostIrcMessage( _T("/NOTICE %s \001FINGER %s (%s)\001"), pmsg->prefix.sNick.c_str(), m_name, m_userID); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP FINGER requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming VERSION + else if (pmsg->m_bIncoming && command == _T("version")) { + PostIrcMessage( _T("/NOTICE %s \001VERSION Miranda NG %s (IRC v.%s%s), (c) 2003-09 J.Persson, G.Hazan\001"), + pmsg->prefix.sNick.c_str(), _T("%mirver"), _T("%version"), + _T(" Unicode")); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP VERSION requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming SOURCE + else if (pmsg->m_bIncoming && command == _T("source")) { + PostIrcMessage( _T("/NOTICE %s \001SOURCE Get Miranda IRC here: http://miranda-ng.org/ \001"), pmsg->prefix.sNick.c_str()); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP SOURCE requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming USERINFO + else if (pmsg->m_bIncoming && command == _T("userinfo")) { + PostIrcMessage( _T("/NOTICE %s \001USERINFO %s\001"), pmsg->prefix.sNick.c_str(), m_userInfo ); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP USERINFO requested by %s") , pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming PING + else if (pmsg->m_bIncoming && command == _T("ping")) { + PostIrcMessage( _T("/NOTICE %s \001%s\001"), pmsg->prefix.sNick.c_str(), mess.c_str()); + + TCHAR temp[300]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("CTCP PING requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming TIME + else if (pmsg->m_bIncoming && command == _T("time")) { + TCHAR temp[300]; + time_t tim = time(NULL); + lstrcpyn( temp, _tctime( &tim ), 25 ); + PostIrcMessage( _T("/NOTICE %s \001TIME %s\001"), pmsg->prefix.sNick.c_str(), temp); + + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP TIME requested by %s"), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } + + // incoming DCC request... lots of stuff happening here... + else if (pmsg->m_bIncoming && command == _T("dcc")) { + CMString type = GetWord(mess.c_str(), 1); + type.MakeLower(); + + // components of a dcc message + CMString sFile = _T(""); + DWORD dwAdr = 0; + int iPort = 0; + unsigned __int64 dwSize = 0; + CMString sToken = _T(""); + bool bIsChat = ( type == _T("chat")); + + // 1. separate the dcc command into the correct pieces + if ( bIsChat || type == _T("send")) { + // if the filename is surrounded by quotes, do this + if ( GetWord(mess.c_str(), 2)[0] == '\"' ) { + int end = 0; + int begin = mess.Find('\"', 0); + if ( begin >= 0 ) { + end = mess.Find('\"', begin + 1); + if ( end >= 0 ) { + sFile = mess.Mid(begin+1, end-begin-1); + + begin = mess.Find(' ', end); + if ( begin >= 0 ) { + CMString rest = mess.Mid(begin, mess.GetLength()); + dwAdr = _tcstoul(GetWord(rest.c_str(), 0).c_str(), NULL, 10); + iPort = _ttoi(GetWord(rest.c_str(), 1).c_str()); + dwSize = _ttoi64(GetWord(rest.c_str(), 2).c_str()); + sToken = GetWord(rest.c_str(), 3); + } } } + } + // ... or try another method of separating the dcc command + else if ( !GetWord(mess.c_str(), (bIsChat) ? 4 : 5 ).IsEmpty()) { + int index = (bIsChat) ? 4 : 5; + bool bFlag = false; + + // look for the part of the ctcp command that contains adress, port and size + while ( !bFlag && !GetWord(mess.c_str(), index).IsEmpty()) { + CMString sTemp; + + if ( type == _T("chat")) + sTemp = GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); + else + sTemp = GetWord(mess.c_str(), index-2) + GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); + + // if all characters are number it indicates we have found the adress, port and size parameters + int ind = 0; + while ( sTemp[ind] != '\0' ) { + if ( !_istdigit( sTemp[ind] )) + break; + ind++; + } + + if ( sTemp[ind] == '\0' && GetWord( mess.c_str(), index + ((bIsChat) ? 1 : 2 )).IsEmpty()) + bFlag = true; + index++; + } + + if ( bFlag ) { + TCHAR* p1 = _tcsdup( GetWordAddress(mess.c_str(), 2 )); + TCHAR* p2 = ( TCHAR* )GetWordAddress( p1, index-5 ); + + if ( type == _T("send")) { + if ( p2 > p1 ) { + p2--; + while( p2 != p1 && *p2 == ' ' ) { + *p2 = '\0'; + p2--; + } + sFile = p1; + } + } + else sFile = _T("chat"); + + free( p1 ); + + dwAdr = _tcstoul(GetWord(mess.c_str(), index - (bIsChat?2:3)).c_str(), NULL, 10); + iPort = _ttoi(GetWord(mess.c_str(), index - (bIsChat?1:2)).c_str()); + dwSize = _ttoi64(GetWord(mess.c_str(), index-1).c_str()); + sToken = GetWord(mess.c_str(), index); + } } + } + else if (type == _T("accept") || type == _T("resume")) { + // if the filename is surrounded by quotes, do this + if ( GetWord(mess.c_str(), 2)[0] == '\"' ) { + int end = 0; + int begin = mess.Find('\"', 0); + if ( begin >= 0 ) { + end = mess.Find('\"', begin + 1); + if ( end >= 0 ) { + sFile = mess.Mid(begin+1, end); + + begin = mess.Find(' ', end); + if ( begin >= 0 ) { + CMString rest = mess.Mid(begin, mess.GetLength()); + iPort = _ttoi(GetWord(rest.c_str(), 0).c_str()); + dwSize = _ttoi(GetWord(rest.c_str(), 1).c_str()); + sToken = GetWord(rest.c_str(), 2); + } } } + } + // ... or try another method of separating the dcc command + else if ( !GetWord(mess.c_str(), 4).IsEmpty()) { + int index = 4; + bool bFlag = false; + + // look for the part of the ctcp command that contains adress, port and size + while ( !bFlag && !GetWord(mess.c_str(), index).IsEmpty()) { + CMString sTemp = GetWord(mess.c_str(), index-1) + GetWord(mess.c_str(), index); + + // if all characters are number it indicates we have found the adress, port and size parameters + int ind = 0; + + while ( sTemp[ind] != '\0' ) { + if ( !_istdigit( sTemp[ind] )) + break; + ind++; + } + + if ( sTemp[ind] == '\0' && GetWord(mess.c_str(), index + 2).IsEmpty()) + bFlag = true; + index++; + } + if ( bFlag ) { + TCHAR* p1 = _tcsdup(GetWordAddress(mess.c_str(), 2)); + TCHAR* p2 = ( TCHAR* )GetWordAddress(p1, index-4); + + if ( p2 > p1 ) { + p2--; + while( p2 != p1 && *p2 == ' ' ) { + *p2 = '\0'; + p2--; + } + sFile = p1; + } + + free( p1 ); + + iPort = _ttoi(GetWord(mess.c_str(), index-2).c_str()); + dwSize = _ttoi64(GetWord(mess.c_str(), index-1).c_str()); + sToken = GetWord(mess.c_str(), index); + } } } + // end separating dcc commands + + // 2. Check for malformed dcc commands or other errors + if ( bIsChat || type == _T("send")) { + TCHAR szTemp[256]; + szTemp[0] = '\0'; + + unsigned long ulAdr = 0; + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + if ( bIsChat && !m_DCCChatEnabled) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: Chat request from %s denied"),pmsg->prefix.sNick.c_str()); + + else if(type == _T("send") && !m_DCCFileEnabled) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: File transfer request from %s denied"),pmsg->prefix.sNick.c_str()); + + else if(type == _T("send") && !iPort && ulAdr == 0) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: Reverse file transfer request from %s denied [No local IP]"),pmsg->prefix.sNick.c_str()); + + if ( sFile.IsEmpty() || dwAdr == 0 || dwSize == 0 || iPort == 0 && sToken.IsEmpty()) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Malformed CTCP request from %s [%s]"),pmsg->prefix.sNick.c_str(), mess.c_str()); + + if ( szTemp[0] ) { + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + return true; + } + + // remove path from the filename if the remote client (stupidly) sent it + CMString sFileCorrected = sFile; + int i = sFile.ReverseFind( '\\' ); + if (i != -1 ) + sFileCorrected = sFile.Mid(i+1, sFile.GetLength()); + sFile = sFileCorrected; + } + else if ( type == _T("accept") || type == _T("resume")) { + TCHAR szTemp[256]; + szTemp[0] = '\0'; + + if ( type == _T("resume") && !m_DCCFileEnabled) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC: File transfer resume request from %s denied"),pmsg->prefix.sNick.c_str()); + + if ( sToken.IsEmpty() && iPort == 0 || sFile.IsEmpty()) + mir_sntprintf(szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Malformed CTCP request from %s [%s]"),pmsg->prefix.sNick.c_str(), mess.c_str()); + + if ( szTemp[0] ) { + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + return true; + } + + // remove path from the filename if the remote client (stupidly) sent it + CMString sFileCorrected = sFile; + int i = sFile.ReverseFind( '\\' ); + if ( i != -1 ) + sFileCorrected = sFile.Mid(i+1, sFile.GetLength()); + sFile = sFileCorrected; + } + + // 3. Take proper actions considering type of command + + // incoming chat request + if ( bIsChat ) { + CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), 0, 0, false, false, true}; + HANDLE hContact = CList_FindContact( &user ); + + // check if it should be ignored + if ( m_DCCChatIgnore == 1 || + m_DCCChatIgnore == 2 && hContact && + DBGetContactSettingByte(hContact,"CList", "NotOnList", 0) == 0 && + DBGetContactSettingByte(hContact,"CList", "Hidden", 0) == 0) + { + CMString host = pmsg->prefix.sUser + _T("@") + pmsg->prefix.sHost; + CList_AddDCCChat(pmsg->prefix.sNick, host, dwAdr, iPort); // add a CHAT event to the clist + } + else { + TCHAR szTemp[512]; + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC: Chat request from %s denied"),pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } } + + // remote requested that the file should be resumed + if ( type == _T("resume")) { + CDccSession* dcc; + if ( sToken.IsEmpty()) + dcc = FindDCCSendByPort( iPort ); + else + dcc = FindPassiveDCCSend( _ttoi( sToken.c_str())); // reverse ft + + if ( dcc ) { + InterlockedExchange(&dcc->dwWhatNeedsDoing, (long)FILERESUME_RESUME); + dcc->dwResumePos = dwSize; // dwSize is the resume position + PostIrcMessage( _T("/PRIVMSG %s \001DCC ACCEPT %s\001"), pmsg->prefix.sNick.c_str(), GetWordAddress(mess.c_str(), 2)); + } } + + // remote accepted your request for a file resume + if ( type == _T("accept")) { + CDccSession* dcc; + if ( sToken.IsEmpty()) + dcc = FindDCCRecvByPortAndName(iPort, pmsg->prefix.sNick.c_str()); + else + dcc = FindPassiveDCCRecv(pmsg->prefix.sNick, sToken); // reverse ft + + if ( dcc ) { + InterlockedExchange( &dcc->dwWhatNeedsDoing, (long)FILERESUME_RESUME ); + dcc->dwResumePos = dwSize; // dwSize is the resume position + SetEvent( dcc->hEvent ); + } } + + if ( type == _T("send")) { + CMString sTokenBackup = sToken; + bool bTurbo = false; // TDCC indicator + + if ( !sToken.IsEmpty() && sToken[sToken.GetLength()-1] == 'T' ) { + bTurbo = true; + sToken.Delete(sToken.GetLength()-1,1); + } + + // if a token exists and the port is non-zero it is the remote + // computer telling us that is has accepted to act as server for + // a reverse filetransfer. The plugin should connect to that computer + // and start sedning the file (if the token is valid). Compare to DCC RECV + if ( !sToken.IsEmpty() && iPort ) { + CDccSession* dcc = FindPassiveDCCSend( _ttoi( sToken.c_str())); + if ( dcc ) { + dcc->SetupPassive( dwAdr, iPort ); + dcc->Connect(); + } + } + else { + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + if ( CallService( MS_IGNORE_ISIGNORED, NULL, IGNOREEVENT_FILE )) + if ( !CList_FindContact( &user )) + return true; + + HANDLE hContact = CList_AddContact( &user, false, true ); + if ( hContact ) { + DCCINFO* di = new DCCINFO; + di->hContact = hContact; + di->sFile = sFile; + di->dwSize = dwSize; + di->sContactName = pmsg->prefix.sNick; + di->dwAdr = dwAdr; + di->iPort = iPort; + di->iType = DCC_SEND; + di->bSender = false; + di->bTurbo = bTurbo; + di->bSSL = false; + di->bReverse = (iPort == 0 && !sToken.IsEmpty()) ? true : false; + if ( di->bReverse ) + di->sToken = sTokenBackup; + + setTString(hContact, "User", pmsg->prefix.sUser.c_str()); + setTString(hContact, "Host", pmsg->prefix.sHost.c_str()); + + TCHAR* tszTemp = ( TCHAR* )sFile.c_str(); + + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.timestamp = (DWORD)time(NULL); + pre.fileCount = 1; + pre.ptszFiles = &tszTemp; + pre.lParam = (LPARAM)di; + + CCSDATA ccs = {0}; + ccs.szProtoService = PSR_FILE; + ccs.hContact = hContact; + ccs.lParam = (LPARAM) & pre; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + } } } + // end type == "send" + } + else if ( pmsg->m_bIncoming ) { + TCHAR temp[300]; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s requested by %s"), ocommand.c_str(), pmsg->prefix.sNick.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, temp, NULL, NULL, NULL, true, false); + } } + + // handle incoming ctcp in notices. This technique is used for replying to CTCP queries + else if(pmsg->sCommand == _T("NOTICE")) { + TCHAR szTemp[300]; + szTemp[0] = '\0'; + + //if we got incoming CTCP Version for contact in CList - then write its as MirVer for that contact! + if (pmsg->m_bIncoming && command == _T("version")) + { + struct CONTACT user = { (TCHAR*)pmsg->prefix.sNick.c_str(), (TCHAR*)pmsg->prefix.sUser.c_str(), (TCHAR*)pmsg->prefix.sHost.c_str(), false, false, false}; + HANDLE hContact = CList_FindContact(&user); + if (hContact) + setTString( hContact, "MirVer", DoColorCodes(GetWordAddress(mess.c_str(), 1), TRUE, FALSE)); + } + + // if the whois window is visible and the ctcp reply belongs to the user in it, then show the reply in the whois window + if ( m_whoisDlg && IsWindowVisible( m_whoisDlg->GetHwnd())) { + m_whoisDlg->m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + if ( lstrcmpi(szTemp, pmsg->prefix.sNick.c_str()) == 0 ) { + if ( pmsg->m_bIncoming && (command == _T("version") || command == _T("userinfo") || command == _T("time"))) { + SetActiveWindow( m_whoisDlg->GetHwnd()); + m_whoisDlg->m_Reply.SetText( DoColorCodes(GetWordAddress(mess.c_str(), 1), TRUE, FALSE)); + return true; + } + if (pmsg->m_bIncoming && command == _T("ping")) { + SetActiveWindow( m_whoisDlg->GetHwnd()); + int s = (int)time(0) - (int)_ttol(GetWordAddress(mess.c_str(), 1)); + TCHAR szTemp[30]; + if ( s == 1 ) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u second"), s ); + else + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u seconds"), s ); + + m_whoisDlg->m_Reply.SetText( DoColorCodes( szTemp, TRUE, FALSE )); + return true; + } } } + + //... else show the reply in the current window + if ( pmsg->m_bIncoming && command == _T("ping")) { + int s = (int)time(0) - (int)_ttol(GetWordAddress(mess.c_str(), 1)); + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP PING reply from %s: %u sec(s)"), pmsg->prefix.sNick.c_str(), s); + DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false ); + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP %s reply from %s: %s"), ocommand.c_str(), pmsg->prefix.sNick.c_str(), GetWordAddress(mess.c_str(), 1)); + DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false ); + } } + + return true; +} + +bool CIrcProto::OnIrc_NAMES( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 3 ) + sNamesList += pmsg->parameters[3] + _T(" "); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_ENDNAMES( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + CMString name = _T("a"); + int i = 0; + BOOL bFlag = false; + + // Is the user on the names list? + while ( !name.IsEmpty()) { + name = GetWord( sNamesList.c_str(), i ); + i++; + if ( !name.IsEmpty()) { + int index = 0; + while ( _tcschr( sUserModePrefixes.c_str(), name[index] )) + index++; + + if ( !lstrcmpi( name.Mid(index, name.GetLength()).c_str(), m_info.sNick.c_str())) { + bFlag = true; + break; + } } } + + if ( bFlag ) { + const TCHAR* sChanName = pmsg->parameters[1].c_str(); + if ( sChanName[0] == '@' || sChanName[0] == '*' || sChanName[0] == '=' ) + sChanName++; + + // Add a new chat window + GCSESSION gcw = {0}; + CMString sID = MakeWndID( sChanName ); + BYTE btOwnMode = 0; + gcw.cbSize = sizeof(GCSESSION); + gcw.iType = GCW_CHATROOM; + gcw.dwFlags = GC_TCHAR; + gcw.ptszID = sID.c_str(); + gcw.pszModule = m_szModuleName; + gcw.ptszName = sChanName; + if ( !CallServiceSync( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw )) { + DBVARIANT dbv; + GCDEST gcd = {0}; + GCEVENT gce = {0}; + CMString sTemp; + int i = 0; + + PostIrcMessage( _T("/MODE %s"), sChanName ); + + gcd.ptszID = ( TCHAR* )sID.c_str(); + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_ADDGROUP; + gce.time = 0; + gce.dwFlags = GC_TCHAR; + + //register the statuses + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + + gce.ptszStatus = _T("Owner"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Admin"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Op"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Halfop"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Voice"); + CallChatEvent(0, (LPARAM)&gce); + gce.ptszStatus = _T("Normal"); + CallChatEvent(0, (LPARAM)&gce); + + i = 0; + sTemp = GetWord(sNamesList.c_str(), i); + + // Fill the nicklist + while ( !sTemp.IsEmpty()) { + CMString sStat; + CMString sTemp2 = sTemp; + sStat = PrefixToStatus(sTemp[0]); + + // fix for networks like freshirc where they allow more than one prefix + while ( PrefixToStatus(sTemp[0]) != _T("Normal")) + sTemp.Delete(0,1); + + gcd.iType = GC_EVENT_JOIN; + gce.ptszUID = sTemp.c_str(); + gce.ptszNick = sTemp.c_str(); + gce.ptszStatus = sStat.c_str(); + BOOL bIsMe = ( !lstrcmpi( gce.ptszNick, m_info.sNick.c_str())) ? TRUE : FALSE; + if ( bIsMe ) { + char BitNr = -1; + switch ( sTemp2[0] ) { + case '+': BitNr = 0; break; + case '%': BitNr = 1; break; + case '@': BitNr = 2; break; + case '!': BitNr = 3; break; + case '*': BitNr = 4; break; + } + if (BitNr >=0) + btOwnMode = ( 1 << BitNr ); + else + btOwnMode = 0; + } + gce.dwFlags = GC_TCHAR; + gce.bIsMe = bIsMe; + gce.time = bIsMe?time(0):0; + CallChatEvent(0, (LPARAM)&gce); + DoEvent( GC_EVENT_SETCONTACTSTATUS, sChanName, sTemp.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE ); + // fix for networks like freshirc where they allow more than one prefix + if ( PrefixToStatus( sTemp2[0]) != _T("Normal")) { + sTemp2.Delete(0,1); + sStat = PrefixToStatus(sTemp2[0]); + while ( sStat != _T("Normal")) { + DoEvent( GC_EVENT_ADDSTATUS, sID.c_str(), sTemp.c_str(), _T("system"), sStat.c_str(), NULL, NULL, false, false, 0 ); + sTemp2.Delete(0,1); + sStat = PrefixToStatus(sTemp2[0]); + } } + + i++; + sTemp = GetWord(sNamesList.c_str(), i); + } + + //Set the item data for the window + { + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, sChanName, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if (!wi) + wi = new CHANNELINFO; + wi->OwnMode = btOwnMode; + wi->pszLimit = 0; + wi->pszMode = 0; + wi->pszPassword = 0; + wi->pszTopic = 0; + wi->codepage = getCodepage(); + DoEvent(GC_EVENT_SETITEMDATA, sChanName, NULL, NULL, NULL, NULL, (DWORD_PTR)wi, false, false, 0); + + if ( !sTopic.IsEmpty() && !lstrcmpi(GetWord(sTopic.c_str(), 0).c_str(), sChanName )) { + DoEvent(GC_EVENT_TOPIC, sChanName, sTopicName.IsEmpty() ? NULL : sTopicName.c_str(), GetWordAddress(sTopic.c_str(), 1), NULL, sTopicTime.IsEmpty() ? NULL : sTopicTime.c_str(), NULL, true, false); + AddWindowItemData(sChanName, 0, 0, 0, GetWordAddress(sTopic.c_str(), 1)); + sTopic = _T(""); + sTopicName = _T(""); + sTopicTime = _T(""); + } } + + gcd.ptszID = (TCHAR*)sID.c_str(); + gcd.iType = GC_EVENT_CONTROL; + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gce.bIsMe = false; + gce.dwItemData = false; + gce.pszNick = NULL; + gce.pszStatus = NULL; + gce.pszText = NULL; + gce.pszUID = NULL; + gce.pszUserInfo = NULL; + gce.time = time(0); + gce.pDest = &gcd; + + if ( !getTString( "JTemp", &dbv )) { + CMString command = _T("a"); + CMString save = _T(""); + int i = 0; + + while ( !command.IsEmpty()) { + command = GetWord( dbv.ptszVal, i ); + i++; + if ( !command.IsEmpty()) { + CMString S = command.Mid(1, command.GetLength()); + if ( !lstrcmpi( sChanName, S.c_str())) + break; + + save += command + _T(" "); + } } + + if ( !command.IsEmpty()) { + save += GetWordAddress( dbv.ptszVal, i ); + switch ( command[0] ) { + case 'M': + CallChatEvent( WINDOW_HIDDEN, (LPARAM)&gce); + break; + case 'X': + CallChatEvent( WINDOW_MAXIMIZE, (LPARAM)&gce); + break; + default: + CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); + break; + } + } + else CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); + + if ( save.IsEmpty()) + DBDeleteContactSetting(NULL, m_szModuleName, "JTemp"); + else + setTString("JTemp", save.c_str()); + DBFreeVariant(&dbv); + } + else CallChatEvent( SESSION_INITDONE, (LPARAM)&gce); + + { gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_ONLINE, (LPARAM)&gce); + } } } } + + sNamesList = _T(""); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_INITIALTOPIC( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) { + AddWindowItemData( pmsg->parameters[1].c_str(), 0, 0, 0, pmsg->parameters[2].c_str()); + sTopic = pmsg->parameters[1] + _T(" ") + pmsg->parameters[2]; + sTopicName = _T(""); + sTopicTime = _T(""); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_INITIALTOPICNAME( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 3 ) { + TCHAR tTimeBuf[128], *tStopStr; + time_t ttTopicTime; + sTopicName = pmsg->parameters[2]; + ttTopicTime = _tcstol( pmsg->parameters[3].c_str(), &tStopStr, 10); + _tcsftime(tTimeBuf, 128, _T("%#c"), localtime(&ttTopicTime)); + sTopicTime = tTimeBuf; + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_TOPIC( const CIrcMessage* pmsg ) +{ + if ( pmsg->parameters.getCount() > 1 && pmsg->m_bIncoming ) { + DoEvent( GC_EVENT_TOPIC, pmsg->parameters[0].c_str(), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str(), NULL, sTopicTime.IsEmpty() ? NULL : sTopicTime.c_str(), NULL, true, false); + AddWindowItemData(pmsg->parameters[0].c_str(), 0, 0, 0, pmsg->parameters[1].c_str()); + } + ShowMessage( pmsg ); + return true; +} + +static void __stdcall sttShowDlgList( void* param ) +{ + CIrcProto* ppro = ( CIrcProto* )param; + if ( ppro->m_listDlg == NULL ) { + ppro->m_listDlg = new CListDlg( ppro ); + ppro->m_listDlg->Show(); + } + SetEvent( ppro->m_evWndCreate ); +} + +bool CIrcProto::OnIrc_LISTSTART( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + CallFunctionAsync( sttShowDlgList, this ); + WaitForSingleObject( m_evWndCreate, INFINITE ); + m_channelNumber = 0; + } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_LIST( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming == 1 && m_listDlg && pmsg->parameters.getCount() > 2 ) { + m_channelNumber++; + LVITEM lvItem; + HWND hListView = GetDlgItem( m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW ); + lvItem.iItem = ListView_GetItemCount( hListView ); + lvItem.mask = LVIF_TEXT | LVIF_PARAM; + lvItem.iSubItem = 0; + lvItem.pszText = (TCHAR*)pmsg->parameters[1].c_str(); + lvItem.lParam = lvItem.iItem; + lvItem.iItem = ListView_InsertItem( hListView, &lvItem ); + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem =1; + lvItem.pszText = (TCHAR*)pmsg->parameters[pmsg->parameters.getCount()-2].c_str(); + ListView_SetItem( hListView, &lvItem ); + + TCHAR* temp = mir_tstrdup( pmsg->parameters[pmsg->parameters.getCount()-1] ); + TCHAR* find = _tcsstr( temp , _T("[+")); + TCHAR* find2 = _tcsstr( temp , _T("]")); + TCHAR* save = temp; + if ( find == temp && find2 != NULL && find+8 >= find2 ) { + temp = _tcsstr( temp, _T("]")); + if ( lstrlen(temp) > 1 ) { + temp++; + temp[0] = '\0'; + lvItem.iSubItem =2; + lvItem.pszText = save; + ListView_SetItem(hListView,&lvItem); + temp[0] = ' '; + temp++; + } + else temp =save; + } + + lvItem.iSubItem =3; + CMString S = DoColorCodes(temp, TRUE, FALSE); + lvItem.pszText = ( TCHAR* )S.c_str(); + ListView_SetItem( hListView, &lvItem ); + temp = save; + mir_free( temp ); + + int percent = 100; + if ( m_noOfChannels > 0 ) + percent = (int)(m_channelNumber*100) / m_noOfChannels; + + TCHAR text[100]; + if ( percent < 100) + mir_sntprintf(text, SIZEOF(text), TranslateT("Downloading list (%u%%) - %u channels"), percent, m_channelNumber); + else + mir_sntprintf(text, SIZEOF(text), TranslateT("Downloading list - %u channels"), m_channelNumber); + m_listDlg->m_status.SetText( text ); + } + + return true; +} + +bool CIrcProto::OnIrc_LISTEND( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_listDlg ) { + EnableWindow(GetDlgItem(m_listDlg->GetHwnd(), IDC_JOIN), true); + ListView_SetSelectionMark(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 0); + ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 1, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 2, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(GetDlgItem(m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW), 3, LVSCW_AUTOSIZE); + m_listDlg->UpdateList(); + + TCHAR text[100]; + mir_sntprintf( text, SIZEOF(text), TranslateT("Done: %u channels"), m_channelNumber ); + int percent = 100; + if ( m_noOfChannels > 0 ) + percent = (int)(m_channelNumber*100) / m_noOfChannels; + if ( percent < 70 ) { + lstrcat( text, _T(" ")); + lstrcat( text, TranslateT("(probably truncated by server)")); + } + SetDlgItemText( m_listDlg->GetHwnd(), IDC_TEXT, text ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_BANLIST( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) { + if ( m_managerDlg->GetHwnd() && ( + m_managerDlg->m_radio1.GetState() && pmsg->sCommand == _T("367") || + m_managerDlg->m_radio2.GetState() && pmsg->sCommand == _T("346") || + m_managerDlg->m_radio3.GetState() && pmsg->sCommand == _T("348")) && + !m_managerDlg->m_radio1.Enabled() && !m_managerDlg->m_radio2.Enabled() && !m_managerDlg->m_radio3.Enabled()) + { + CMString S = pmsg->parameters[2]; + if ( pmsg->parameters.getCount() > 3 ) { + S += _T(" - "); + S += pmsg->parameters[3]; + if ( pmsg->parameters.getCount() > 4 ) { + S += _T(" - ( "); + time_t time = StrToInt( pmsg->parameters[4].c_str()); + S += _tctime( &time ); + ReplaceString( S, _T("\n"), _T(" ")); + S += _T(")"); + } } + + SendDlgItemMessage(m_managerDlg->GetHwnd(), IDC_LIST, LB_ADDSTRING, 0, (LPARAM)S.c_str()); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_BANLISTEND( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + if ( m_managerDlg->GetHwnd() && + ( m_managerDlg->m_radio1.GetState() && pmsg->sCommand == _T("368") + || m_managerDlg->m_radio2.GetState() && pmsg->sCommand == _T("347") + || m_managerDlg->m_radio3.GetState() && pmsg->sCommand == _T("349")) && + !m_managerDlg->m_radio1.Enabled() && !m_managerDlg->m_radio2.Enabled() && !m_managerDlg->m_radio3.Enabled()) + { + if ( strchr( sChannelModes.c_str(), 'b' )) + m_managerDlg->m_radio1.Enable(); + if ( strchr( sChannelModes.c_str(), 'I' )) + m_managerDlg->m_radio2.Enable(); + if ( strchr( sChannelModes.c_str(), 'e' )) + m_managerDlg->m_radio3.Enable(); + if ( !IsDlgButtonChecked(m_managerDlg->GetHwnd(), IDC_NOTOP)) + m_managerDlg->m_add.Enable(); + } } + + ShowMessage( pmsg ); + return true; +} + +static void __stdcall sttShowWhoisWnd( void* param ) +{ + CIrcMessage* pmsg = ( CIrcMessage* )param; + CIrcProto* ppro = ( CIrcProto* )pmsg->m_proto; + if ( ppro->m_whoisDlg == NULL ) { + ppro->m_whoisDlg = new CWhoisDlg( ppro ); + ppro->m_whoisDlg->Show(); + } + SetEvent( ppro->m_evWndCreate ); + + ppro->m_whoisDlg->ShowMessage( pmsg ); + delete pmsg; +} + +bool CIrcProto::OnIrc_WHOIS_NAME( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 5 && m_manualWhoisCount > 0 ) { + CallFunctionAsync( sttShowWhoisWnd, new CIrcMessage( *pmsg )); + WaitForSingleObject( m_evWndCreate, INFINITE ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_CHANNELS( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) + m_whoisDlg->m_InfoChannels.SetText( pmsg->parameters[2].c_str()); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_AWAY( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) + m_whoisDlg->m_InfoAway2.SetText( pmsg->parameters[2].c_str()); + if ( m_manualWhoisCount < 1 && pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 ) + WhoisAwayReply = pmsg->parameters[2]; + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_OTHER( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { + TCHAR temp[1024], temp2[1024]; + m_whoisDlg->m_InfoOther.GetText( temp, 1000 ); + lstrcat( temp, _T("%s\r\n")); + mir_sntprintf( temp2, 1020, temp, pmsg->parameters[2].c_str()); + m_whoisDlg->m_InfoOther.SetText( temp2 ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_END( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 && m_manualWhoisCount < 1 ) { + CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, false, true}; + HANDLE hContact = CList_FindContact( &user ); + if ( hContact ) + ProtoBroadcastAck( m_szModuleName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM)WhoisAwayReply.c_str()); + } + + m_manualWhoisCount--; + if (m_manualWhoisCount < 0) + m_manualWhoisCount = 0; + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_IDLE( const CIrcMessage* pmsg ) +{ + int D = 0; + int H = 0; + int M = 0; + int S = 0; + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { + S = StrToInt(pmsg->parameters[2].c_str()); + D = S/(60*60*24); + S -= (D * 60 * 60 *24); + H = S/(60*60); + S -= (H * 60 * 60); + M = S/60; + S -= (M * 60 ); + + TCHAR temp[100]; + if ( D ) + mir_sntprintf(temp, 99, _T("%ud, %uh, %um, %us"), D, H, M, S); + else if (H) + mir_sntprintf(temp, 99, _T("%uh, %um, %us"), H, M, S); + else if (M) + mir_sntprintf(temp, 99, _T("%um, %us"), M, S); + else if (S) + mir_sntprintf(temp, 99, _T("%us"), S); + else + temp[0] = 0; + + TCHAR temp3[256]; + TCHAR tTimeBuf[128], *tStopStr; + time_t ttTime = _tcstol( pmsg->parameters[3].c_str(), &tStopStr, 10); + _tcsftime(tTimeBuf, 128, _T("%c"), localtime(&ttTime)); + mir_sntprintf( temp3, SIZEOF(temp3), _T("online since %s, idle %s"), tTimeBuf, temp); + m_whoisDlg->m_AwayTime.SetText( temp3 ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_SERVER( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) + m_whoisDlg->m_InfoServer.SetText( pmsg->parameters[2].c_str()); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_AUTH( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && m_whoisDlg && pmsg->parameters.getCount() > 2 && m_manualWhoisCount > 0 ) { + if ( pmsg->sCommand == _T("330")) + m_whoisDlg->m_InfoAuth.SetText( pmsg->parameters[2].c_str()); + else if ( pmsg->parameters[2] == _T("is an identified user") || pmsg->parameters[2] == _T("is a registered nick")) + m_whoisDlg->m_InfoAuth.SetText( pmsg->parameters[2].c_str()); + else + OnIrc_WHOIS_OTHER( pmsg ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHOIS_NO_USER( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 2 && !IsChannel( pmsg->parameters[1] )) { + if ( m_whoisDlg ) + m_whoisDlg->ShowMessageNoUser( pmsg ); + + CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, false, false}; + HANDLE hContact = CList_FindContact( &user ); + if ( hContact ) { + AddOutgoingMessageToDB( hContact, (TCHAR*)((CMString)_T("> ") + pmsg->parameters[2] + (CMString)_T(": ") + pmsg->parameters[1]).c_str()); + + DBVARIANT dbv; + if ( !getTString( hContact, "Default", &dbv )) { + setTString( hContact, "Nick", dbv.ptszVal ); + + DBVARIANT dbv2; + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) + DoUserhostWithReason(1, ((CMString)_T("S") + dbv.ptszVal).c_str(), true, dbv.ptszVal ); + else { + if ( !getTString( hContact, "UWildcard", &dbv2 )) { + DoUserhostWithReason(2, ((CMString)_T("S") + dbv2.ptszVal).c_str(), true, dbv2.ptszVal ); + DBFreeVariant(&dbv2); + } + else DoUserhostWithReason(2, ((CMString)_T("S") + dbv.ptszVal).c_str(), true, dbv.ptszVal ); + } + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + DBFreeVariant(&dbv); + } } } + + ShowMessage( pmsg ); + return true; +} + +static void __stdcall sttShowNickWnd( void* param ) +{ + CIrcMessage* pmsg = ( CIrcMessage* )param; + CIrcProto* ppro = pmsg->m_proto; + if ( ppro->m_nickDlg == NULL ) { + ppro->m_nickDlg = new CNickDlg( ppro ); + ppro->m_nickDlg->Show(); + } + SetEvent( ppro->m_evWndCreate ); + SetWindowText( GetDlgItem( ppro->m_nickDlg->GetHwnd(), IDC_CAPTION ), TranslateT("Change nickname")); + SetWindowText( GetDlgItem( ppro->m_nickDlg->GetHwnd(), IDC_TEXT ), pmsg->parameters.getCount() > 2 ? pmsg->parameters[2].c_str() : _T("")); + ppro->m_nickDlg->m_Enick.SetText( pmsg->parameters[1].c_str()); + ppro->m_nickDlg->m_Enick.SendMsg( CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); + delete pmsg; +} + +bool CIrcProto::OnIrc_NICK_ERR( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + if ( nickflag && ((m_alternativeNick[0] != 0)) && (pmsg->parameters.getCount() > 2 && _tcscmp(pmsg->parameters[1].c_str(), m_alternativeNick))) { + TCHAR m[200]; + mir_sntprintf( m, SIZEOF(m), _T("NICK %s"), m_alternativeNick ); + if ( IsConnected()) + SendIrcMessage( m ); + } + else { + CallFunctionAsync( sttShowNickWnd, new CIrcMessage( *pmsg )); + WaitForSingleObject( m_evWndCreate, INFINITE ); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_JOINERROR( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming ) { + DBVARIANT dbv; + if ( !getTString( "JTemp", &dbv )) { + CMString command = _T("a"); + CMString save = _T(""); + int i = 0; + + while ( !command.IsEmpty()) { + command = GetWord( dbv.ptszVal, i ); + i++; + + if ( !command.IsEmpty() && pmsg->parameters[0] == command.Mid(1, command.GetLength())) + save += command + _T(" "); + } + + DBFreeVariant(&dbv); + + if ( save.IsEmpty()) + DBDeleteContactSetting( NULL, m_szModuleName, "JTemp" ); + else + setTString( "JTemp", save.c_str()); + } } + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_UNKNOWN( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { + if ( pmsg->parameters[0] == _T("WHO") && GetNextUserhostReason(2) != _T("U")) + return true; + if ( pmsg->parameters[0] == _T("USERHOST") && GetNextUserhostReason(1) != _T("U")) + return true; + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_ENDMOTD( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && !bPerformDone ) + DoOnConnect( pmsg ); + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_NOOFCHANNELS( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) + m_noOfChannels = StrToInt( pmsg->parameters[1].c_str()); + + if ( pmsg->m_bIncoming && !bPerformDone ) + DoOnConnect( pmsg ); + + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_ERROR( const CIrcMessage* pmsg ) +{ + if ( pmsg->m_bIncoming && !m_disableErrorPopups && m_iDesiredStatus != ID_STATUS_OFFLINE) { + MIRANDASYSTRAYNOTIFY msn; + msn.cbSize = sizeof(MIRANDASYSTRAYNOTIFY); + msn.szProto = m_szModuleName; + msn.tszInfoTitle = TranslateT("IRC error"); + + CMString S; + if ( pmsg->parameters.getCount() > 0 ) + S = DoColorCodes( pmsg->parameters[0].c_str(), TRUE, FALSE ); + else + S = TranslateT( "Unknown" ); + + msn.tszInfo = ( TCHAR* )S.c_str(); + msn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE; + msn.uTimeout = 15000; + CallService( MS_CLIST_SYSTRAY_NOTIFY, 0, ( LPARAM )&msn ); + } + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHO_END( const CIrcMessage* pmsg ) +{ + CMString command = GetNextUserhostReason(2); + if ( command[0] == 'S' ) { + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + // is it a channel? + if ( IsChannel( pmsg->parameters[1] )) { + CMString S; + CMString User = GetWord( m_whoReply.c_str(), 0 ); + while ( !User.IsEmpty()) { + if ( GetWord( m_whoReply.c_str(), 3)[0] == 'G' ) { + S += User; + S += _T("\t"); + DoEvent( GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[1].c_str(), User.c_str(), NULL, NULL, NULL, ID_STATUS_AWAY, FALSE, FALSE); + } + else DoEvent( GC_EVENT_SETCONTACTSTATUS, pmsg->parameters[1].c_str(), User.c_str(), NULL, NULL, NULL, ID_STATUS_ONLINE, FALSE, FALSE); + + CMString SS = GetWordAddress( m_whoReply.c_str(), 4 ); + if ( SS.IsEmpty()) + break; + m_whoReply = SS; + User = GetWord(m_whoReply.c_str(), 0); + } + + DoEvent( GC_EVENT_SETSTATUSEX, pmsg->parameters[1].c_str(), NULL, S.IsEmpty() ? NULL : S.c_str(), NULL, NULL, GC_SSE_TABDELIMITED, FALSE, FALSE); + return true; + } + + /// if it is not a channel + TCHAR* UserList = mir_tstrdup( m_whoReply.c_str()); + const TCHAR* p1= UserList; + m_whoReply = _T(""); + CONTACT user = { (TCHAR*)pmsg->parameters[1].c_str(), NULL, NULL, false, true, false}; + HANDLE hContact = CList_FindContact( &user ); + + if ( hContact && getByte( hContact, "AdvancedMode", 0 ) == 1 ) { + DBVARIANT dbv1, dbv2, dbv3, dbv4, dbv5, dbv6, dbv7; + TCHAR *DBDefault = NULL, *DBNick = NULL, *DBWildcard = NULL; + TCHAR *DBUser = NULL, *DBHost = NULL, *DBManUser = NULL, *DBManHost = NULL; + if ( !getTString(hContact, "Default", &dbv1)) DBDefault = dbv1.ptszVal; + if ( !getTString(hContact, "Nick", &dbv2)) DBNick = dbv2.ptszVal; + if ( !getTString(hContact, "UWildcard", &dbv3)) DBWildcard = dbv3.ptszVal; + if ( !getTString(hContact, "UUser", &dbv4)) DBUser = dbv4.ptszVal; + if ( !getTString(hContact, "UHost", &dbv5)) DBHost = dbv5.ptszVal; + if ( !getTString(hContact, "User", &dbv6)) DBManUser = dbv6.ptszVal; + if ( !getTString(hContact, "Host", &dbv7)) DBManHost = dbv7.ptszVal; + if ( DBWildcard ) + CharLower( DBWildcard ); + + CMString nick; + CMString user; + CMString host; + CMString away = GetWord(p1, 3); + + while ( !away.IsEmpty()) { + nick = GetWord(p1, 0); + user = GetWord(p1, 1); + host = GetWord(p1, 2); + if (( DBWildcard && WCCmp( DBWildcard, nick.c_str()) || DBNick && !lstrcmpi(DBNick, nick.c_str()) || DBDefault && !lstrcmpi(DBDefault, nick.c_str())) + && (WCCmp(DBUser, user.c_str()) && WCCmp(DBHost, host.c_str()))) + { + if (away[0] == 'G' && getWord( hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_AWAY) + setWord(hContact, "Status", ID_STATUS_AWAY); + else if (away[0] == 'H' && getWord( hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_ONLINE) + setWord(hContact, "Status", ID_STATUS_ONLINE); + + if (( DBNick && lstrcmpi( nick.c_str(), DBNick)) || !DBNick ) + setTString( hContact, "Nick", nick.c_str()); + if (( DBManUser && lstrcmpi( user.c_str(), DBManUser)) || !DBManUser ) + setTString( hContact, "User", user.c_str()); + if (( DBManHost && lstrcmpi(host.c_str(), DBManHost)) || !DBManHost ) + setTString(hContact, "Host", host.c_str()); + + goto LBL_Exit; + } + p1 = GetWordAddress(p1, 4); + away = GetWord(p1, 3); + } + + if ( DBWildcard && DBNick && !WCCmp( CharLower( DBWildcard ), CharLower( DBNick ))) { + setTString(hContact, "Nick", DBDefault); + + DoUserhostWithReason(2, ((CMString)_T("S") + DBWildcard).c_str(), true, DBWildcard); + + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + goto LBL_Exit; + } + + if ( getWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE ) { + setWord(hContact, "Status", ID_STATUS_OFFLINE); + setTString(hContact, "Nick", DBDefault); + setString(hContact, "User", ""); + setString(hContact, "Host", ""); + } +LBL_Exit: + if ( DBDefault ) DBFreeVariant(&dbv1); + if ( DBNick ) DBFreeVariant(&dbv2); + if ( DBWildcard ) DBFreeVariant(&dbv3); + if ( DBUser ) DBFreeVariant(&dbv4); + if ( DBHost ) DBFreeVariant(&dbv5); + if ( DBManUser ) DBFreeVariant(&dbv6); + if ( DBManHost ) DBFreeVariant(&dbv7); + } + mir_free( UserList ); + } + } + else ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_WHO_REPLY( const CIrcMessage* pmsg ) +{ + CMString command = PeekAtReasons(2); + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 6 && command[0] == 'S' ) { + m_whoReply.AppendFormat( _T("%s %s %s %s "), pmsg->parameters[5].c_str(), pmsg->parameters[2].c_str(), pmsg->parameters[3].c_str(), pmsg->parameters[6].c_str()); + if ( lstrcmpi( pmsg->parameters[5].c_str(), m_info.sNick.c_str()) == 0 ) { + TCHAR host[1024]; + lstrcpyn( host, pmsg->parameters[3].c_str(), 1024 ); + ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( _T2A(host), IP_AUTO )); + } } + + if ( command[0] == 'U' ) + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_TRYAGAIN( const CIrcMessage* pmsg ) +{ + CMString command = _T(""); + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 1 ) { + if ( pmsg->parameters[1] == _T("WHO")) + command = GetNextUserhostReason(2); + + if ( pmsg->parameters[1] == _T("USERHOST")) + command = GetNextUserhostReason(1); + } + if (command[0] == 'U') + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_USERHOST_REPLY( const CIrcMessage* pmsg ) +{ + CMString command = _T(""); + if ( pmsg->m_bIncoming ) { + command = GetNextUserhostReason(1); + if ( !command.IsEmpty() && command != _T("U") && pmsg->parameters.getCount() > 1 ) { + CONTACT finduser = {NULL, NULL, NULL, false, false, false}; + TCHAR* p1 = NULL; + TCHAR* p2 = NULL; + int awaystatus = 0; + CMString sTemp; + CMString host; + CMString user; + CMString nick; + CMString mask; + CMString mess; + CMString channel; + int i; + int j; + + // Status-check pre-processing: Setup check-list + OBJLIST checklist( 10 ); + if ( command[0] == 'S' ) { + j = 0; + sTemp = GetWord(command.c_str(), 0); + sTemp.Delete(0,1); + while ( !sTemp.IsEmpty()) { + checklist.insert( new CMString( sTemp )); + j++; + sTemp = GetWord(command.c_str(), j); + } } + + // Cycle through results + j = 0; + sTemp = GetWord( pmsg->parameters[1].c_str(), j ); + while ( !sTemp.IsEmpty()) { + p1 = mir_tstrdup( sTemp.c_str()); + p2 = p1; + + // Pull out host, user and nick + p2 = _tcschr(p1, '@'); + if ( p2 ) { + *p2 = '\0'; + p2++; + host = p2; + } + p2 = _tcschr(p1, '='); + if ( p2 ) { + if (*(p2-1) == '*') + *(p2-1) = '\0'; // remove special char for IRCOps + *p2 = '\0'; + p2++; + awaystatus = *p2; + p2++; + user = p2; + nick = p1; + } + mess = _T(""); + mask = nick + _T("!") + user + _T("@") + host; + if ( host.IsEmpty() || user.IsEmpty() || nick.IsEmpty()) { + mir_free( p1 ); + continue; + } + + // Do command + switch ( command[0] ) { + case 'S': // Status check + { + finduser.name = (TCHAR*)nick.c_str(); + finduser.host = (TCHAR*)host.c_str(); + finduser.user = (TCHAR*)user.c_str(); + + HANDLE hContact = CList_FindContact(&finduser); + if ( hContact && getByte( hContact, "AdvancedMode", 0 ) == 0 ) { + setWord(hContact, "Status", awaystatus == '-'? ID_STATUS_AWAY : ID_STATUS_ONLINE); + setTString(hContact, "User", user.c_str()); + setTString(hContact, "Host", host.c_str()); + setTString(hContact, "Nick", nick.c_str()); + + // If user found, remove from checklist + for ( i = 0; i < checklist.getCount(); i++ ) + if ( !lstrcmpi(checklist[i].c_str(), nick.c_str())) + checklist.remove( i ); + } + break; + } + case 'I': // m_ignore + mess = _T("/IGNORE %question=\""); + mess += TranslateT("Please enter the hostmask (nick!user@host)\nNOTE! Contacts on your contact list are never ignored"); + mess += (CMString)_T("\",\"") + TranslateT("Ignore") + _T("\",\"*!*@") + host + _T("\""); + if ( m_ignoreChannelDefault ) + mess += _T(" +qnidcm"); + else + mess += _T(" +qnidc"); + break; + + case 'J': // Unignore + mess = _T("/UNIGNORE *!*@") + host; + break; + + case 'B': // Ban + channel = (command.c_str() + 1); + mess = _T("/MODE ") + channel + _T(" +b *!*@") + host; + break; + + case 'K': // Ban & Kick + channel = (command.c_str() + 1); + mess.Format( _T("/MODE %s +b *!*@%s%%newl/KICK %s %s"), channel.c_str(), host.c_str(), channel.c_str(), nick.c_str()); + break; + + case 'L': // Ban & Kick with reason + channel = (command.c_str() + 1); + mess.Format( _T("/MODE %s +b *!*@%s%%newl/KICK %s %s %%question=\"%s\",\"%s\",\"%s\""), + channel.c_str(), host.c_str(), channel.c_str(), nick.c_str(), + TranslateT("Please enter the reason"), TranslateT("Ban'n Kick"), TranslateT("Jerk")); + break; + } + + mir_free( p1 ); + + // Post message + if ( !mess.IsEmpty()) + PostIrcMessageWnd( NULL, NULL, mess.c_str()); + j++; + sTemp = GetWord(pmsg->parameters[1].c_str(), j); + } + + // Status-check post-processing: make buddies in ckeck-list offline + if ( command[0] == 'S' ) { + for ( i = 0; i < checklist.getCount(); i++ ) { + finduser.name = (TCHAR*)checklist[i].c_str(); + finduser.ExactNick = true; + CList_SetOffline( &finduser ); + } } + + return true; + } } + + if ( !pmsg->m_bIncoming || command == _T("U")) + ShowMessage( pmsg ); + return true; +} + +bool CIrcProto::OnIrc_SUPPORT( const CIrcMessage* pmsg ) +{ + static const TCHAR* lpszFmt = _T("Try server %99[^ ,], port %19s"); + TCHAR szAltServer[100]; + TCHAR szAltPort[20]; + if ( pmsg->parameters.getCount() > 1 && _stscanf(pmsg->parameters[1].c_str(), lpszFmt, &szAltServer, &szAltPort) == 2 ) { + ShowMessage( pmsg ); + lstrcpynA( m_serverName, _T2A(szAltServer), 99 ); + lstrcpynA( m_portStart, _T2A(szAltPort), 9 ); + + m_noOfChannels = 0; + ConnectToServer(); + return true; + } + + if ( pmsg->m_bIncoming && !bPerformDone ) + DoOnConnect(pmsg); + + if ( pmsg->m_bIncoming && pmsg->parameters.getCount() > 0 ) { + CMString S; + for ( int i = 0; i < pmsg->parameters.getCount(); i++ ) { + TCHAR* temp = mir_tstrdup( pmsg->parameters[i].c_str()); + if ( _tcsstr( temp, _T("CHANTYPES="))) { + TCHAR* p1 = _tcschr( temp, '=' ); + p1++; + if ( lstrlen( p1 ) > 0 ) + sChannelPrefixes = p1; + } + if ( _tcsstr(temp, _T("CHANMODES="))) { + TCHAR* p1 = _tcschr( temp, '=' ); + p1++; + if ( lstrlen( p1 ) > 0) + sChannelModes = ( char* )_T2A( p1 ); + } + if ( _tcsstr( temp, _T("PREFIX="))) { + TCHAR* p1 = _tcschr( temp, '(' ); + TCHAR* p2 = _tcschr( temp, ')' ); + if ( p1 && p2 ) { + p1++; + if ( p1 != p2 ) + sUserModes = ( char* )_T2A( p1 ); + sUserModes = sUserModes.Mid(0, p2-p1); + p2++; + if ( *p2 != '\0' ) + sUserModePrefixes = p2; + } + else { + p1 = _tcschr( temp, '=' ); + p1++; + sUserModePrefixes = p1; + for ( int i =0; i < sUserModePrefixes.GetLength()+1; i++ ) { + if ( sUserModePrefixes[i] == '@' ) + sUserModes.SetAt( i, 'o' ); + else if ( sUserModePrefixes[i] == '+' ) + sUserModes.SetAt( i, 'v' ); + else if ( sUserModePrefixes[i] == '-' ) + sUserModes.SetAt( i, 'u' ); + else if ( sUserModePrefixes[i] == '%' ) + sUserModes.SetAt( i, 'h' ); + else if ( sUserModePrefixes[i] == '!' ) + sUserModes.SetAt( i, 'a' ); + else if ( sUserModePrefixes[i] == '*' ) + sUserModes.SetAt( i, 'q' ); + else if ( sUserModePrefixes[i] == '\0' ) + sUserModes.SetAt( i, '\0' ); + else + sUserModes.SetAt( i, '_' ); + } } } + + mir_free( temp ); + } } + + ShowMessage( pmsg ); + return true; +} + +void CIrcProto::OnIrcDefault( const CIrcMessage* pmsg ) +{ + ShowMessage( pmsg ); +} + +void CIrcProto::OnIrcDisconnected() +{ + m_statusMessage = _T(""); + DBDeleteContactSetting(NULL, m_szModuleName, "JTemp"); + bTempDisableCheck = false; + bTempForceCheck = false; + m_iTempCheckTime = 0; + + m_myHost[0] = '\0'; + + int Temp = m_iStatus; + KillIdent(); + KillChatTimer( OnlineNotifTimer ); + KillChatTimer( OnlineNotifTimer3 ); + KillChatTimer( KeepAliveTimer ); + KillChatTimer( InitTimer ); + KillChatTimer( IdentTimer ); + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp, ID_STATUS_OFFLINE); + + CMString sDisconn = _T("\0035\002"); + sDisconn += TranslateT("*Disconnected*"); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, sDisconn.c_str(), NULL, NULL, NULL, true, false); + + { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gce.cbSize = sizeof(GCEVENT); + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_OFFLINE, (LPARAM)&gce); + } + + if ( !Miranda_Terminated()) + CList_SetAllOffline( m_disconnectDCCChats ); + + // restore the original nick, cause it might be changed + memcpy( m_nick, m_pNick, sizeof( m_nick )); + setTString( "Nick", m_pNick ); + + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS | CMIF_GRAYED; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoin, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuList, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuNick, ( LPARAM )&clmi ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnConnect + +static void __stdcall sttMainThrdOnConnect( void* param ) +{ + CIrcProto* ppro = ( CIrcProto* )param; + + ppro->SetChatTimer( ppro->InitTimer, 1*1000, TimerProc ); + if ( ppro->m_identTimer ) + ppro->SetChatTimer( ppro->IdentTimer, 60*1000, IdentTimerProc ); + if ( ppro->m_sendKeepAlive ) + ppro->SetChatTimer( ppro->KeepAliveTimer, 60*1000, KeepAliveTimerProc ); + if ( ppro->m_autoOnlineNotification && !ppro->bTempDisableCheck || ppro->bTempForceCheck ) { + ppro->SetChatTimer( ppro->OnlineNotifTimer, 1000, OnlineNotifTimerProc ); + if ( ppro->m_channelAwayNotification ) + ppro->SetChatTimer( ppro->OnlineNotifTimer3, 3000, OnlineNotifTimerProc3); +} } + +bool CIrcProto::DoOnConnect( const CIrcMessage* ) +{ + bPerformDone = true; + nickflag = true; + + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoin, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuList, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuNick, ( LPARAM )&clmi ); + + int Temp = m_iStatus; + m_iStatus = ID_STATUS_ONLINE; + ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE )Temp, m_iStatus ); + + if ( m_iDesiredStatus == ID_STATUS_AWAY ) + PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); + + if ( m_perform ) { + DoPerform( "ALL NETWORKS" ); + if ( IsConnected()) { + DoPerform( _T2A( m_info.sNetwork.c_str())); + switch( m_iStatus ) { + case ID_STATUS_FREECHAT: DoPerform( "Event: Free for chat" ); break; + case ID_STATUS_ONLINE: DoPerform( "Event: Available" ); break; + } } } + + if ( m_rejoinChannels ) { + int count = CallServiceSync( MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_szModuleName); + for ( int i = 0; i < count ; i++ ) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX | DATA | NAME | TYPE; + gci.iItem = i; + gci.pszModule = m_szModuleName; + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci) && gci.iType == GCW_CHATROOM ) { + CHANNELINFO* wi = ( CHANNELINFO* )gci.dwItemData; + if ( wi && wi->pszPassword ) + PostIrcMessage( _T("/JOIN %s %s"), gci.pszName, wi->pszPassword); + else + PostIrcMessage( _T("/JOIN %s"), gci.pszName); + } } } + + DoEvent( GC_EVENT_ADDGROUP, SERVERWINDOW, NULL, NULL, _T("Normal"), NULL, NULL, FALSE, TRUE); + { + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gce.dwFlags = GC_TCHAR; + gce.cbSize = sizeof(GCEVENT); + gcd.ptszID = SERVERWINDOW; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + gce.pDest = &gcd; + CallChatEvent( SESSION_ONLINE, (LPARAM)&gce); + } + + CallFunctionAsync( sttMainThrdOnConnect, this ); + nickflag = false; + return 0; +} + +static void __cdecl AwayWarningThread(LPVOID) +{ + MessageBox(NULL, TranslateT("The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically."), TranslateT("IRC Error"), MB_OK); +} + +int CIrcProto::DoPerform( const char* event ) +{ + String sSetting = String("PERFORM:") + event; + sSetting.MakeUpper(); + + DBVARIANT dbv; + if ( !getTString( sSetting.c_str(), &dbv )) { + if ( !my_strstri( dbv.ptszVal, _T("/away"))) + PostIrcMessageWnd( NULL, NULL, dbv.ptszVal ); + else + mir_forkthread( AwayWarningThread, NULL ); + DBFreeVariant( &dbv ); + return 1; + } + return 0; +} + +int CIrcProto::IsIgnored( const CMString& nick, const CMString& address, const CMString& host, char type) +{ + return IsIgnored( nick + _T("!") + address + _T("@") + host, type ); +} + +int CIrcProto::IsIgnored( CMString user, char type ) +{ + for ( int i=0; i < m_ignoreItems.getCount(); i++ ) { + const CIrcIgnoreItem& C = m_ignoreItems[i]; + + if ( type == '\0' ) + if ( !lstrcmpi( user.c_str(), C.mask.c_str())) + return i+1; + + bool bUserContainsWild = ( _tcschr( user.c_str(), '*') != NULL || _tcschr( user.c_str(), '?' ) != NULL ); + if ( !bUserContainsWild && WCCmp( C.mask.c_str(), user.c_str()) || + bUserContainsWild && !lstrcmpi( user.c_str(), C.mask.c_str())) + { + if ( C.flags.IsEmpty() || C.flags[0] != '+' ) + continue; + + if ( !_tcschr( C.flags.c_str(), type )) + continue; + + if ( C.network.IsEmpty()) + return i+1; + + if ( IsConnected() && !lstrcmpi( C.network.c_str(), m_info.sNetwork.c_str())) + return i+1; + } } + + return 0; +} + +bool CIrcProto::AddIgnore( const TCHAR* mask, const TCHAR* flags, const TCHAR* network ) +{ + RemoveIgnore( mask ); + m_ignoreItems.insert( new CIrcIgnoreItem( mask, (_T("+") + CMString(flags)).c_str(), network )); + RewriteIgnoreSettings(); + + if ( m_ignoreDlg ) + m_ignoreDlg->RebuildList(); + return true; +} + +bool CIrcProto::RemoveIgnore( const TCHAR* mask ) +{ + int idx; + while (( idx = IsIgnored( mask, '\0')) != 0 ) + m_ignoreItems.remove( idx-1 ); + + RewriteIgnoreSettings(); + + if ( m_ignoreDlg ) + m_ignoreDlg->RebuildList(); + return true; +} diff --git a/protocols/IRCG/src/commandmonitor.h b/protocols/IRCG/src/commandmonitor.h new file mode 100644 index 0000000000..940cb9cc02 --- /dev/null +++ b/protocols/IRCG/src/commandmonitor.h @@ -0,0 +1,22 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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. +*/ + +using namespace irc; diff --git a/protocols/IRCG/src/input.cpp b/protocols/IRCG/src/input.cpp new file mode 100644 index 0000000000..c564b7844c --- /dev/null +++ b/protocols/IRCG/src/input.cpp @@ -0,0 +1,936 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" +#include "version.h" + +#define NICKSUBSTITUTE _T("!_nick_!") + +void CIrcProto::FormatMsg(CMString& text) +{ + TCHAR temp[30]; + lstrcpyn(temp, GetWord(text.c_str(), 0).c_str(), 29); + CharLower(temp); + CMString command = temp; + CMString S = _T(""); + if (command == _T("/quit") || command == _T("/away")) + S = GetWord(text.c_str(), 0) + _T(" :") + GetWordAddress(text.c_str(), 1); + else if (command == _T("/privmsg") || command == _T("/part") || command == _T("/topic") || command == _T("/notice")) { + S = GetWord(text.c_str(), 0) + _T(" ") + GetWord(text.c_str(), 1) + _T(" :"); + if (!GetWord(text.c_str(), 2).IsEmpty()) + S += CMString(GetWordAddress(text.c_str(), 2)); + } + else if (command == _T("/kick")) { + S = GetWord(text.c_str(), 0) + _T(" ") + GetWord(text.c_str(), 1) + _T(" ") + GetWord(text.c_str(), 2) + _T(" :") + GetWordAddress(text.c_str(), 3); + } + else if (command == _T("/nick")) { + if ( !_tcsstr(GetWord(text.c_str(), 1).c_str(), NICKSUBSTITUTE )) { + sNick4Perform = GetWord(text.c_str(), 1); + S = GetWordAddress(text.c_str(), 0); + } + else { + CMString sNewNick = GetWord(text.c_str(), 1); + if ( sNick4Perform == _T("")) { + DBVARIANT dbv; + if ( !getTString( "PNick", &dbv )) { + sNick4Perform = dbv.ptszVal; + DBFreeVariant(&dbv); + } } + + ReplaceString( sNewNick, NICKSUBSTITUTE, sNick4Perform.c_str()); + S = GetWord(text.c_str(), 0) + _T(" ") + sNewNick; + } + } + else S = GetWordAddress(text.c_str(), 0); + + S.Delete(0,1); + text = S; +} + +static void AddCR( CMString& text ) +{ + ReplaceString( text, _T("\n"), _T("\r\n")); + ReplaceString( text, _T("\r\r"), _T("\r")); +} + +CMString CIrcProto::DoAlias( const TCHAR *text, TCHAR *window) +{ + CMString Messageout = _T(""); + const TCHAR* p1 = text; + const TCHAR* p2 = text; + bool LinebreakFlag = false, hasAlias = false; + p2 = _tcsstr(p1, _T("\r\n")); + if ( !p2 ) + p2 = _tcschr(p1, '\0'); + if ( p1 == p2 ) + return (CMString)text; + + do { + if ( LinebreakFlag ) + Messageout += _T("\r\n"); + + TCHAR* line = new TCHAR[p2-p1 +1]; + lstrcpyn(line, p1, p2-p1+1); + TCHAR* test = line; + while ( *test == ' ' ) + test++; + if ( *test == '/' ) { + lstrcpyn(line, GetWordAddress(line, 0), p2-p1+1); + CMString S = line; + delete [] line; + line = new TCHAR[S.GetLength()+2]; + lstrcpyn(line, S.c_str(), S.GetLength()+1); + CMString alias( m_alias ); + const TCHAR* p3 = _tcsstr( alias.c_str(), (GetWord(line, 0)+ _T(" ")).c_str()); + if ( p3 != alias.c_str()) { + CMString S = _T("\r\n"); + S += GetWord(line, 0) + _T(" "); + p3 = _tcsstr( alias.c_str(), S.c_str()); + if ( p3 ) + p3 += 2; + } + if ( p3 != NULL ) { + hasAlias = true; + const TCHAR* p4 = _tcsstr( p3, _T("\r\n")); + if ( !p4 ) + p4 = _tcschr( p3, '\0' ); + + *( TCHAR* )p4 = 0; + CMString S = p3; + ReplaceString( S, _T("##"), window ); + ReplaceString( S, _T("$?"), _T("%question")); + + for ( int index = 1; index < 8; index++ ) { + TCHAR str[5]; + mir_sntprintf( str, SIZEOF(str), _T("#$%u"), index ); + if ( !GetWord(line, index).IsEmpty() && IsChannel( GetWord( line, index ))) + ReplaceString( S, str, GetWord(line, index).c_str()); + else { + CMString S1 = _T("#"); + S1 += GetWord( line, index ); + ReplaceString( S, str, S1.c_str()); + } + } + for ( int index2 = 1; index2 <8; index2++ ) { + TCHAR str[5]; + mir_sntprintf( str, SIZEOF(str), _T("$%u-"), index2 ); + ReplaceString( S, str, GetWordAddress( line, index2 )); + } + for ( int index3 = 1; index3 <8; index3++ ) { + TCHAR str[5]; + mir_sntprintf( str, SIZEOF(str), _T("$%u"), index3 ); + ReplaceString( S, str, GetWord(line, index3).c_str()); + } + Messageout += GetWordAddress(S.c_str(), 1); + } + else Messageout += line; + } + else Messageout += line; + + p1 = p2; + if ( *p1 == '\r' ) + p1 += 2; + p2 = _tcsstr( p1, _T("\r\n")); + if ( !p2 ) + p2 = _tcschr( p1, '\0' ); + delete [] line; + LinebreakFlag = true; + } + while ( *p1 != '\0'); + + return hasAlias ? DoIdentifiers(Messageout, window) : Messageout; +} + +CMString CIrcProto::DoIdentifiers( CMString text, const TCHAR* ) +{ + SYSTEMTIME time; + TCHAR str[2]; + + GetLocalTime( &time ); + ReplaceString( text, _T("%mnick"), m_nick); + ReplaceString( text, _T("%anick"), m_alternativeNick); + ReplaceString( text, _T("%awaymsg"), m_statusMessage.c_str()); + ReplaceString( text, _T("%module"), _A2T(m_szModuleName)); + ReplaceString( text, _T("%name"), m_name); + ReplaceString( text, _T("%newl"), _T("\r\n")); + ReplaceString( text, _T("%network"), m_info.sNetwork.c_str()); + ReplaceString( text, _T("%me"), m_info.sNick.c_str()); + + char mirver[100]; + CallService(MS_SYSTEM_GETVERSIONTEXT, SIZEOF(mirver), LPARAM(mirver)); + ReplaceString(text, _T("%mirver"), _A2T(mirver)); + + ReplaceString(text, _T("%version"), _T(__VERSION_STRING)); + + str[0] = 3; str[1] = '\0'; + ReplaceString(text, _T("%color"), str); + + str[0] = 2; + ReplaceString(text, _T("%bold"), str); + + str[0] = 31; + ReplaceString(text, _T("%underline"), str); + + str[0] = 22; + ReplaceString(text, _T("%italics"), str); + return text; +} + +static void __stdcall sttSetTimerOn( void* _pro ) +{ + CIrcProto* ppro = ( CIrcProto* )_pro; + ppro->DoEvent( GC_EVENT_INFORMATION, NULL, ppro->m_info.sNick.c_str(), TranslateT( "The buddy check function is enabled"), NULL, NULL, NULL, true, false); + ppro->SetChatTimer( ppro->OnlineNotifTimer, 500, OnlineNotifTimerProc ); + if ( ppro->m_channelAwayNotification ) + ppro->SetChatTimer( ppro->OnlineNotifTimer3, 1500, OnlineNotifTimerProc3 ); +} + +static void __stdcall sttSetTimerOff( void* _pro ) +{ + CIrcProto* ppro = ( CIrcProto* )_pro; + ppro->DoEvent( GC_EVENT_INFORMATION, NULL, ppro->m_info.sNick.c_str(), TranslateT("The buddy check function is disabled"), NULL, NULL, NULL, true, false); + ppro->KillChatTimer( ppro->OnlineNotifTimer ); + ppro->KillChatTimer( ppro->OnlineNotifTimer3 ); +} + +BOOL CIrcProto::DoHardcodedCommand( CMString text, TCHAR* window, HANDLE hContact ) +{ + TCHAR temp[30]; + lstrcpyn(temp, GetWord(text.c_str(), 0).c_str(), 29 ); + CharLower(temp); + CMString command = temp; + CMString one = GetWord(text.c_str(), 1); + CMString two = GetWord(text.c_str(), 2); + CMString three = GetWord(text.c_str(), 3); + CMString therest = GetWordAddress(text.c_str(), 4); + + if ( command == _T("/servershow") || command == _T("/serverhide")) { + if ( m_useServer ) { + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gce.dwFlags = GC_TCHAR; + gcd.iType = GC_EVENT_CONTROL; + gcd.ptszID = SERVERWINDOW; + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + CallChatEvent( command == _T("/servershow") ? WINDOW_VISIBLE : WINDOW_HIDDEN, (LPARAM)&gce); + } + return true; + } + + else if (command == _T("/sleep") || command == _T("/wait")) { + if (!one.IsEmpty()) { + int ms; + if (_stscanf(one.c_str(), _T("%d"), &ms) == 1 && ms > 0 && ms <= 4000) + Sleep(ms); + else + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Incorrect parameters. Usage: /sleep [ms], ms should be greater than 0 and less than 4000."), NULL, NULL, NULL, true, false); + } + return true; + } + + if (command == _T("/clear")) { + CMString S; + if ( !one.IsEmpty()) { + if ( one == _T("server")) + S = SERVERWINDOW; + else + S = MakeWndID( one.c_str()); + } + else if ( lstrcmpi( window, SERVERWINDOW) == 0 ) + S = window; + else + S = MakeWndID( window ); + + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gce.cbSize = sizeof(GCEVENT); + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + gcd.ptszID = (TCHAR*)S.c_str(); + CallChatEvent( WINDOW_CLEARLOG, (LPARAM)&gce); + return true; + } + + if ( command == _T("/ignore")) { + if ( IsConnected()) { + CMString IgnoreFlags; + TCHAR temp[500]; + if ( one.IsEmpty()) { + if ( m_ignore ) + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is enabled"), NULL, NULL, NULL, true, false); + else + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is disabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !lstrcmpi( one.c_str(), _T("on"))) { + m_ignore = 1; + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is enabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !lstrcmpi( one.c_str(), _T("off"))) { + m_ignore = 0; + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Ignore system is disabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !_tcschr( one.c_str(), '!' ) && !_tcschr( one.c_str(), '@' )) + one += _T("!*@*"); + + if ( !two.IsEmpty() && two[0] == '+' ) { + if ( _tcschr( two.c_str(), 'q')) + IgnoreFlags += 'q'; + if ( _tcschr( two.c_str(), 'n')) + IgnoreFlags += 'n'; + if ( _tcschr( two.c_str(), 'i')) + IgnoreFlags += 'i'; + if ( _tcschr( two.c_str(), 'd')) + IgnoreFlags += 'd'; + if ( _tcschr( two.c_str(), 'c')) + IgnoreFlags += 'c'; + if ( _tcschr( two.c_str(), 'm')) + IgnoreFlags += 'm'; + } + else IgnoreFlags = _T("qnidc"); + + CMString m_network; + if ( three.IsEmpty()) + m_network = m_info.sNetwork; + else + m_network = three; + + AddIgnore( one.c_str(), IgnoreFlags.c_str(), m_network.c_str()); + + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s on %s is now ignored (+%s)"), one.c_str(), m_network.c_str(), IgnoreFlags.c_str()); + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + } + return true; + } + + if (command == _T("/unignore")) { + if ( !_tcschr( one.c_str(), '!' ) && !_tcschr(one.c_str(), '@')) + one += _T("!*@*"); + + TCHAR temp[500]; + if ( RemoveIgnore( one.c_str())) + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s is not ignored now"), one.c_str()); + else + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s was not ignored"), one.c_str()); + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + return true; + } + + if ( command == _T("/userhost")) { + if ( one.IsEmpty()) + return true; + + DoUserhostWithReason( 1, _T("U"), false, temp ); + return false; + } + + if ( command == _T("/joinx")) { + if ( !one.IsEmpty()) { + for ( int i=1; ; i++ ) { + CMString tmp = GetWord( text.c_str(), i ); + if ( tmp.IsEmpty()) + break; + + AddToJTemp( 'X', tmp ); + } + + PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); + } + return true; + } + + if ( command == _T("/joinm")) { + if ( !one.IsEmpty()) { + for ( int i=1; ; i++ ) { + CMString tmp = GetWord( text.c_str(), i ); + if ( tmp.IsEmpty()) + break; + + AddToJTemp( 'M', tmp ); + } + + PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); + } + return true; + } + + if (command == _T("/nusers")) { + TCHAR szTemp[40]; + CMString S = MakeWndID(window); + GC_INFO gci = {0}; + gci.Flags = BYID|NAME|COUNT; + gci.pszModule = m_szModuleName; + gci.pszID = (TCHAR*)S.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, ( LPARAM )&gci )) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("users: %u"), gci.iCount); + + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + return true; + } + + if (command == _T("/echo")) { + if ( one.IsEmpty()) + return true; + + if ( !lstrcmpi( one.c_str(), _T("on"))) { + bEcho = TRUE; + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Outgoing commands are shown"), NULL, NULL, NULL, true, false); + } + + if ( !lstrcmpi( one.c_str(), _T("off"))) { + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("Outgoing commands are not shown"), NULL, NULL, NULL, true, false); + bEcho = FALSE; + } + + return true; + } + + if (command == _T("/buddycheck")) { + if ( one.IsEmpty()) { + if (( m_autoOnlineNotification && !bTempDisableCheck) || bTempForceCheck ) + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The buddy check function is enabled"), NULL, NULL, NULL, true, false); + else + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The buddy check function is disabled"), NULL, NULL, NULL, true, false); + return true; + } + if ( !lstrcmpi( one.c_str(), _T("on"))) { + bTempForceCheck = true; + bTempDisableCheck = false; + CallFunctionAsync( sttSetTimerOn, this ); + } + if ( !lstrcmpi( one.c_str(), _T("off"))) { + bTempForceCheck = false; + bTempDisableCheck = true; + CallFunctionAsync( sttSetTimerOff, this ); + } + if ( !lstrcmpi( one.c_str(), _T("time")) && !two.IsEmpty()) { + m_iTempCheckTime = StrToInt( two.c_str()); + if ( m_iTempCheckTime < 10 && m_iTempCheckTime != 0 ) + m_iTempCheckTime = 10; + + if ( m_iTempCheckTime == 0 ) + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), TranslateT("The time interval for the buddy check function is now at default setting"), NULL, NULL, NULL, true, false); + else { + TCHAR temp[200]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("The time interval for the buddy check function is now %u seconds"), m_iTempCheckTime); + DoEvent( GC_EVENT_INFORMATION, NULL, m_info.sNick.c_str(), temp, NULL, NULL, NULL, true, false); + } } + return true; + } + + if (command == _T("/whois")) { + if ( one.IsEmpty()) + return false; + m_manualWhoisCount++; + return false; + } + + if ( command == _T("/channelmanager")) { + if ( window && !hContact && IsChannel( window )) { + if ( IsConnected()) { + if ( m_managerDlg != NULL ) { + SetActiveWindow( m_managerDlg->GetHwnd()); + m_managerDlg->Close(); + } + else { + m_managerDlg = new CManagerDlg( this ); + m_managerDlg->Show(); + m_managerDlg->InitManager( 1, window ); + } } } + + return true; + } + + if ( command == _T("/who")) { + if ( one.IsEmpty()) + return true; + + DoUserhostWithReason( 2, _T("U"), false, _T("%s"), one.c_str()); + return false; + } + + if (command == _T("/hop")) { + if ( !IsChannel( window )) + return true; + + PostIrcMessage( _T("/PART %s"), window ); + + if (( one.IsEmpty() || !IsChannel( one ))) { + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi && wi->pszPassword ) + PostIrcMessage( _T("/JOIN %s %s"), window, wi->pszPassword); + else + PostIrcMessage( _T("/JOIN %s"), window); + return true; + } + + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gcd.iType = GC_EVENT_CONTROL; + CMString S = MakeWndID(window); + gcd.ptszID = (TCHAR*)S.c_str(); + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + + PostIrcMessage( _T("/JOIN %s"), GetWordAddress(text.c_str(), 1)); + return true; + } + + if (command == _T("/list" )) { + if ( m_listDlg == NULL ) { + m_listDlg = new CListDlg( this ); + m_listDlg->Show(); + } + SetActiveWindow( m_listDlg->GetHwnd()); + int minutes = ( int )m_noOfChannels/4000; + int minutes2 = ( int )m_noOfChannels/9000; + + TCHAR text[256]; + mir_sntprintf( text, SIZEOF(text), TranslateT("This command is not recommended on a network of this size!\r\nIt will probably cause high CPU usage and/or high bandwidth\r\nusage for around %u to %u minute(s).\r\n\r\nDo you want to continue?"), minutes2, minutes); + if ( m_noOfChannels < 4000 || ( m_noOfChannels >= 4000 && MessageBox( NULL, text, TranslateT("IRC warning") , MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES)) { + ListView_DeleteAllItems( GetDlgItem( m_listDlg->GetHwnd(), IDC_INFO_LISTVIEW )); + PostIrcMessage( _T("/lusers" )); + return false; + } + m_listDlg->m_status.SetText( TranslateT("Aborted")); + return true; + } + + if (command == _T("/me")) { + if ( one.IsEmpty()) + return true; + + TCHAR szTemp[4000]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\001ACTION %s\001"), GetWordAddress(text.c_str(), 1)); + PostIrcMessageWnd( window, hContact, szTemp ); + return true; + } + + if (command == _T("/ame")) { + if ( one.IsEmpty()) + return true; + + CMString S = _T("/ME ") + DoIdentifiers(GetWordAddress(text.c_str(), 1), window); + ReplaceString( S, _T("%"), _T("%%")); + DoEvent( GC_EVENT_SENDMESSAGE, NULL, NULL, S.c_str(), NULL, NULL, NULL, FALSE, FALSE); + return true; + } + + if (command == _T("/amsg")) { + if ( one.IsEmpty()) + return true; + + CMString S = DoIdentifiers( GetWordAddress(text.c_str(), 1), window ); + ReplaceString( S, _T("%"), _T("%%")); + DoEvent( GC_EVENT_SENDMESSAGE, NULL, NULL, S.c_str(), NULL, NULL, NULL, FALSE, FALSE); + return true; + } + + if (command == _T("/msg")) { + if ( one.IsEmpty() || two.IsEmpty()) + return true; + + TCHAR szTemp[4000]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s"), GetWordAddress(text.c_str(), 1)); + + PostIrcMessageWnd(window, hContact, szTemp); + return true; + } + + if (command == _T("/query")) { + if ( one.IsEmpty() || IsChannel(one.c_str())) + return true; + + CONTACT user = { (TCHAR*)one.c_str(), NULL, NULL, false, false, false}; + HANDLE hContact2 = CList_AddContact(&user, false, false); + if ( hContact2 ) { + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) + DoUserhostWithReason(1, (_T("S") + one).c_str(), true, one.c_str()); + else { + DBVARIANT dbv1; + if ( !getTString( hContact, "UWildcard", &dbv1 )) { + CMString S = _T("S"); + S += dbv1.ptszVal; + DoUserhostWithReason(2, S.c_str(), true, dbv1.ptszVal); + DBFreeVariant(&dbv1); + } + else { + CMString S = _T("S"); + S += one; + DoUserhostWithReason(2, S.c_str(), true, one.c_str()); + } } + + CallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact2, 0 ); + } + + if ( !two.IsEmpty()) { + TCHAR szTemp[4000]; + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s"), GetWordAddress(text.c_str(), 1)); + PostIrcMessageWnd( window, hContact, szTemp ); + } + return true; + } + + if (command == _T("/ctcp")) { + if ( one.IsEmpty() || two.IsEmpty()) + return true; + + TCHAR szTemp[1000]; + unsigned long ulAdr = 0; + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + // if it is not dcc or if it is dcc and a local ip exist + if ( lstrcmpi( two.c_str(), _T("dcc")) != 0 || ulAdr ) { + if ( lstrcmpi( two.c_str(), _T("ping")) == 0 ) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s \001%s %u\001"), one.c_str(), two.c_str(), time(0)); + else + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("/PRIVMSG %s \001%s\001"), one.c_str(), GetWordAddress(text.c_str(), 2)); + PostIrcMessageWnd( window, hContact, szTemp ); + } + + if ( lstrcmpi(two.c_str(), _T("dcc")) != 0 ) { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("CTCP %s request sent to %s"), two.c_str(), one.c_str()); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + + return true; + } + + if (command == _T("/dcc")) { + if ( one.IsEmpty() || two.IsEmpty()) + return true; + + if ( lstrcmpi( one.c_str(), _T("send")) == 0 ) { + TCHAR szTemp[1000]; + unsigned long ulAdr = 0; + + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + if ( ulAdr ) { + CONTACT user = { (TCHAR*)two.c_str(), NULL, NULL, false, false, true }; + HANDLE hContact = CList_AddContact( &user, false, false ); + if ( hContact ) { + CMString s; + + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) + DoUserhostWithReason( 1, (_T("S") + two).c_str(), true, two.c_str()); + else { + DBVARIANT dbv1; + CMString S = _T("S"); + if ( !getTString( hContact, "UWildcard", &dbv1 )) { + S += dbv1.ptszVal; + DoUserhostWithReason(2, S.c_str(), true, dbv1.ptszVal ); + DBFreeVariant( &dbv1 ); + } + else { + S += two; + DoUserhostWithReason( 2, S.c_str(), true, two.c_str()); + } } + + if ( three.IsEmpty()) + CallService( MS_FILE_SENDFILE, ( WPARAM )hContact, 0 ); + else { + CMString temp = GetWordAddress(text.c_str(), 3); + TCHAR* pp[2]; + TCHAR* p = ( TCHAR* )temp.c_str(); + pp[0] = p; + pp[1] = NULL; + CallService( MS_FILE_SENDSPECIFICFILES, (WPARAM)hContact, (LPARAM)pp ); + } } + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to automatically resolve external IP")); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + return true; + } + + if ( lstrcmpi( one.c_str(), _T("chat")) == 0 ) { + TCHAR szTemp[1000]; + + unsigned long ulAdr = 0; + if ( m_manualHost ) + ulAdr = ConvertIPToInteger( m_mySpecifiedHostIP ); + else + ulAdr = ConvertIPToInteger( m_IPFromServer ? m_myHost : m_myLocalHost ); + + if ( ulAdr ) { + CMString contact = two; contact += _T(DCCSTRING); + CONTACT user = { (TCHAR*)contact.c_str(), NULL, NULL, false, false, true}; + HANDLE hContact = CList_AddContact( &user, false, false ); + setByte(hContact, "DCC", 1); + + int iPort = 0; + if ( hContact ) { + DCCINFO* dci = new DCCINFO; + dci->hContact = hContact; + dci->sContactName = two; + dci->iType = DCC_CHAT; + dci->bSender = true; + + CDccSession* dcc = new CDccSession(this, dci); + CDccSession* olddcc = FindDCCSession(hContact); + if ( olddcc ) + olddcc->Disconnect(); + AddDCCSession(hContact, dcc); + iPort = dcc->Connect(); + } + + if ( iPort != 0 ) { + PostIrcMessage( _T("/CTCP %s DCC CHAT chat %u %u"), two.c_str(), ulAdr, iPort ); + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC CHAT request sent to %s"), two.c_str(), one.c_str()); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to bind port")); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } + } + else { + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("DCC ERROR: Unable to automatically resolve external IP")); + DoEvent( GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + } } + return true; + } + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct DoInputRequestParam +{ + DoInputRequestParam( CIrcProto* _pro, const TCHAR* _str ) : + ppro( _pro ), + str( mir_tstrdup( _str )) + {} + + CIrcProto* ppro; + TCHAR* str; +}; + +static void __stdcall DoInputRequestAliasApcStub( void* _par ) +{ + DoInputRequestParam* param = ( DoInputRequestParam* )_par; + CIrcProto* ppro = param->ppro; + TCHAR* str = param->str; + + TCHAR* infotext = NULL; + TCHAR* title = NULL; + TCHAR* defaulttext = NULL; + CMString command = ( TCHAR* )str; + TCHAR* p = _tcsstr(( TCHAR* )str, _T("%question")); + if ( p[9] == '=' && p[10] == '\"' ) { + infotext = &p[11]; + p = _tcschr( infotext, '\"' ); + if ( p ) { + *p = '\0'; + p++; + if ( *p == ',' && p[1] == '\"' ) { + p++; p++; + title = p; + p = _tcschr( title, '\"' ); + if ( p ) { + *p = '\0'; + p++; + if ( *p == ',' && p[1] == '\"' ) { + p++; p++; + defaulttext = p; + p = _tcschr( defaulttext, '\"' ); + if ( p ) + *p = '\0'; + } } } } } + + CQuestionDlg* dlg = new CQuestionDlg( ppro ); + dlg->Show(); + HWND question_hWnd = dlg->GetHwnd(); + + if ( title ) + SetDlgItemText( question_hWnd, IDC_CAPTION, title); + else + SetDlgItemText( question_hWnd, IDC_CAPTION, TranslateT("Input command")); + + if ( infotext ) + SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), infotext ); + else + SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), TranslateT("Please enter the reply")); + + if ( defaulttext ) + SetWindowText( GetDlgItem( question_hWnd, IDC_EDIT), defaulttext ); + + SetDlgItemText( question_hWnd, IDC_HIDDENEDIT, command.c_str()); + dlg->Activate(); + + mir_free( str ); + delete param; +} + +bool CIrcProto::PostIrcMessage( const TCHAR* fmt, ... ) +{ + if ( !fmt || lstrlen(fmt) < 1 || lstrlen(fmt) > 4000 ) + return 0; + + va_list marker; + va_start( marker, fmt ); + static TCHAR szBuf[4*1024]; + mir_vsntprintf( szBuf, SIZEOF(szBuf), fmt, marker ); + va_end( marker ); + + return PostIrcMessageWnd(NULL, NULL, szBuf); +} + +bool CIrcProto::PostIrcMessageWnd( TCHAR* window, HANDLE hContact, const TCHAR* szBuf ) +{ + DBVARIANT dbv; + TCHAR windowname[256]; + BYTE bDCC = 0; + + if ( hContact ) + bDCC = getByte( hContact, "DCC", 0 ); + + if ( !IsConnected() && !bDCC || !szBuf || lstrlen(szBuf) < 1 ) + return 0; + + if ( hContact && !getTString( hContact, "Nick", &dbv )) { + lstrcpyn( windowname, dbv.ptszVal, 255); + DBFreeVariant(&dbv); + } + else if ( window ) + lstrcpyn( windowname, window, 255 ); + else + lstrcpyn( windowname, SERVERWINDOW, 255 ); + + if ( lstrcmpi( window, SERVERWINDOW) != 0 ) { + TCHAR* p1 = _tcschr( windowname, ' ' ); + if ( p1 ) + *p1 = '\0'; + } + + // remove unecessary linebreaks, and do the aliases + CMString Message = szBuf; + AddCR( Message ); + RemoveLinebreaks( Message ); + if ( !hContact && IsConnected()) { + Message = DoAlias( Message.c_str(), windowname ); + + if ( Message.Find( _T("%question")) != -1 ) { + CallFunctionAsync( DoInputRequestAliasApcStub, new DoInputRequestParam( this, Message )); + return 1; + } + + ReplaceString( Message, _T("%newl"), _T("\r\n")); + RemoveLinebreaks( Message ); + } + + if ( Message.IsEmpty()) + return 0; + + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, windowname, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + int codepage = ( wi ) ? wi->codepage : getCodepage(); + + // process the message + while ( !Message.IsEmpty()) { + // split the text into lines, and do an automatic textsplit on long lies as well + bool flag = false; + CMString DoThis = _T(""); + int index = Message.Find( _T("\r\n"), 0 ); + if ( index == -1 ) + index = Message.GetLength(); + + if ( index > 464 ) + index = 432; + DoThis = Message.Mid(0, index); + Message.Delete(0, index); + if ( Message.Find( _T("\r\n"), 0 ) == 0 ) + Message.Delete( 0, 2 ); + + //do this if it's a /raw + if ( IsConnected() && ( GetWord(DoThis.c_str(), 0) == _T("/raw") || GetWord(DoThis.c_str(), 0) == _T("/quote"))) { + if ( GetWord( DoThis.c_str(), 1 ).IsEmpty()) + continue; + + CMString S = GetWordAddress( DoThis.c_str(), 1 ); + SendIrcMessage( S.c_str(), true, codepage ); + continue; + } + + // Do this if the message is not a command + if ( (GetWord( DoThis.c_str(), 0)[0] != '/') || // not a command + ( (GetWord( DoThis.c_str(), 0)[0] == '/') && (GetWord( DoThis.c_str(), 0)[1] == '/')) || // or double backslash at the beginning + hContact ) { + CMString S = _T("/PRIVMSG "); + if ( lstrcmpi(window, SERVERWINDOW) == 0 && !m_info.sServerName.IsEmpty()) + S += m_info.sServerName + _T(" ") + DoThis; + else + S += CMString(windowname) + _T(" ") + DoThis; + + DoThis = S; + flag = true; + } + + // and here we send it unless the command was a hardcoded one that should not be sent + if ( DoHardcodedCommand( DoThis, windowname, hContact )) + continue; + + if ( !IsConnected() && !bDCC ) + continue; + + if ( !flag && IsConnected()) + DoThis = DoIdentifiers(DoThis, windowname); + + if ( hContact ) { + if ( flag && bDCC ) { + CDccSession* dcc = FindDCCSession( hContact ); + if ( dcc ) { + FormatMsg( DoThis ); + CMString mess = GetWordAddress(DoThis.c_str(), 2); + if ( mess[0] == ':' ) + mess.Delete(0,1); + mess += '\n'; + dcc->SendStuff( mess.c_str()); + } + } + else if ( IsConnected()) { + FormatMsg( DoThis ); + SendIrcMessage( DoThis.c_str(), false, codepage ); + } + } + else { + FormatMsg( DoThis ); + SendIrcMessage( DoThis.c_str(), true, codepage ); + } } + + return 1; +} diff --git a/protocols/IRCG/src/irc.h b/protocols/IRCG/src/irc.h new file mode 100644 index 0000000000..9fe6584d87 --- /dev/null +++ b/protocols/IRCG/src/irc.h @@ -0,0 +1,725 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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. +*/ + +#ifndef _IRCWIN_H_ +#define _IRCWIN_H_ + +#define MIRANDA_VER 0x0A00 +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0501 + +#include "m_stdhdr.h" + +#define _CRT_SECURE_NO_WARNINGS + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "newpluginapi.h" +#include "m_system.h" +#include "m_system_cpp.h" +#include "m_protocols.h" +#include "m_protomod.h" +#include "m_protosvc.h" +#include "m_protoint.h" +#include "m_clist.h" +#include "m_options.h" +#include "m_database.h" +#include "m_utils.h" +#include "m_skin.h" +#include "m_netlib.h" +#include "m_clui.h" +#include "m_langpack.h" +#include "m_message.h" +#include "m_userinfo.h" +#include "m_addcontact.h" +#include "m_button.h" +#include "m_genmenu.h" +#include "m_file.h" +#include "m_ignore.h" +#include "m_chat.h" +#include "m_icolib.h" +#include "m_ircscript.h" +#include "win2k.h" + +#include "resource.h" + +#define IRC_QUICKCONNECT "/QuickConnectMenu" +#define IRC_JOINCHANNEL "/JoinChannelMenu" +#define IRC_CHANGENICK "/ChangeNickMenu" +#define IRC_SHOWLIST "/ShowListMenu" +#define IRC_SHOWSERVER "/ShowServerMenu" +#define IRC_UM_CHANSETTINGS "/UMenuChanSettings" +#define IRC_UM_WHOIS "/UMenuWhois" +#define IRC_UM_DISCONNECT "/UMenuDisconnect" +#define IRC_UM_IGNORE "/UMenuIgnore" + +#define STR_QUITMESSAGE "\002Miranda NG!\002 Smaller, Faster, Easier. http://miranda-ng.org/" +#define STR_USERINFO "I'm a happy Miranda NG user! Get it here: http://miranda-ng.org/" +#define STR_AWAYMESSAGE "I'm away from the computer." // Default away +#define DCCSTRING " (DCC)" +#define SERVERSMODULE "IRC Servers" +#define SERVERWINDOW _T("Network log") + +#define DCC_CHAT 1 +#define DCC_SEND 2 + +#define FILERESUME_CANCEL 11 + +struct CIrcProto; + +#include "mstring.h" +typedef CMStringA String; + +// special service for tweaking performance, implemented in chat.dll +#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr" +typedef int (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam); +typedef struct { + GETEVENTFUNC pfnAddEvent; +} + GCPTRS; + +#define IP_AUTO 1 +#define IP_MANUAL 2 + +struct IPRESOLVE // Contains info about the channels +{ + IPRESOLVE( const char* _addr, int _type ) : + sAddr( _addr ), + iType( _type ) + {} + + ~IPRESOLVE() + {} + + String sAddr; + int iType; +}; + +struct CHANNELINFO // Contains info about the channels +{ + TCHAR* pszTopic; + TCHAR* pszMode; + TCHAR* pszPassword; + TCHAR* pszLimit; + BYTE OwnMode; /* own mode on the channel. Bitmask: + 0: voice + 1: halfop + 2: op + 3: admin + 4: owner */ + int codepage; +}; + +struct SERVER_INFO // Contains info about different servers +{ + ~SERVER_INFO(); + + char *m_name, *m_address, *m_group; + int m_portStart, m_portEnd, m_iSSL; +}; + +struct PERFORM_INFO // Contains 'm_perform buffer' for different networks +{ + PERFORM_INFO( const char* szSetting, const TCHAR* value ) : + mSetting( szSetting ), + mText( value ) + {} + + ~PERFORM_INFO() + {} + + String mSetting; + CMString mText; +}; + +struct CONTACT // Contains info about users +{ + TCHAR* name; + TCHAR* user; + TCHAR* host; + bool ExactOnly; + bool ExactWCOnly; + bool ExactNick; +}; + +struct TDbSetting +{ + int offset; + char* name; + int type; + size_t size; + union + { + int defValue; + TCHAR* defStr; + }; +}; + +#include "irclib.h" +using namespace irc; + +#include "irc_dlg.h" + +///////////////////////////////////////////////////////////////////////////////////////// + +struct CIrcProto; +typedef void ( __cdecl CIrcProto::*IrcThreadFunc )( void* param ); +typedef int ( __cdecl CIrcProto::*IrcEventFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CIrcProto::*IrcServiceFunc )( WPARAM, LPARAM ); +typedef INT_PTR ( __cdecl CIrcProto::*IrcServiceFuncParam )( WPARAM, LPARAM, LPARAM ); + +typedef bool (CIrcProto::*PfnIrcMessageHandler)(const CIrcMessage* pmsg); + +struct CIrcHandler +{ + CIrcHandler( const TCHAR* _name, PfnIrcMessageHandler _handler ) : + m_name( _name ), + m_handler( _handler ) + {} + + const TCHAR* m_name; + PfnIrcMessageHandler m_handler; +}; + +struct CIrcProto : public PROTO_INTERFACE, public MZeroedObject +{ + CIrcProto( const char*, const TCHAR* ); + ~CIrcProto(); + + // Protocol interface + + virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr ); + virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent ); + + virtual int __cdecl Authorize( HANDLE hContact ); + virtual int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason ); + virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage ); + + virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData ); + + virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ); + virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer ); + virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ); + virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ); + + virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL ); + virtual HICON __cdecl GetIcon( int iconIndex ); + virtual int __cdecl GetInfo( HANDLE hContact, int infoType ); + + virtual HANDLE __cdecl SearchBasic( const PROTOCHAR* id ); + virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR* email ); + virtual HANDLE __cdecl SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName ); + virtual HWND __cdecl SearchAdvanced( HWND owner ); + virtual HWND __cdecl CreateExtendedSearchUI( HWND owner ); + + virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvFile( HANDLE hContact, PROTORECVFILET* ); + virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* ); + virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* ); + + virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ); + virtual HANDLE __cdecl SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ); + virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg ); + virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url ); + + virtual int __cdecl SetApparentMode( HANDLE hContact, int mode ); + virtual int __cdecl SetStatus( int iNewStatus ); + + virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact ); + virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt ); + virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg ); + virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg ); + + virtual int __cdecl UserIsTyping( HANDLE hContact, int type ); + + virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); + + // Services + INT_PTR __cdecl SvcCreateAccMgrUI( WPARAM, LPARAM ); + INT_PTR __cdecl GetMyAwayMsg( WPARAM, LPARAM ); + + INT_PTR __cdecl OnChangeNickMenuCommand( WPARAM, LPARAM ); + INT_PTR __cdecl OnDoubleclicked( WPARAM, LPARAM ); + INT_PTR __cdecl OnJoinChat( WPARAM, LPARAM ); + INT_PTR __cdecl OnJoinMenuCommand( WPARAM, LPARAM ); + INT_PTR __cdecl OnLeaveChat( WPARAM, LPARAM ); + INT_PTR __cdecl OnMenuChanSettings( WPARAM, LPARAM ); + INT_PTR __cdecl OnMenuDisconnect( WPARAM , LPARAM ); + INT_PTR __cdecl OnMenuIgnore( WPARAM, LPARAM ); + INT_PTR __cdecl OnMenuWhois( WPARAM, LPARAM ); + INT_PTR __cdecl OnQuickConnectMenuCommand(WPARAM, LPARAM ); + INT_PTR __cdecl OnShowListMenuCommand( WPARAM, LPARAM ); + INT_PTR __cdecl OnShowServerMenuCommand( WPARAM, LPARAM ); + + // Events + int __cdecl OnContactDeleted( WPARAM, LPARAM ); + int __cdecl OnInitOptionsPages( WPARAM, LPARAM ); + int __cdecl OnInitUserInfo( WPARAM, LPARAM ); + int __cdecl OnModulesLoaded( WPARAM, LPARAM ); + int __cdecl OnMenuPreBuild( WPARAM, LPARAM ); + int __cdecl OnPreShutdown( WPARAM, LPARAM ); + int __cdecl OnDbSettingChanged( WPARAM, LPARAM ); + + int __cdecl GCEventHook( WPARAM, LPARAM ); + int __cdecl GCMenuHook( WPARAM, LPARAM ); + + // Data + + char m_serverName[100]; + char m_password [500]; + TCHAR m_identSystem[10]; + char m_network[30]; + char m_portStart[10]; + char m_portEnd[10]; + int m_iSSL; + TCHAR m_identPort[10]; + TCHAR m_retryWait[10]; + TCHAR m_retryCount[10]; + TCHAR m_nick[30], m_pNick[30]; + TCHAR m_alternativeNick[30]; + TCHAR m_name[200]; + TCHAR m_userID[200]; + TCHAR m_quitMessage[400]; + TCHAR m_userInfo[500]; + char m_myHost[50]; + char m_mySpecifiedHost[500]; + char m_mySpecifiedHostIP[50]; + char m_myLocalHost[50]; + WORD m_myLocalPort; + TCHAR* m_alias; + int m_serverComboSelection; + int m_quickComboSelection; + int m_onlineNotificationTime; + int m_onlineNotificationLimit; + BYTE m_scriptingEnabled; + BYTE m_IPFromServer; + BYTE m_showAddresses; + BYTE m_disconnectDCCChats; + BYTE m_disableErrorPopups; + BYTE m_rejoinChannels; + BYTE m_rejoinIfKicked; + BYTE m_hideServerWindow; + BYTE m_ident; + BYTE m_identTimer; + BYTE m_retry; + BYTE m_disableDefaultServer; + BYTE m_autoOnlineNotification; + BYTE m_sendKeepAlive; + BYTE m_joinOnInvite; + BYTE m_perform; + BYTE m_forceVisible; + BYTE m_ignore; + BYTE m_ignoreChannelDefault; + BYTE m_useServer; + BYTE m_DCCFileEnabled; + BYTE m_DCCChatEnabled; + BYTE m_DCCChatAccept; + BYTE m_DCCChatIgnore; + BYTE m_DCCPassive; + BYTE m_DCCMode; + WORD m_DCCPacketSize; + BYTE m_manualHost; + BYTE m_oldStyleModes; + BYTE m_channelAwayNotification; + BYTE m_sendNotice; + BYTE m_utfAutodetect; + int m_codepage; + COLORREF colors[16]; + HICON hIcon[13]; + + OBJLIST vUserhostReasons; + OBJLIST vWhoInProgress; + + CRITICAL_SECTION cs; + CRITICAL_SECTION m_gchook; + CRITICAL_SECTION m_resolve; + HANDLE m_evWndCreate; + + CMString m_statusMessage; + bool m_bMbotInstalled; + int m_iTempCheckTime; + + CIrcSessionInfo si; + + int m_iRetryCount; + int m_portCount; + DWORD m_bConnectRequested; + DWORD m_bConnectThreadRunning; + + HGENMENU hMenuRoot, hMenuQuick, hMenuServer, hMenuJoin, hMenuNick, hMenuList; + HANDLE hNetlib, hNetlibDCC; + + bool bTempDisableCheck, bTempForceCheck, bEcho; + bool nickflag; + + bool bPerformDone; + + CJoinDlg* m_joinDlg; + CListDlg* m_listDlg; + CManagerDlg* m_managerDlg; + CNickDlg* m_nickDlg; + CWhoisDlg* m_whoisDlg; + CQuickDlg* m_quickDlg; + CIgnorePrefsDlg* m_ignoreDlg; + + int m_noOfChannels, m_manualWhoisCount; + String sChannelModes, sUserModes; + CMString sChannelPrefixes, sUserModePrefixes, WhoisAwayReply; + + CDlgBase::CreateParam OptCreateAccount, OptCreateConn, OptCreateIgnore, OptCreateOther; + + //clist.cpp + HANDLE CList_AddContact(struct CONTACT * user, bool InList, bool SetOnline); + bool CList_SetAllOffline(BYTE ChatsToo); + HANDLE CList_SetOffline(struct CONTACT * user); + + bool CList_AddEvent(struct CONTACT * user, HICON Icon, HANDLE event, const char * tooltip, int type ) ; + HANDLE CList_FindContact (struct CONTACT * user); + BOOL CList_AddDCCChat(const CMString& name, const CMString& hostmask, unsigned long adr, int port) ; + + //commandmonitor.cpp + UINT_PTR IdentTimer, InitTimer, KeepAliveTimer, OnlineNotifTimer, OnlineNotifTimer3; + + int AddOutgoingMessageToDB(HANDLE hContact, TCHAR* msg); + bool DoOnConnect(const CIrcMessage *pmsg); + int DoPerform(const char* event); + void __cdecl ResolveIPThread( void* di ); + + bool AddIgnore(const TCHAR* mask, const TCHAR* mode, const TCHAR* network) ; + int IsIgnored(const CMString& nick, const CMString& address, const CMString& host, char type) ; + int IsIgnored(CMString user, char type); + bool RemoveIgnore(const TCHAR* mask) ; + + //input.cpp + CMString DoAlias( const TCHAR *text, TCHAR *window); + BOOL DoHardcodedCommand( CMString text, TCHAR* window, HANDLE hContact ); + CMString DoIdentifiers( CMString text, const TCHAR* window ); + void FormatMsg(CMString& text); + bool PostIrcMessageWnd(TCHAR* pszWindow, HANDLE hContact,const TCHAR* szBuf); + bool PostIrcMessage( const TCHAR* fmt, ...); + + // irclib.cpp + UINT_PTR DCCTimer; + void SendIrcMessage( const TCHAR*, bool bNotify = true, int codepage = -1 ); + + // ircproto.cpp + void __cdecl AckBasicSearch( void* param ); + void __cdecl AckMessageFail( void* info ); + void __cdecl AckMessageFailDcc( void* info ); + void __cdecl AckMessageSuccess( void* info ); + + int SetStatusInternal( int iNewStatus, bool bIsInternal ); + + //options.cpp + HWND m_hwndConnect; + + OBJLIST m_ignoreItems; + + int m_channelNumber; + CMString m_whoReply; + CMString sNamesList; + CMString sTopic; + CMString sTopicName; + CMString sTopicTime; + CMString m_namesToWho; + CMString m_channelsToWho; + CMString m_namesToUserhost; + + void InitPrefs(void); + void InitIgnore(void); + + void ReadSettings( TDbSetting* sets, int count ); + void RewriteIgnoreSettings( void ); + void WriteSettings( TDbSetting* sets, int count ); + + //output + BOOL ShowMessage (const CIrcMessage* pmsg); + + //scripting.cpp + INT_PTR __cdecl Scripting_InsertRawIn(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_InsertRawOut(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_InsertGuiIn(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_InsertGuiOut(WPARAM wParam,LPARAM lParam); + INT_PTR __cdecl Scripting_GetIrcData(WPARAM wparam, LPARAM lparam); + BOOL Scripting_TriggerMSPRawIn(char ** pszRaw); + BOOL Scripting_TriggerMSPRawOut(char ** pszRaw); + BOOL Scripting_TriggerMSPGuiIn(WPARAM * wparam, GCEVENT * gce); + BOOL Scripting_TriggerMSPGuiOut(GCHOOK * gch); + + // services.cpp + void ConnectToServer(void); + void DisconnectFromServer(void); + void DoNetlibLog( const char* fmt, ... ); + void IrcHookEvent( const char*, IrcEventFunc ); + void InitMainMenus(void); + + void ircFork( IrcThreadFunc, void* arg ); + HANDLE ircForkEx( IrcThreadFunc, void* arg ); + + UINT_PTR RetryTimer; + + void __cdecl ConnectServerThread( void* ); + void __cdecl DisconnectServerThread( void* ); + + //tools.cpp + void AddToJTemp(TCHAR op, CMString& sCommand); + bool AddWindowItemData(CMString window, const TCHAR* pszLimit, const TCHAR* pszMode, const TCHAR* pszPassword, const TCHAR* pszTopic); + INT_PTR CallChatEvent(WPARAM wParam, LPARAM lParam); + void CreateProtoService( const char* serviceName, IrcServiceFunc pFunc ); + INT_PTR DoEvent(int iEvent, const TCHAR* pszWindow, const TCHAR* pszNick, const TCHAR* pszText, const TCHAR* pszStatus, const TCHAR* pszUserInfo, DWORD_PTR dwItemData, bool bAddToLog, bool bIsMe,time_t timestamp = 1); + void FindLocalIP(HANDLE con); + bool FreeWindowItemData(CMString window, CHANNELINFO* wis); + bool IsChannel(const char* sName); + bool IsChannel(const TCHAR* sName); + void KillChatTimer(UINT_PTR &nIDEvent); + CMString MakeWndID(const TCHAR* sWindow); + CMString ModeToStatus(int sMode); + CMString PrefixToStatus(int cPrefix); + int SetChannelSBText(CMString sWindow, CHANNELINFO * wi); + void SetChatTimer(UINT_PTR &nIDEvent,UINT uElapse, TIMERPROC lpTimerFunc); + + void ClearUserhostReasons(int type); + void DoUserhostWithReason(int type, CMString reason, bool bSendCommand, CMString userhostparams, ...); + CMString GetNextUserhostReason(int type); + CMString PeekAtReasons(int type); + + int getByte( const char* name, BYTE defaultValue ); + int getByte( HANDLE hContact, const char* name, BYTE defaultValue ); + int getDword( const char* name, DWORD defaultValue ); + int getDword( HANDLE hContact, const char* name, DWORD defaultValue ); + int getString( const char* name, DBVARIANT* ); + int getString( HANDLE hContact, const char* name, DBVARIANT* ); + int getTString( const char* name, DBVARIANT* ); + int getTString( HANDLE hContact, const char* name, DBVARIANT* ); + int getWord( const char* name, WORD defaultValue ); + int getWord( HANDLE hContact, const char* name, WORD defaultValue ); + + void setByte( const char* name, BYTE value ); + void setByte( HANDLE hContact, const char* name, BYTE value ); + void setDword( const char* name, DWORD value ); + void setDword( HANDLE hContact, const char* name, DWORD value ); + void setString( const char* name, const char* value ); + void setString( HANDLE hContact, const char* name, const char* value ); + void setTString( const char* name, const TCHAR* value ); + void setTString( HANDLE hContact, const char* name, const TCHAR* value ); + void setWord( const char* name, int value ); + void setWord( HANDLE hContact, const char* name, int value ); + + // userinfo.cpp + void __cdecl AckUserInfoSearch( void* hContact ); + + //////////////////////////////////////////////////////////////////////////////////////// + // former CIrcSession class + + void AddDCCSession(HANDLE hContact, CDccSession* dcc); + void AddDCCSession(DCCINFO* pdci, CDccSession* dcc); + void RemoveDCCSession(HANDLE hContact); + void RemoveDCCSession(DCCINFO* pdci); + + CDccSession* FindDCCSession(HANDLE hContact); + CDccSession* FindDCCSession(DCCINFO* pdci); + CDccSession* FindDCCSendByPort(int iPort); + CDccSession* FindDCCRecvByPortAndName(int iPort, const TCHAR* szName); + CDccSession* FindPassiveDCCSend(int iToken); + CDccSession* FindPassiveDCCRecv(CMString sName, CMString sToken); + + void DisconnectAllDCCSessions(bool Shutdown); + void CheckDCCTimeout(void); + + bool Connect(const CIrcSessionInfo& info); + void Disconnect(void); + void KillIdent(void); + + int NLSend(const TCHAR* fmt, ...); + int NLSend(const char* fmt, ...); + int NLSend(const unsigned char* buf, int cbBuf); + int NLSendNoScript( const unsigned char* buf, int cbBuf); + int NLReceive(unsigned char* buf, int cbBuf); + void InsertIncomingEvent(TCHAR* pszRaw); + + __inline bool IsConnected() const { return con != NULL; } + + // send-to-stream operators + int getCodepage() const; + __inline void setCodepage( int aPage ) { codepage = aPage; } + + CIrcSessionInfo m_info; + +protected : + int codepage; + HANDLE con; + HANDLE hBindPort; + void DoReceive(); + LIST m_dcc_chats; + LIST m_dcc_xfers; + +private : + CRITICAL_SECTION m_dcc; // protect the dcc objects + + void createMessageFromPchar( const char* p ); + void Notify(const CIrcMessage* pmsg); + void __cdecl ThreadProc( void *pparam ); + + //////////////////////////////////////////////////////////////////////////////////////// + // former CIrcMonitor class + + bool OnIrc_PING(const CIrcMessage* pmsg); + bool OnIrc_WELCOME(const CIrcMessage* pmsg); + bool OnIrc_YOURHOST(const CIrcMessage* pmsg); + bool OnIrc_NICK(const CIrcMessage* pmsg); + bool OnIrc_PRIVMSG(const CIrcMessage* pmsg); + bool OnIrc_JOIN(const CIrcMessage* pmsg); + bool OnIrc_QUIT(const CIrcMessage* pmsg); + bool OnIrc_PART(const CIrcMessage* pmsg); + bool OnIrc_KICK(const CIrcMessage* pmsg); + bool OnIrc_MODE(const CIrcMessage* pmsg); + bool OnIrc_USERHOST_REPLY(const CIrcMessage* pmsg); + bool OnIrc_MODEQUERY(const CIrcMessage* pmsg); + bool OnIrc_NAMES(const CIrcMessage* pmsg); + bool OnIrc_ENDNAMES(const CIrcMessage* pmsg); + bool OnIrc_INITIALTOPIC(const CIrcMessage* pmsg); + bool OnIrc_INITIALTOPICNAME(const CIrcMessage* pmsg); + bool OnIrc_TOPIC(const CIrcMessage* pmsg); + bool OnIrc_TRYAGAIN(const CIrcMessage* pmsg); + bool OnIrc_NOTICE(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_NAME(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_CHANNELS(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_SERVER(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_AWAY(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_IDLE(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_END(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_OTHER(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_AUTH(const CIrcMessage* pmsg); + bool OnIrc_WHOIS_NO_USER(const CIrcMessage* pmsg); + bool OnIrc_NICK_ERR(const CIrcMessage* pmsg); + bool OnIrc_ENDMOTD(const CIrcMessage* pmsg); + bool OnIrc_LISTSTART(const CIrcMessage* pmsg); + bool OnIrc_LIST(const CIrcMessage* pmsg); + bool OnIrc_LISTEND(const CIrcMessage* pmsg); + bool OnIrc_BANLIST(const CIrcMessage* pmsg); + bool OnIrc_BANLISTEND(const CIrcMessage* pmsg); + bool OnIrc_SUPPORT(const CIrcMessage* pmsg); + bool OnIrc_BACKFROMAWAY(const CIrcMessage* pmsg); + bool OnIrc_SETAWAY(const CIrcMessage* pmsg); + bool OnIrc_JOINERROR(const CIrcMessage* pmsg); + bool OnIrc_UNKNOWN(const CIrcMessage* pmsg); + bool OnIrc_ERROR(const CIrcMessage* pmsg); + bool OnIrc_NOOFCHANNELS(const CIrcMessage* pmsg); + bool OnIrc_PINGPONG(const CIrcMessage* pmsg); + bool OnIrc_INVITE(const CIrcMessage* pmsg); + bool OnIrc_WHO_END(const CIrcMessage* pmsg); + bool OnIrc_WHO_REPLY(const CIrcMessage* pmsg); + bool OnIrc_WHOTOOLONG(const CIrcMessage* pmsg); + + bool IsCTCP(const CIrcMessage* pmsg); + + void OnIrcDefault(const CIrcMessage* pmsg); + void OnIrcDisconnected(); + + static OBJLIST m_handlers; + + PfnIrcMessageHandler FindMethod(const TCHAR* lpszName); + + void OnIrcMessage(const CIrcMessage* pmsg); + CMString sNick4Perform; +}; + +// map actual member functions to their associated IRC command. +// put any number of this macro in the class's constructor. +#define IRC_MAP_ENTRY(name, member) \ + m_handlers.insert( new CIrcHandler( _T(name), &CIrcProto::OnIrc_##member )); + +///////////////////////////////////////////////////////////////////////////////////////// +// Functions + +//main.cpp +extern HINSTANCE hInst; + +extern LIST g_Instances; + +extern OBJLIST g_servers; + +void UpgradeCheck(void); + +CIrcProto* GetTimerOwner( UINT_PTR eventId ); + +VOID CALLBACK IdentTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK KeepAliveTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK OnlineNotifTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK OnlineNotifTimerProc3( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK DCCTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); +VOID CALLBACK RetryTimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ); + +// options.cpp + +void InitServers(void); +void RereadServers(void); + +void InitContactMenus(void); +void UninitContactMenus(void); + +void WindowSetIcon(HWND hWnd, int iconId); +void WindowFreeIcon(HWND hWnd); + +void AddIcons(void); +void UninitIcons(void); +HICON LoadIconEx(int iIndex, bool big = false); +HANDLE GetIconHandle(int iconId); +void ReleaseIconEx(HICON hIcon); + +// services.cpp + +extern BOOL bChatInstalled, m_bMbotInstalled; + +//tools.cpp +int __stdcall WCCmp(const TCHAR* wild, const TCHAR* string); +char* __stdcall IrcLoadFile(TCHAR * szPath); +CMString __stdcall GetWord(const TCHAR* text, int index); +CMString& __stdcall ReplaceString (CMString& text, const TCHAR* replaceme, const TCHAR* newword); +const TCHAR* __stdcall GetWordAddress(const TCHAR* text, int index); +void __stdcall RemoveLinebreaks( CMString& Message ); +TCHAR* __stdcall my_strstri(const TCHAR *s1, const TCHAR *s2) ; +TCHAR* __stdcall DoColorCodes (const TCHAR* text, bool bStrip, bool bReplacePercent); + +String& __stdcall ReplaceString (String& text, const char* replaceme, const char* newword); +String __stdcall GetWord(const char* text, int index); + +#pragma comment(lib,"comctl32.lib") + +#endif diff --git a/protocols/IRCG/src/irc_dlg.h b/protocols/IRCG/src/irc_dlg.h new file mode 100644 index 0000000000..887e9f0d0c --- /dev/null +++ b/protocols/IRCG/src/irc_dlg.h @@ -0,0 +1,329 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "ui_utils.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// Dialogs + +struct CMessageBoxDlg : public CProtoDlgBase +{ + DCCINFO* pdci; + + CMessageBoxDlg( CIrcProto* _pro, DCCINFO* _dci ); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); + + virtual void OnInitDialog(); +}; + +struct CCoolIrcDlg : public CProtoDlgBase +{ + CCoolIrcDlg( CIrcProto* _pro, int dlgId, HWND parent = NULL ); + + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + virtual void OnInitDialog(); + virtual void OnDestroy(); +}; + +struct CWhoisDlg : public CCoolIrcDlg +{ + CWhoisDlg( CIrcProto* _pro ); + + CCtrlCombo m_InfoNick; + CCtrlEdit m_Reply; + CCtrlBase m_Caption, m_AwayTime; + CCtrlBase m_InfoName, m_InfoId, m_InfoAddress, m_InfoChannels, m_InfoAuth, + m_InfoServer, m_InfoAway2, m_InfoOther; + CCtrlButton m_Ping, m_Version, m_Time, m_userInfo, m_Refresh, m_Query; + + void ShowMessage( const CIrcMessage* ); + void ShowMessageNoUser( const CIrcMessage* ); + + void OnGo( CCtrlButton* ); + void OnQuery( CCtrlButton* ); + void OnPing( CCtrlButton* ); + void OnUserInfo( CCtrlButton* ); + void OnTime( CCtrlButton* ); + void OnVersion( CCtrlButton* ); + + virtual void OnInitDialog(); + virtual void OnClose(); + virtual void OnDestroy(); +}; + +struct CNickDlg : public CCoolIrcDlg +{ + CNickDlg( CIrcProto* _pro ); + + CCtrlCombo m_Enick; + CCtrlButton m_Ok; + + virtual void OnInitDialog(); + virtual void OnDestroy(); + + void OnOk( CCtrlButton* ); +}; + +struct CListDlg : public CProtoDlgBase +{ + CListDlg( CIrcProto* _pro ); + + virtual void OnInitDialog(); + virtual void OnChange( CCtrlBase* ctrl ); + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + virtual void OnDestroy(); + virtual int Resizer(UTILRESIZECONTROL *urc); + + TCHAR m_title[255]; + CCtrlListView m_list, m_list2; + CCtrlEdit m_filter, m_status; + UINT_PTR m_timer; + + CCtrlButton m_Join; + void OnJoin( CCtrlButton* ); + + void List_OnColumnClick( CCtrlListView::TEventInfo* ev ); + + void UpdateList( void ); +}; + +struct CJoinDlg : public CCoolIrcDlg +{ + CJoinDlg( CIrcProto* _pro ); + + virtual void OnInitDialog(); + virtual void OnDestroy(); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); +}; + +struct CQuickDlg : public CCoolIrcDlg +{ + CQuickDlg( CIrcProto* _pro ); + + virtual void OnInitDialog(); + virtual void OnDestroy(); + + CCtrlCombo m_serverCombo; + void OnServerCombo( CCtrlData* ); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); + +private: + struct SERVER_INFO* m_si; +}; + +struct CManagerDlg : public CCoolIrcDlg +{ + CManagerDlg( CIrcProto* _pro ); + + CCtrlCheck m_check1, m_check2, m_check3, m_check4, m_check5, m_check6, m_check7, m_check8, m_check9; + CCtrlEdit m_key, m_limit; + CCtrlCombo m_topic; + CCtrlCheck m_radio1, m_radio2, m_radio3; + CCtrlMButton m_add, m_edit, m_remove, m_applyTopic, m_applyModes; + CCtrlListBox m_list; + + virtual void OnInitDialog(); + virtual void OnClose(); + virtual void OnDestroy(); + + void OnCheck( CCtrlData* ); + void OnCheck5( CCtrlData* ); + void OnCheck6( CCtrlData* ); + void OnRadio( CCtrlData* ); + + void OnAdd( CCtrlButton* ); + void OnEdit( CCtrlButton* ); + void OnRemove( CCtrlButton* ); + + void OnListDblClick( CCtrlListBox* ); + void OnChangeList( CCtrlListBox* ); + void OnChangeModes( CCtrlData* ); + void OnChangeTopic( CCtrlData* ); + + void OnApplyModes( CCtrlButton* ); + void OnApplyTopic( CCtrlButton* ); + + void ApplyQuestion(); + void CloseQuestion(); + void InitManager( int mode, const TCHAR* window ); +}; + +struct CQuestionDlg : public CCoolIrcDlg +{ + CQuestionDlg( CIrcProto* _pro, CManagerDlg* owner = NULL ); + + virtual void OnInitDialog(); + virtual void OnClose(); + + CCtrlButton m_Ok; + void OnOk( CCtrlButton* ); + + void Activate(); + +private: + CManagerDlg* m_owner; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// options + +//---- the first property page: Account ------------------------------------------------- + +struct CConnectPrefsDlg : public CProtoDlgBase +{ + bool m_serverlistModified; + + CCtrlCombo m_serverCombo; + CCtrlEdit m_server, m_port, m_port2, m_pass; + CCtrlMButton m_add, m_edit, m_del; + CCtrlEdit m_nick, m_nick2, m_name, m_userID; + + CCtrlCheck m_ident, m_identTimer; + CCtrlEdit m_identSystem, m_identPort; + + CCtrlCheck m_retry; + CCtrlEdit m_retryCount, m_retryWait; + + CCtrlCheck m_forceVisible, m_rejoinOnKick, m_rejoinChannels, m_disableError, + m_address, m_useServer, m_showServer, m_keepAlive, m_autoJoin, + m_oldStyle, m_onlineNotif, m_channelAway, m_enableServer; + CCtrlEdit m_onlineTimer, m_limit, m_spin1, m_spin2, m_ssl; + + CConnectPrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new CConnectPrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnApply(); + + void OnServerCombo( CCtrlData* ); + void OnAddServer( CCtrlButton* ); + void OnDeleteServer( CCtrlButton* ); + void OnEditServer( CCtrlButton* ); + void OnStartup( CCtrlData* ); + void OnIdent( CCtrlData* ); + void OnUseServer( CCtrlData* ); + void OnOnlineNotif( CCtrlData* ); + void OnChannelAway( CCtrlData* ); + void OnRetry( CCtrlData* ); +}; + +//---- the second property page: DCC/CTCP ----------------------------------------------- + +struct CCtcpPrefsDlg : public CProtoDlgBase +{ + CCtrlCombo m_combo; + CCtrlCheck m_slow, m_fast, m_disc, m_passive, m_sendNotice, m_enableIP, m_fromServer; + CCtrlEdit m_ip, m_userInfo; + CCtrlCheck m_radio1, m_radio2, m_radio3; + + CCtcpPrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new CCtcpPrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnApply(); + + void OnClicked( CCtrlData* ); +}; + +//---- the third property page: Other --------------------------------------------------- + +struct COtherPrefsDlg : public CProtoDlgBase +{ + bool m_performlistModified; + + CCtrlButton m_url; + CCtrlMButton m_add, m_delete; + CCtrlCombo m_performCombo, m_codepage; + CCtrlEdit m_pertormEdit, m_quitMessage, m_alias; + CCtrlCheck m_perform, m_scripting, m_autodetect; + + COtherPrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new COtherPrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnApply(); + virtual void OnDestroy(); + + void OnUrl( CCtrlButton* ); + void OnPerformCombo( CCtrlData* ); + void OnCodePage( CCtrlData* ); + void OnPerformEdit( CCtrlData* ); + void OnPerform( CCtrlData* ); + void OnAdd( CCtrlButton* ); + void OnDelete( CCtrlButton* ); + + void addPerformComboValue( int idx, const char* szValueName ); +}; + +//---- the fourth property page: Ignore ------------------------------------------------- + +struct CIgnorePrefsDlg : public CProtoDlgBase +{ + CCtrlMButton m_add, m_edit, m_del; + CCtrlCheck m_enable, m_ignoreChat, m_ignoreFile, m_ignoreChannel, m_ignoreUnknown; + CCtrlListView m_list; + + CIgnorePrefsDlg( CIrcProto* _pro ); + + static CDlgBase* Create( void* param ) { return new CIgnorePrefsDlg(( CIrcProto* )param ); } + + virtual void OnInitDialog(); + virtual void OnDestroy(); + virtual void OnApply(); + + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + void List_OnColumnClick( CCtrlListView::TEventInfo* ); + void OnEnableIgnore( CCtrlData* ); + void OnIgnoreChat( CCtrlData* ); + void OnAdd( CCtrlButton* ); + void OnEdit( CCtrlButton* ); + void OnDelete( CCtrlButton* ); + + void FixButtons( void ); + void RebuildList( void ); + void UpdateList( void ); +}; + +struct CAddIgnoreDlg : public CProtoDlgBase +{ + CCtrlButton m_Ok; + CIgnorePrefsDlg* m_owner; + + TCHAR szOldMask[500]; + + CAddIgnoreDlg( CIrcProto* _pro, const TCHAR* mask, CIgnorePrefsDlg* parent ); + + virtual void OnInitDialog(); + virtual void OnClose(); + + void OnOk( CCtrlButton* ); +}; diff --git a/protocols/IRCG/src/irclib.cpp b/protocols/IRCG/src/irclib.cpp new file mode 100644 index 0000000000..c018b57a02 --- /dev/null +++ b/protocols/IRCG/src/irclib.cpp @@ -0,0 +1,1505 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +#define DCCCHATTIMEOUT 300 +#define DCCSENDTIMEOUT 120 + +using namespace irc; + +int CDccSession::nDcc = 0; + +static int CompareHandlers( const CIrcHandler* p1, const CIrcHandler* p2 ) +{ + return lstrcmp( p1->m_name, p2->m_name ); +} + +OBJLIST CIrcProto::m_handlers( 30, CompareHandlers ); + +//////////////////////////////////////////////////////////////////// + +CIrcMessage::CIrcMessage( CIrcProto* _pro, const TCHAR* lpszCmdLine, int codepage, bool bIncoming, bool bNotify ) : + m_proto( _pro ), + m_bIncoming( bIncoming ), + m_bNotify( bNotify ), + m_codePage( codepage ), + parameters( 10 ) +{ + ParseIrcCommand(lpszCmdLine); +} + +CIrcMessage::CIrcMessage(const CIrcMessage& m) : + sCommand( m.sCommand ), + m_bIncoming( m.m_bIncoming ), + m_bNotify( m.m_bNotify ), + m_codePage( m.m_codePage ), + m_proto( m.m_proto ), + parameters( m.parameters.getCount()) +{ + prefix.sNick = m.prefix.sNick; + prefix.sUser = m.prefix.sUser; + prefix.sHost = m.prefix.sHost; + + for ( int i=0; i < m.parameters.getCount(); i++ ) + parameters.insert( new CMString( m.parameters[i] )); +} + +CIrcMessage::~CIrcMessage() +{ +} + +void CIrcMessage::Reset() +{ + prefix.sNick = prefix.sUser = prefix.sHost = sCommand = _T(""); + m_bIncoming = false; + m_bNotify = true; + + parameters.destroy(); +} + +CIrcMessage& CIrcMessage::operator = (const CIrcMessage& m) +{ + if ( &m != this ) { + sCommand = m.sCommand; + parameters = m.parameters; + prefix.sNick = m.prefix.sNick; + prefix.sUser = m.prefix.sUser; + prefix.sHost = m.prefix.sHost; + m_bIncoming = m.m_bIncoming; + m_bNotify = m.m_bNotify; + } + return *this; +} + +CIrcMessage& CIrcMessage::operator = (const TCHAR* lpszCmdLine) +{ + Reset(); + ParseIrcCommand(lpszCmdLine); + return *this; +} + +void CIrcMessage::ParseIrcCommand(const TCHAR* lpszCmdLine) +{ + const TCHAR* p1 = lpszCmdLine; + const TCHAR* p2 = lpszCmdLine; + + // prefix exists ? + if ( *p1 == ':' ) { + // break prefix into its components (nick!user@host) + p2 = ++p1; + while( *p2 && !_tcschr( _T(" !"), *p2 )) + ++p2; + prefix.sNick.SetString(p1, p2 - p1); + if ( *p2 != '!' ) + goto end_of_prefix; + p1 = ++p2; + while( *p2 && !_tcschr( _T(" @"), *p2 )) + ++p2; + prefix.sUser.SetString(p1, p2 - p1); + if ( *p2 != '@' ) + goto end_of_prefix; + p1 = ++p2; + while( *p2 && *p2 != ' ' ) + ++p2; + prefix.sHost.SetString(p1, p2 - p1); +end_of_prefix : + while( *p2 && *p2 == ' ' ) + ++p2; + p1 = p2; + } + + // get command + p2 = p1; + while( *p2 && *p2 != ' ' ) + ++p2; + + sCommand.SetString(p1, p2 - p1); + sCommand.MakeUpper(); + while( *p2 && *p2 == ' ' ) + ++p2; + p1 = p2; + + // get parameters + while( *p1 ) { + if ( *p1 == ':' ) { + ++p1; + + // seek end-of-message + while( *p2 ) + ++p2; + parameters.insert( new CMString(p1, p2 - p1)); + break; + } + else { + // seek end of parameter + while( *p2 && *p2 != ' ' ) + ++p2; + parameters.insert( new CMString(p1, p2 - p1)); + // see next parameter + while( *p2 && *p2 == ' ' ) + ++p2; + p1 = p2; +} } } + +//////////////////////////////////////////////////////////////////// + +int CIrcProto::getCodepage() const +{ + return ( con != NULL ) ? codepage : CP_ACP; +} + +void CIrcProto::SendIrcMessage( const TCHAR* msg, bool bNotify, int codepage ) +{ + if ( codepage == -1 ) + codepage = getCodepage(); + + if ( this ) { + char* str = mir_t2a_cp( msg, codepage ); + rtrim( str ); + int cbLen = (int)strlen( str ); + str = ( char* )mir_realloc( str, cbLen+3 ); + strcat( str, "\r\n" ); + NLSend(( const BYTE* )str, cbLen+2 ); + mir_free( str ); + + if ( bNotify ) { + CIrcMessage ircMsg( this, msg, codepage ); + if ( !ircMsg.sCommand.IsEmpty() && ircMsg.sCommand != _T("QUIT")) + Notify( &ircMsg ); +} } } + +bool CIrcProto::Connect(const CIrcSessionInfo& info) +{ + codepage = m_codepage; + + NETLIBOPENCONNECTION ncon = { 0 }; + ncon.cbSize = sizeof(ncon); + ncon.szHost = info.sServer.c_str(); + ncon.wPort = info.iPort; + con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM) hNetlib, (LPARAM) & ncon); + if (con == NULL) { + TCHAR szTemp[300]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0035%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u)."), + TranslateT("Failed to connect to"), si.sNetwork.c_str(), si.sServer.c_str(), si.iPort); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); + return false; + } + + FindLocalIP(con); // get the local ip used for filetransfers etc + + if ( info.m_iSSL > 0 ) { + if ( !CallService( MS_NETLIB_STARTSSL, ( WPARAM ) con, 0 ) && info.m_iSSL == 2 ) { + Netlib_CloseHandle( con ); + con = NULL; + m_info.Reset(); + return false; + } } + + if ( Miranda_Terminated()) { + Disconnect(); + return false; + } + + m_info = info; + + // start receiving messages from host + ircFork( &CIrcProto::ThreadProc, NULL ); + Sleep( 100 ); + if ( info.sPassword.GetLength()) + NLSend( "PASS %s\r\n", info.sPassword.c_str()); + NLSend( _T("NICK %s\r\n"), info.sNick.c_str()); + + CMString m_userID = GetWord(info.sUserID.c_str(), 0); + TCHAR szHostName[MAX_PATH]; + DWORD cbHostName = SIZEOF( szHostName ); + GetComputerName(szHostName, &cbHostName); + CMString HostName = GetWord(szHostName, 0); + if ( m_userID.IsEmpty()) + m_userID = _T("Miranda"); + if ( HostName.IsEmpty()) + HostName= _T("host"); + NLSend( _T("USER %s %s %s :%s\r\n"), m_userID.c_str(), HostName.c_str(), _T("server"), info.sFullName.c_str()); + + return con != NULL; +} + +void CIrcProto::Disconnect(void) +{ + static const DWORD dwServerTimeout = 5 * 1000; + + if ( con == NULL ) + return; + + KillIdent(); + + if ( m_quitMessage && m_quitMessage[0] ) + NLSend( _T("QUIT :%s\r\n"), m_quitMessage); + else + NLSend( "QUIT \r\n" ); + + Sleep(50); + + if ( con ) + Netlib_Shutdown(con); + + m_info.Reset(); + return; +} + +void CIrcProto::Notify(const CIrcMessage* pmsg) +{ + OnIrcMessage(pmsg); +} + +int CIrcProto::NLSend( const unsigned char* buf, int cbBuf) +{ + if ( m_bMbotInstalled && m_scriptingEnabled ) { + int iVal = NULL; + char * pszTemp = 0; + pszTemp = ( char* ) mir_alloc( lstrlenA((const char *) buf ) + 1); + lstrcpynA(pszTemp, (const char *)buf, lstrlenA ((const char *)buf) + 1); + + if ( Scripting_TriggerMSPRawOut(&pszTemp) && pszTemp ) { + if (con) + iVal = Netlib_Send(con, (const char*)pszTemp, lstrlenA(pszTemp), MSG_DUMPASTEXT); + } + if ( pszTemp ) + mir_free( pszTemp ); + + return iVal; + } + + if (con) + return Netlib_Send(con, (const char*)buf, cbBuf, MSG_DUMPASTEXT); + + return 0; +} + +int CIrcProto::NLSend( const TCHAR* fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + + TCHAR szBuf[1024*4]; + mir_vsntprintf(szBuf, SIZEOF(szBuf), fmt, marker); + va_end(marker); + + char* buf = mir_t2a_cp( szBuf, getCodepage()); + int result = NLSend((unsigned char*)buf, (int)strlen(buf)); + mir_free( buf ); + return result; +} + +int CIrcProto::NLSend( const char* fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + + char szBuf[1024*4]; + int cbLen = mir_vsnprintf(szBuf, SIZEOF(szBuf), fmt, marker); + va_end(marker); + + return NLSend((unsigned char*)szBuf, cbLen ); +} + +int CIrcProto::NLSendNoScript( const unsigned char* buf, int cbBuf) +{ + if ( con ) + return Netlib_Send(con, (const char*)buf, cbBuf, MSG_DUMPASTEXT); + + return 0; +} + +int CIrcProto::NLReceive(unsigned char* buf, int cbBuf) +{ + return Netlib_Recv( con, (char*)buf, cbBuf, MSG_DUMPASTEXT ); +} + +void CIrcProto::KillIdent() +{ + if ( hBindPort ) { + HANDLE hPort = hBindPort; + hBindPort = NULL; + Netlib_CloseHandle( hPort ); + } +} + +void CIrcProto::InsertIncomingEvent(TCHAR* pszRaw) +{ + CIrcMessage msg( this, pszRaw, true); + Notify( &msg ); + return; +} + +void CIrcProto::createMessageFromPchar( const char* p ) +{ + TCHAR* ptszMsg; + if ( codepage != CP_UTF8 && m_utfAutodetect ) { + if ( mir_utf8decodecp( NEWSTR_ALLOCA(p), codepage, &ptszMsg ) == NULL ) + ptszMsg = mir_a2t_cp( p, codepage ); + } + else ptszMsg = mir_a2t_cp( p, codepage ); + CIrcMessage msg( this, ptszMsg, codepage, true ); + Notify( &msg ); + mir_free( ptszMsg ); +} + +void CIrcProto::DoReceive() +{ + char chBuf[1024*4+1]; + int cbInBuf = 0; + + if ( m_info.bIdentServer && m_info.iIdentServerPort != NULL ) { + NETLIBBIND nb = {0}; + nb.cbSize = sizeof(NETLIBBIND); + nb.pfnNewConnectionV2 = DoIdent; + nb.pExtra = this; + nb.wPort = m_info.iIdentServerPort; + hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)hNetlib,(LPARAM) &nb); + if ( !hBindPort || nb.wPort != m_info.iIdentServerPort ) { + DoNetlibLog("Error: unable to bind local port %u", m_info.iIdentServerPort); + KillIdent(); + } } + + while( con ) { + int nLinesProcessed = 0; + + int cbRead = NLReceive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); + if ( cbRead <= 0 ) + break; + + cbInBuf += cbRead; + chBuf[cbInBuf] = '\0'; + + char* pStart = chBuf; + while( *pStart ) { + char* pEnd; + + // seek end-of-line + for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) + ; + if ( *pEnd == '\0' ) + break; // uncomplete message. stop parsing. + + ++nLinesProcessed; + + // replace end-of-line with NULLs and skip + while( *pEnd == '\r' || *pEnd == '\n' ) + *pEnd++ = '\0'; + + // process single message by monitor objects + if ( *pStart ) { + if ( m_bMbotInstalled && m_scriptingEnabled ) { + char* pszTemp = mir_strdup( pStart ); + + if ( Scripting_TriggerMSPRawIn( &pszTemp ) && pszTemp ) { + char* p1 = pszTemp; + // replace end-of-line with NULLs + while( *p1 != '\0' ) { + if ( *p1 == '\r' || *p1 == '\n') + *p1 = '\0'; + p1++; + } + + createMessageFromPchar( pszTemp ); + } + + mir_free( pszTemp ); + } + else createMessageFromPchar( pStart ); + } + + cbInBuf -= pEnd - pStart; + pStart = pEnd; + } + + // discard processed messages + if ( nLinesProcessed != 0 ) + memmove(chBuf, pStart, cbInBuf+1); + } + + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } + + // notify monitor objects that the connection has been closed + Notify(NULL); +} + +void __cdecl CIrcProto::ThreadProc( void* ) +{ + DoReceive(); + m_info.Reset(); +} + +void CIrcProto::AddDCCSession(HANDLE, CDccSession* dcc) +{ + EnterCriticalSection(&m_dcc); + + CDccSession* p = m_dcc_chats.find(dcc); + if ( p ) + m_dcc_chats.remove( p ); + + m_dcc_chats.insert( dcc ); + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::AddDCCSession(DCCINFO*, CDccSession* dcc) +{ + EnterCriticalSection(&m_dcc); + + m_dcc_xfers.insert( dcc ); + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::RemoveDCCSession(HANDLE hContact) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) + if ( m_dcc_chats[i]->di->hContact == hContact ) { + m_dcc_chats.remove( i ); + break; + } + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::RemoveDCCSession(DCCINFO* pdci) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) + if ( m_dcc_xfers[i]->di == pdci ) { + m_dcc_xfers.remove( i ); + break; + } + + LeaveCriticalSection(&m_dcc); +} + +CDccSession* CIrcProto::FindDCCSession(HANDLE hContact) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) + if ( m_dcc_chats[i]->di->hContact == hContact ) { + LeaveCriticalSection(&m_dcc); + return m_dcc_chats[ i ]; + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindDCCSession(DCCINFO* pdci) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) + if ( m_dcc_xfers[i]->di == pdci ) { + LeaveCriticalSection(&m_dcc); + return m_dcc_xfers[ i ]; + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindDCCSendByPort(int iPort) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + CDccSession* p = m_dcc_xfers[i]; + if ( p->di->iType == DCC_SEND && p->di->bSender && iPort == p->di->iPort ) { + LeaveCriticalSection(&m_dcc); + return p; + } + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindDCCRecvByPortAndName(int iPort, const TCHAR* szName) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + CDccSession* p = m_dcc_xfers[i]; + DBVARIANT dbv; + if ( !getTString(p->di->hContact, "Nick", &dbv)) { + if ( p->di->iType == DCC_SEND && !p->di->bSender && !lstrcmpi( szName, dbv.ptszVal) && iPort == p->di->iPort ) { + DBFreeVariant(&dbv); + LeaveCriticalSection(&m_dcc); + return p; + } + DBFreeVariant(&dbv); + } + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindPassiveDCCSend(int iToken) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + if ( m_dcc_xfers[ i ]->iToken == iToken ) { + LeaveCriticalSection(&m_dcc); + return m_dcc_xfers[ i ]; + } + } + + LeaveCriticalSection(&m_dcc); + return 0; +} + +CDccSession* CIrcProto::FindPassiveDCCRecv(CMString sName, CMString sToken) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_xfers.getCount(); i++ ) { + CDccSession* p = m_dcc_xfers[i]; + if ( sToken == p->di->sToken && sName == p->di->sContactName ) { + LeaveCriticalSection(&m_dcc); + return p; + } + } + LeaveCriticalSection(&m_dcc); + return 0; +} + +void CIrcProto::DisconnectAllDCCSessions(bool Shutdown) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) + if ( m_disconnectDCCChats || Shutdown ) + m_dcc_chats[i]->Disconnect(); + + LeaveCriticalSection(&m_dcc); +} + +void CIrcProto::CheckDCCTimeout(void) +{ + EnterCriticalSection(&m_dcc); + + for ( int i=0; i < m_dcc_chats.getCount(); i++ ) { + CDccSession* p = m_dcc_chats[i]; + if ( time(0) > p->tLastActivity + DCCCHATTIMEOUT ) + p->Disconnect(); + } + + for ( int j=0; j < m_dcc_xfers.getCount(); j++ ) { + CDccSession* p = m_dcc_xfers[j]; + if ( time(0) > p->tLastActivity + DCCSENDTIMEOUT ) + p->Disconnect(); + } + + LeaveCriticalSection(&m_dcc); +} + +//////////////////////////////////////////////////////////////////// + +CIrcIgnoreItem::CIrcIgnoreItem( const TCHAR* _mask, const TCHAR* _flags, const TCHAR* _network ) : + mask( _mask ), + flags( _flags ), + network( _network ) +{ +} + +CIrcIgnoreItem::CIrcIgnoreItem( int codepage, const char* _mask, const char* _flags, const char* _network ) : + mask( (TCHAR *)_A2T( _mask, codepage )), + flags( (TCHAR *)_A2T( _flags, codepage )), + network( (TCHAR *)_A2T( _network, codepage )) +{ +} + +CIrcIgnoreItem::~CIrcIgnoreItem() +{ +} + +//////////////////////////////////////////////////////////////////// + +CIrcSessionInfo::CIrcSessionInfo() : + iPort(0), + bIdentServer(false), + iIdentServerPort(0) +{ +} + +CIrcSessionInfo::CIrcSessionInfo(const CIrcSessionInfo& si) : + sServer(si.sServer), + sServerName(si.sServerName), + iPort(si.iPort), + sNick(si.sNick), + sUserID(si.sUserID), + sFullName(si.sFullName), + sPassword(si.sPassword), + bIdentServer(si.bIdentServer), + m_iSSL(si.m_iSSL), + sIdentServerType(si.sIdentServerType), + sNetwork(si.sNetwork), + iIdentServerPort(si.iIdentServerPort) +{ +} + +void CIrcSessionInfo::Reset() +{ + sServer = ""; + sServerName = _T(""); + iPort = 0; + sNick = _T(""); + sUserID = _T(""); + sFullName = _T(""); + sPassword = ""; + bIdentServer = false; + bNickFlag = false; + m_iSSL = 0; + sIdentServerType = _T(""); + iIdentServerPort = 0; + sNetwork = _T(""); +} + +//////////////////////////////////////////////////////////////////// + +void CIrcProto::OnIrcMessage(const CIrcMessage* pmsg) +{ + if ( pmsg != NULL ) { + PfnIrcMessageHandler pfn = FindMethod( pmsg->sCommand.c_str()); + if ( pfn ) { + // call member function. if it returns 'false', + // call the default handling + __try + { + if ( !(this->*pfn)( pmsg )) + OnIrcDefault( pmsg ); + } + __except( EXCEPTION_EXECUTE_HANDLER ) // dedicated to Sava :) + { + DoNetlibLog( "IRC handler feels sick: %S", pmsg->sCommand.c_str()); + } + } + else // handler not found. call default handler + OnIrcDefault( pmsg ); + } + else OnIrcDisconnected(); +} + +PfnIrcMessageHandler CIrcProto::FindMethod(const TCHAR* lpszName) +{ + CIrcHandler temp( lpszName, NULL ); + CIrcHandler* p = m_handlers.find( &temp ); + return ( p == NULL ) ? NULL : p->m_handler; +} + +//////////////////////////////////////////////////////////////////// + +#define IPC_ADDR_SIZE 4 /* Size of IP address, change for IPv6. */ + +char* ConvertIntegerToIP(unsigned long int_ip_addr) +{ + IN_ADDR intemp; + IN_ADDR in; + intemp.S_un.S_addr = int_ip_addr; + + in.S_un.S_un_b.s_b1 = intemp.S_un.S_un_b.s_b4; + in.S_un.S_un_b.s_b2 = intemp.S_un.S_un_b.s_b3; + in.S_un.S_un_b.s_b3 = intemp.S_un.S_un_b.s_b2; + in.S_un.S_un_b.s_b4 = intemp.S_un.S_un_b.s_b1; + + return inet_ntoa( in ); +} + +unsigned long ConvertIPToInteger( char* IP ) +{ + IN_ADDR in; + IN_ADDR intemp; + + if ( IP == 0 || lstrlenA(IP) == 0) + return 0; + + intemp.S_un.S_addr = inet_addr(IP); + + in.S_un.S_un_b.s_b1 = intemp.S_un.S_un_b.s_b4; + in.S_un.S_un_b.s_b2 = intemp.S_un.S_un_b.s_b3; + in.S_un.S_un_b.s_b3 = intemp.S_un.S_un_b.s_b2; + in.S_un.S_un_b.s_b4 = intemp.S_un.S_un_b.s_b1; + return in.S_un.S_addr; +} + +//////////////////////////////////////////////////////////////////// + +// initialize basic stuff needed for the dcc objects, also start a timer for checking the status of connections (timeouts) +CDccSession::CDccSession( CIrcProto* _pro, DCCINFO* pdci ) : + m_proto( _pro ), + NewFileName(0), + dwWhatNeedsDoing(0), + tLastPercentageUpdate(0), + dwTotal(0), + iGlobalToken(), + dwResumePos(0), + hEvent(0), + con(0), + hBindPort(0) +{ + tLastActivity = time(0); + + di = pdci; // Setup values passed to the constructor + + ZeroMemory(&pfts, sizeof(PROTOFILETRANSFERSTATUS)); + pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); + + if(di->iType == DCC_SEND && di->bSender == false) + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if(nDcc == 0) + m_proto->SetChatTimer(m_proto->DCCTimer, 20*1000, DCCTimerProc); + + nDcc++; // increase the count of existing objects + + iGlobalToken++; + if(iGlobalToken == 1000) + iGlobalToken = 1; + iToken = iGlobalToken; + + iPacketSize = m_proto->getWord( "PacketSize", 4096 ); + + if ( di->dwAdr ) + m_proto->setDword(di->hContact, "IP", di->dwAdr); // mtooltip stuff +} + +CDccSession::~CDccSession() // destroy all that needs destroying +{ + if ( di->iType == DCC_SEND ) { + // ack SUCCESS or FAILURE + if (dwTotal == di->dwSize ) + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (void *)di, 0); + else + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); + } + + if ( di->iType == DCC_CHAT ) { + CDccSession* dcc = m_proto->FindDCCSession(di->hContact); + if ( dcc && this == dcc ) { + m_proto->RemoveDCCSession(di->hContact); // objects automatically remove themselves from the list of objects + m_proto->setWord(di->hContact, "Status", ID_STATUS_OFFLINE); + } } + + if ( di->iType == DCC_SEND ) + m_proto->RemoveDCCSession( di ); + + if ( hEvent != NULL ) { + SetEvent( hEvent ); + CloseHandle( hEvent ); + hEvent = NULL; + } + + delete di; + nDcc--; + + if ( nDcc < 0 ) + nDcc = 0; + + if ( nDcc == 0 ) + m_proto->KillChatTimer( m_proto->DCCTimer ); // destroy the timer when no dcc objects remain +} + +int CDccSession::NLSend(const unsigned char* buf, int cbBuf) +{ + tLastActivity = time(0); + + if (con) + return Netlib_Send(con, (const char*)buf, cbBuf, di->iType == DCC_CHAT?MSG_DUMPASTEXT:MSG_NODUMP); + + return 0; +} + +int CDccSession::NLReceive(const unsigned char* buf, int cbBuf) +{ + int n = 0; + + if(con) + n = Netlib_Recv(con, (char*)buf, cbBuf, di->iType == DCC_CHAT?MSG_DUMPASTEXT:MSG_NODUMP); + + tLastActivity = time(0); + return n; +} + +int CDccSession::SendStuff(const TCHAR* fmt) +{ + String buf = _T2A( fmt, m_proto->getCodepage()); + return NLSend(( const unsigned char* )buf.c_str(), buf.GetLength()); +} + +// called when the user wants to connect/create a new connection given the parameters in the constructor. +int CDccSession::Connect() +{ + if ( !di->bSender || di->bReverse ) { + if ( !con ) + mir_forkthread( ConnectProc, this ); // spawn a new thread for time consuming activities, ie when connecting to a remote computer + return true; + } + + if ( !con ) + return SetupConnection(); // no need to spawn thread for setting up a listening port locally + + return false; +} + +void __cdecl CDccSession::ConnectProc( void *pparam ) +{ + CDccSession* pThis = (CDccSession*)pparam; + if ( !pThis->con ) + pThis->SetupConnection(); +} + +// small function to setup the address and port of the remote computer fror passive filetransfers +void CDccSession::SetupPassive(DWORD adress, DWORD port) +{ + di->dwAdr = adress; + di->iPort = (int)port; + + m_proto->setDword(di->hContact, "IP", di->dwAdr); // mtooltip stuff +} + +int CDccSession::SetupConnection() +{ + // if it is a dcc chat connection make sure it is "offline" to begin with, since no connection exists still + if ( di->iType == DCC_CHAT ) + m_proto->setWord(di->hContact, "Status", ID_STATUS_OFFLINE); + + // Set up stuff needed for the filetransfer dialog (if it is a filetransfer) + if ( di->iType == DCC_SEND ) { + file[0] = ( TCHAR* )di->sFileAndPath.c_str(); + file[1] = 0; + + pfts.tszCurrentFile = ( TCHAR* )di->sFileAndPath.c_str(); + pfts.tszWorkingDir = ( TCHAR* )di->sPath.c_str(); + pfts.hContact = di->hContact; + pfts.flags = PFTS_TCHAR + ((di->bSender) ? PFTS_SENDING : PFTS_RECEIVING); + pfts.totalFiles = 1; + pfts.currentFileNumber = 0; + pfts.totalBytes = di->dwSize; + pfts.currentFileSize = pfts.totalBytes; + pfts.ptszFiles = file; + pfts.totalProgress = 0; + pfts.currentFileProgress = 0; + pfts.currentFileTime = (unsigned long)time(0); + } + + // create a listening socket for outgoing chat/send requests. The remote computer connects to this computer. Used for both chat and filetransfer. + if ( di->bSender && !di->bReverse ) { + NETLIBBIND nb = {0}; + nb.cbSize = sizeof(NETLIBBIND); + nb.pfnNewConnectionV2 = DoIncomingDcc; // this is the (helper) function to be called once an incoming connection is made. The 'real' function that is called is IncomingConnection() + nb.pExtra = (void *)this; + nb.wPort = 0; + hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)m_proto->hNetlibDCC,(LPARAM) &nb); + + if ( hBindPort == NULL ) { + delete this; // dcc objects destroy themselves when the connection has been closed or failed for some reasson. + return 0; + } + + di->iPort = nb.wPort; // store the port internally so it is possible to search for it (for resuming of filetransfers purposes) + return nb.wPort; // return the created port so it can be sent to the remote computer in a ctcp/dcc command + } + + // If a remote computer initiates a chat session this is used to connect to the remote computer (user already accepted at this point). + // also used for connecting to a remote computer for remote file transfers + if ( di->iType == DCC_CHAT && !di->bSender || di->iType == DCC_SEND && di->bSender && di->bReverse ) { + NETLIBOPENCONNECTION ncon = { 0 }; + ncon.cbSize = sizeof(ncon); + ncon.szHost = ConvertIntegerToIP(di->dwAdr); + ncon.wPort = (WORD) di->iPort; + con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM)m_proto->hNetlibDCC, (LPARAM) & ncon); + } + + + // If a remote computer initiates a filetransfer this is used to connect to that computer (the user has chosen to accept but it is possible the file exists/needs to be resumed etc still) + if ( di->iType == DCC_SEND && !di->bSender ) { + + // this following code is for miranda to be able to show the resume/overwrite etc dialog if the file that we are receiving already exists. + // It must be done before we create the connection or else the other party will begin sending packets while the user is still deciding if + // s/he wants to resume/cancel or whatever. Just the way dcc is... + + // if the file exists (dialog is shown) WaitForSingleObject() till the dialog is closed and PS_FILERESUME has been processed. + // dwWhatNeedsDoing will be set using InterlockedExchange() (from other parts of the code depending on action) before SetEvent() is called. + // If the user has chosen rename then InterlockedExchange() will be used for setting NewFileName to a string containing the new name. + // Furthermore dwResumePos will be set using InterlockedExchange() to indicate what the file position to start from is. + if ( ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (void *)di, (LPARAM)&pfts)) { + WaitForSingleObject( hEvent, INFINITE ); + switch( dwWhatNeedsDoing ) { + case FILERESUME_RENAME: + // If the user has chosen to rename the file we need to change variables accordingly. NewFileName has been set using + // InterlockedExchange() + if ( NewFileName) { // the user has chosen to rename the new incoming file. + di->sFileAndPath = NewFileName; + + int i = di->sFileAndPath.ReverseFind( '\\' ); + if ( i != -1 ) { + di->sPath = di->sFileAndPath.Mid(0, i+1); + di->sFile = di->sFileAndPath.Mid(i+1, di->sFileAndPath.GetLength()); + } + + pfts.tszCurrentFile = ( TCHAR* )di->sFileAndPath.c_str(); + pfts.tszWorkingDir = ( TCHAR* )di->sPath.c_str(); + pfts.totalBytes = di->dwSize; + pfts.currentFileSize = pfts.totalBytes; + + delete[] NewFileName; + NewFileName = NULL; + } + break; + + case FILERESUME_OVERWRITE: + case FILERESUME_RESUME : + // no action needed at this point, just break out of the switch statement + break; + + case FILERESUME_CANCEL : + return FALSE; + + case FILERESUME_SKIP : + default: + delete this; // per usual dcc objects destroy themselves when they fail or when connection is closed + return FALSE; + } } + + // hack for passive filetransfers + if ( di->iType == DCC_SEND && !di->bSender && di->bReverse ) { + NETLIBBIND nb = {0}; + nb.cbSize = sizeof(NETLIBBIND); + nb.pfnNewConnectionV2 = DoIncomingDcc; // this is the (helper) function to be called once an incoming connection is made. The 'real' function that is called is IncomingConnection() + nb.pExtra = (void *)this; + nb.wPort = 0; + hBindPort = (HANDLE)CallService( MS_NETLIB_BINDPORT, (WPARAM)m_proto->hNetlibDCC,(LPARAM) &nb); + + if ( hBindPort == NULL ) { + m_proto->DoEvent(GC_EVENT_INFORMATION, 0, m_proto->m_info.sNick.c_str(), LPGENT("DCC ERROR: Unable to bind local port for passive filetransfer"), NULL, NULL, NULL, true, false); + delete this; // dcc objects destroy themselves when the connection has been closed or failed for some reasson. + return 0; + } + + di->iPort = nb.wPort; // store the port internally so it is possible to search for it (for resuming of filetransfers purposes) + + CMString sFileWithQuotes = di->sFile; + + // if spaces in the filename surround with quotes + if ( sFileWithQuotes.Find( ' ', 0 ) != -1 ) { + sFileWithQuotes.Insert( 0, _T("\"")); + sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); + } + + // send out DCC RECV command for passive filetransfers + unsigned long ulAdr = 0; + if ( m_proto->m_manualHost ) + ulAdr = ConvertIPToInteger( m_proto->m_mySpecifiedHostIP ); + else + ulAdr = m_proto->m_IPFromServer ? ConvertIPToInteger( m_proto->m_myHost ) : nb.dwExternalIP; + + if ( di->iPort && ulAdr ) + m_proto->PostIrcMessage( _T("/CTCP %s DCC SEND %s %u %u %I64u %s"), di->sContactName.c_str(), sFileWithQuotes.c_str(), ulAdr, di->iPort, di->dwSize, di->sToken.c_str()); + + return TRUE; + } + + // connect to the remote computer from which you are receiving the file (now all actions to take (resume/overwrite etc) have been decided + NETLIBOPENCONNECTION ncon = { 0 }; + ncon.cbSize = sizeof(ncon); + ncon.szHost = ConvertIntegerToIP(di->dwAdr); + ncon.wPort = (WORD) di->iPort; + + con = (HANDLE) CallService( MS_NETLIB_OPENCONNECTION, (WPARAM)m_proto->hNetlibDCC, (LPARAM) & ncon); + } + + // if for some reason the plugin has failed to connect to the remote computer the object is destroyed. + if ( con == NULL ) { + delete this; + return FALSE; // failed to connect + } + + // if it is a chat connection set the user to online now since we now know there is a connection + if ( di->iType == DCC_CHAT ) + m_proto->setWord(di->hContact, "Status", ID_STATUS_ONLINE); + + // spawn a new thread to handle receiving/sending of data for the new chat/filetransfer connection to the remote computer + mir_forkthread( ThreadProc, this ); + + return con != NULL; +} + +// called by netlib for incoming connections on a listening socket (chat/filetransfer) +int CDccSession::IncomingConnection(HANDLE hConnection, DWORD dwIP) +{ + con = hConnection; + if ( con == NULL ) { + delete this; + return false; // failed to connect + } + + m_proto->setDword(di->hContact, "IP", dwIP); // mToolTip stuff + + if ( di->iType == DCC_CHAT ) + m_proto->setWord(di->hContact, "Status", ID_STATUS_ONLINE); // set chat to online + + // same as above, spawn a new thread to handle receiving/sending of data for the new incoming chat/filetransfer connection + mir_forkthread(ThreadProc, this ); + return true; +} + +// here we decide which function to use for communicating with the remote computer, depending on connection type +void __cdecl CDccSession::ThreadProc(void *pparam) +{ + CDccSession* pThis = (CDccSession*)pparam; + + // if it is an incoming connection on a listening port, then we should close the listenting port so only one can connect (the one you offered + // the connection to) can connect and not evil IRCopers with haxxored IRCDs + if ( pThis->hBindPort ) { + Netlib_CloseHandle(pThis->hBindPort); + pThis->hBindPort = NULL; + } + + if ( pThis->di->iType == DCC_CHAT ) + pThis->DoChatReceive(); // dcc chat + + else if ( !pThis->di->bSender ) + pThis->DoReceiveFile(); // receive a file + + else if ( pThis->di->bSender ) + pThis->DoSendFile(); // send a file +} + +// this is done when the user is initiating a filetransfer to a remote computer +void CDccSession::DoSendFile() +{ + // initialize the filetransfer dialog + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (void *)di, 0); + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (void *)di, 0); + + WORD wPacketSize = m_proto->getWord( "DCCPacketSize", 1024*4); + + if ( wPacketSize < 256 ) + wPacketSize = 256; + + if ( wPacketSize > 32 * 1024 ) + wPacketSize = 32 * 1024; + + BYTE* chBuf = new BYTE[wPacketSize+1]; + + // is there a connection? + if ( con ) { + // open the file for reading + int hFile = _topen( di->sFileAndPath.c_str(), _O_RDONLY | _O_BINARY, _S_IREAD); + if (hFile >= 0) { + unsigned __int64 dwLastAck = 0; + + // if the user has chosen to resume a file, dwResumePos will contain a value (set using InterlockedExchange()) + // and then the variables and the file pointer are changed accordingly. + if ( dwResumePos && dwWhatNeedsDoing == FILERESUME_RESUME ) { + _lseeki64(hFile, dwResumePos, SEEK_SET); + dwTotal = dwResumePos; + dwLastAck = dwResumePos; + pfts.totalProgress = dwResumePos; + pfts.currentFileProgress = dwResumePos; + } + + // initial ack to set the 'percentage-ready meter' to the correct value + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + + tLastActivity = time(0); + + // create a packet receiver to handle receiving ack's from the remote computer. + HANDLE hPackrcver = (HANDLE)CallService( MS_NETLIB_CREATEPACKETRECVER, (WPARAM)con, (LPARAM)sizeof(DWORD)); + NETLIBPACKETRECVER npr; + npr.cbSize = sizeof(NETLIBPACKETRECVER); + npr.dwTimeout = 60*1000; + npr.bufferSize = sizeof(DWORD); + npr.bytesUsed = 0; + + // until the connection is dropped it will spin around in this while() loop + while ( con ) { + // read a packet + int iRead = _read(hFile, chBuf, wPacketSize); + if ( iRead <= 0 ) + break; // break out if everything has already been read + + // send the package + int cbSent = NLSend((unsigned char*)chBuf, iRead); + if ( cbSent <= 0 ) + break; // break out if connection is lost or a transmission error has occured + + if ( !con ) + break; + + dwTotal += cbSent; + + // block connection and receive ack's from remote computer (if applicable) + if ( m_proto->m_DCCMode == 0 ) { + DWORD dwRead = 0; + DWORD dwPacket = NULL; + + do { + dwRead = CallService( MS_NETLIB_GETMOREPACKETS, (WPARAM)hPackrcver, (LPARAM)&npr); + npr.bytesUsed = sizeof(DWORD); + + if ( dwRead <= 0) + break; // connection closed, or a timeout occurred. + + dwPacket = *(DWORD*)npr.buffer; + dwLastAck = ntohl(dwPacket); + + } + while(con && dwTotal != dwLastAck); + + if ( !con || dwRead <= 0 ) + goto DCC_STOP; + } + + if ( m_proto->m_DCCMode == 1 ) { + DWORD dwRead = 0; + DWORD dwPacket = 0; + + do { + dwRead = CallService( MS_NETLIB_GETMOREPACKETS, (WPARAM)hPackrcver, (LPARAM)&npr); + npr.bytesUsed = sizeof(DWORD); + if ( dwRead <= 0) + break; // connection closed, or a timeout occurred. + + dwPacket = *(DWORD*)npr.buffer; + dwLastAck = ntohl(dwPacket); + } + while(con && (di->dwSize != dwTotal + && dwTotal - dwLastAck >= 100*1024 + || di->dwSize == dwTotal // get the last packets when the whole file has been sent + && dwTotal != dwLastAck)); + + if ( !con || dwRead <= 0 ) + goto DCC_STOP; + } + + // update the filetransfer dialog's 'percentage-ready meter' once per second only to save cpu + if ( tLastPercentageUpdate < time(0)) { + tLastPercentageUpdate = time(0); + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + } + + // close the connection once the whole file has been sent an completely ack'ed + if ( dwLastAck >= di->dwSize ) { + Netlib_CloseHandle(con); + con = NULL; + } } + +DCC_STOP: + // need to close the connection if it isn't allready + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } + + // ack the progress one final time + tLastActivity = time(0); + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + + _close(hFile); + } + else // file was not possible to open for reading + { + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } } } + + delete []chBuf; + delete this; // ... and hopefully all went right, cuz here the object is deleted in any case +} + +// This is called when receiving a file from a remote computer. +void CDccSession::DoReceiveFile() +{ + // initialize the filetransfer dialog + ProtoBroadcastAck( m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (void *)di, 0); + + BYTE chBuf[1024*32+1]; + + // do some stupid thing so the filetransfer dialog shows the right thing + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (void *)di, 0); + + // open the file for writing (and reading in case it is a resume) + int hFile = _topen( di->sFileAndPath.c_str(), + (dwWhatNeedsDoing == FILERESUME_RESUME ? _O_APPEND : _O_TRUNC | _O_CREAT) | _O_RDWR | _O_BINARY, + _S_IREAD | _S_IWRITE); + if ( hFile >= 0 ) { + unsigned __int64 dwLastAck = 0; + + // dwResumePos and dwWhatNeedsDoing has possibly been set using InterlockedExchange() + // if set it is a resume and we adjust variables and the file pointer accordingly. + if ( dwResumePos && dwWhatNeedsDoing == FILERESUME_RESUME ) { + _lseeki64(hFile, dwResumePos, SEEK_SET); + dwTotal = dwResumePos; + dwLastAck = dwResumePos; + pfts.totalProgress = dwResumePos; + pfts.currentFileProgress = dwResumePos; + } + + // send an initial ack for the percentage-ready meter + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + + // the while loop will spin around till the connection is dropped, locally or by the remote computer. + while ( con ) { + // read + int cbRead = NLReceive((unsigned char*)chBuf, sizeof(chBuf)); + if ( cbRead <= 0 ) + break; + + // write it to the file + _write(hFile, chBuf, cbRead); + + dwTotal += cbRead; + + // this snippet sends out an ack for every 4 kb received in send ahead + // or every packet for normal mode + if ( !di->bTurbo ) { + DWORD no = dwTotal; + no = htonl(no); + NLSend((unsigned char *)&no, sizeof(DWORD)); + dwLastAck = dwTotal; + } + else dwLastAck = dwTotal; + + // sets the 'last update time' to check for timed out connections, and also make sure we only + // ack the 'percentage-ready meter' only once a second to save CPU. + if ( tLastPercentageUpdate < time( 0 )) { + tLastPercentageUpdate = time (0); + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + } + + // if file size is known and everything is received then disconnect + if ( di->dwSize && di->dwSize == dwTotal ) { + Netlib_CloseHandle(con); + con = NULL; + } } + // receiving loop broken locally or by remote computer, just some cleaning up left.... + + pfts.totalProgress = dwTotal; + pfts.currentFileProgress = dwTotal; + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_DATA, (void *)di, (LPARAM) &pfts); + _close(hFile); + } + else { + ProtoBroadcastAck(m_proto->m_szModuleName, di->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (void *)di, 0); + if ( con ) { // file not possible to open for writing so we ack FAILURE and close the handle + Netlib_CloseHandle(con); + con = NULL; + } } + + delete this; // and finally the object is deleted +} + +// this function handles receiving text in dcc chats and then send it in the protochain. very uncomplicated... +// For sending text the SendStuff() function is called (with the help of some function in CIrcProto to find the right +// Dcc object). See CIrcProto for info on how the dcc objects are stored, retreived and deleted. + +void CDccSession::DoChatReceive() +{ + char chBuf[1024*4+1]; + int cbInBuf = 0; + + // loop to spin around while there is a connection + while( con ) { + int cbRead; + int nLinesProcessed = 0; + + cbRead = NLReceive((unsigned char*)chBuf+cbInBuf, sizeof(chBuf)-cbInBuf-1); + if ( cbRead <= 0 ) + break; + + cbInBuf += cbRead; + chBuf[cbInBuf] = '\0'; + + char* pStart = chBuf; + while( *pStart ) { + char* pEnd; + + // seek end-of-line + for(pEnd=pStart; *pEnd && *pEnd != '\r' && *pEnd != '\n'; ++pEnd) + ; + if ( *pEnd == '\0' ) + break; // uncomplete message. stop parsing. + + ++nLinesProcessed; + + // replace end-of-line with NULLs and skip + while( *pEnd == '\r' || *pEnd == '\n' ) + *pEnd++ = '\0'; + + if ( *pStart ) { + // send it off to some messaging module + + PROTORECVEVENT pre = {0}; + pre.timestamp = (DWORD)time(NULL); +// pre.szMessage = (char*)DoColorCodes((TCHAR*)pStart, true, false); //!!!! // remove color codes + pre.szMessage = pStart; + + CCSDATA ccs = {0}; + ccs.szProtoService = PSR_MESSAGE; + ccs.hContact = di->hContact; + ccs.lParam = (LPARAM) ⪯ + + CallService( MS_PROTO_CHAINRECV, 0, (LPARAM) & ccs); + } + + cbInBuf -= pEnd - pStart; + pStart = pEnd; + } + + // discard processed messages + if ( nLinesProcessed != 0 ) + memmove(chBuf, pStart, cbInBuf+1); + } + + delete this; // delete the object when the connection is dropped +} + +// disconnect the stuff +int CDccSession::Disconnect() +{ + if ( hBindPort ) { + Netlib_CloseHandle(hBindPort); + hBindPort = NULL; + } + + // if 'con' exists it is cuz a connection exists. + // Terminating 'con' will cause any spawned threads to die and then the object will destroy itself. + if ( con ) { + Netlib_CloseHandle(con); + con = NULL; + } + else delete this; // if 'con' do not exist (no connection made so far from the object) the object is destroyed + + return TRUE; +} + +//////////////////////////////////////////////////////////////////// +// check if the dcc chats should disconnect ( default 5 minute timeout ) + +VOID CALLBACK DCCTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( ppro ) + ppro->CheckDCCTimeout(); +} + +// helper function for incoming dcc connections. +void DoIncomingDcc(HANDLE hConnection, DWORD dwRemoteIP, void * p1) +{ + CDccSession* dcc = (CDccSession*)p1; + dcc->IncomingConnection(hConnection, dwRemoteIP); +} + +// ident server + +void strdel( char* parBuffer, int len ) +{ + char* p; + for ( p = parBuffer+len; *p != 0; p++ ) + p[ -len ] = *p; + + p[ -len ] = '\0'; +} + +void DoIdent(HANDLE hConnection, DWORD, void* extra ) +{ + CIrcProto* ppro = ( CIrcProto* )extra; + + char szBuf[1024]; + int cbTotal = 0; + + for (;;) { + int cbRead = Netlib_Recv(hConnection, szBuf+cbTotal, sizeof(szBuf)-1-cbTotal, 0); + if ( cbRead == SOCKET_ERROR || cbRead == 0) + break; + + cbTotal += cbRead; + szBuf[cbTotal] = '\0'; + +LBL_Parse: + char* EOLPos = strstr(szBuf, "\r\n"); + if (EOLPos == NULL) + continue; + + EOLPos[0] = EOLPos[1] = '\0'; + rtrim( szBuf ); + ppro->DoNetlibLog("Got Ident request: %s", szBuf); + + unsigned int PeerPortNrRcvd = 0, LocalPortNrRcvd = 0; + int iParamCnt = sscanf( szBuf, "%d , %d", &LocalPortNrRcvd, &PeerPortNrRcvd ); + + int cbLen = 0; + char buf[1024*4]; + + if (iParamCnt != 2) + cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : ERROR : UNKNOWN-ERROR\r\n", szBuf); + else + { + for (int i = 0; i < g_Instances.getCount(); i++) + { + if (PeerPortNrRcvd == g_Instances[i]->m_info.iPort && LocalPortNrRcvd == g_Instances[i]->m_myLocalPort) + { + cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : USERID : " TCHAR_STR_PARAM " : " TCHAR_STR_PARAM "\r\n", + szBuf, g_Instances[i]->m_info.sIdentServerType.c_str() , g_Instances[i]->m_info.sUserID.c_str()); + break; + } + } + + if (cbLen == 0) + cbLen = mir_snprintf(buf, SIZEOF(buf), "%s : ERROR : INVALID-PORT\r\n", szBuf); + } + + if ( Netlib_Send(hConnection, (const char*)buf, cbLen, 0) > 0) + ppro->DoNetlibLog("Sent Ident answer: %s", buf); + else + ppro->DoNetlibLog("Sending Ident answer failed."); + + if ( ppro->m_identTimer ) + break; + + cbTotal -= EOLPos + 2 - szBuf; + strdel(szBuf, int(EOLPos + 2 - szBuf)); + goto LBL_Parse; + } + Netlib_CloseHandle(hConnection); +} diff --git a/protocols/IRCG/src/irclib.h b/protocols/IRCG/src/irclib.h new file mode 100644 index 0000000000..7dcb5a4c01 --- /dev/null +++ b/protocols/IRCG/src/irclib.h @@ -0,0 +1,175 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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. +*/ + +#ifndef _IRC_H_ +#define _IRC_H_ + +#pragma warning (disable: 4786) + +void DoIdent(HANDLE hConnection, DWORD dwRemoteIP, void* extra); +void DoIncomingDcc(HANDLE hConnection, DWORD dwRemoteIP, void* extra); +unsigned long ConvertIPToInteger(char * IP); +char* ConvertIntegerToIP(unsigned long int_ip_addr); + +//////////////////////////////////////////////////////////////////// +namespace irc { +//////////////////////////////////////////////////////////////////// + +struct DCCINFO : public MZeroedObject +{ + DWORD dwAdr; + unsigned __int64 dwSize; + DWORD iType; + CMString sToken; + int iPort; + BOOL bTurbo; + BOOL bSSL; + BOOL bSender; + BOOL bReverse; + CMString sPath; + CMString sFile; + CMString sFileAndPath; + CMString sHostmask; + HANDLE hContact; + CMString sContactName; +}; + +class CIrcMessage +{ +public : + struct Prefix + { + CMString sNick, sUser, sHost; + } + prefix; + + CIrcProto* m_proto; + CMString sCommand; + OBJLIST parameters; + bool m_bIncoming; + bool m_bNotify; + int m_codePage; + + //CIrcMessage( CIrcProto* ); // default constructor + CIrcMessage( CIrcProto*, const TCHAR* lpszCmdLine, int codepage, bool bIncoming=false, bool bNotify = true); // parser constructor + CIrcMessage( const CIrcMessage& m ); // copy constructor + ~CIrcMessage(); + + void Reset(); + + CIrcMessage& operator = (const CIrcMessage& m); + CIrcMessage& operator = (const TCHAR* lpszCmdLine); + +private : + void ParseIrcCommand(const TCHAR* lpszCmdLine); +}; + +//////////////////////////////////////////////////////////////////// + +struct CIrcSessionInfo +{ + String sServer; + CMString sServerName; + CMString sNick; + CMString sUserID; + CMString sFullName; + String sPassword; + CMString sIdentServerType; + CMString sNetwork; + bool bIdentServer; + bool bNickFlag; + int m_iSSL; + unsigned int iIdentServerPort; + unsigned int iPort; + + CIrcSessionInfo(); + CIrcSessionInfo(const CIrcSessionInfo& si); + + void Reset(); +}; + +//////////////////////////////////////////////////////////////////// + +struct CIrcIgnoreItem +{ + CIrcIgnoreItem( const TCHAR*, const TCHAR*, const TCHAR* ); + CIrcIgnoreItem( int codepage, const char*, const char*, const char* ); + ~CIrcIgnoreItem(); + + CMString mask, flags, network; +}; + +//////////////////////////////////////////////////////////////////// + +class CDccSession +{ +protected: + CIrcProto* m_proto; + HANDLE con; // connection handle + HANDLE hBindPort; // handle for listening port + static int nDcc; // number of dcc objects + unsigned __int64 dwTotal; // total bytes sent/received + + int iPacketSize; // size of outgoing packets + int iGlobalToken; + + PROTOFILETRANSFERSTATUS pfts; // structure used to setup and update the filetransfer dialogs of miranda + TCHAR* file[2]; + + int SetupConnection(); + void DoSendFile(); + void DoReceiveFile(); + void DoChatReceive(); + int NLSend( const unsigned char* buf, int cbBuf); + int NLReceive(const unsigned char* buf, int cbBuf); + static void __cdecl ThreadProc(void *pparam); + static void __cdecl ConnectProc(void *pparam); + +public: + + CDccSession(CIrcProto*, DCCINFO* pdci); // constructor + ~CDccSession(); // destructor, ÷òî õàðàêòåðíî + + time_t tLastPercentageUpdate; // time of last update of the filetransfer dialog + time_t tLastActivity; // time of last in/out activity of the object + time_t tLastAck; // last acked filesize + + HANDLE hEvent; // Manual object + long dwWhatNeedsDoing; // Set to indicate what FILERESUME_ action is chosen by the user + TCHAR* NewFileName; // contains new file name if FILERESUME_RENAME chosen + unsigned __int64 dwResumePos; // position to resume from if FILERESUME_RESUME + + int iToken; // used to identify (find) objects in reverse dcc filetransfers + + DCCINFO* di; // details regarding the filetrasnfer + + int Connect(); + void SetupPassive( DWORD adr, DWORD port ); + int SendStuff(const TCHAR* fmt); + int IncomingConnection(HANDLE hConnection, DWORD dwIP); + int Disconnect(); +}; + +//////////////////////////////////////////////////////////////////// +}; // end of namespace irc +//////////////////////////////////////////////////////////////////// + +#endif // _IRC_H_ diff --git a/protocols/IRCG/src/ircproto.cpp b/protocols/IRCG/src/ircproto.cpp new file mode 100644 index 0000000000..9ff2a1c851 --- /dev/null +++ b/protocols/IRCG/src/ircproto.cpp @@ -0,0 +1,1076 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" +#include "version.h" + +#include + +static int CompareSessions( const CDccSession* p1, const CDccSession* p2 ) +{ + return INT_PTR( p1->di->hContact ) - INT_PTR( p2->di->hContact ); +} + +CIrcProto::CIrcProto( const char* szModuleName, const TCHAR* tszUserName ) : + m_dcc_chats( 10, CompareSessions ), + m_dcc_xfers( 10, CompareSessions ), + m_ignoreItems( 10 ), + vUserhostReasons( 10 ), + vWhoInProgress( 10 ) +{ + m_iVersion = 2; + m_tszUserName = mir_tstrdup( tszUserName ); + m_szModuleName = mir_strdup( szModuleName ); + + InitializeCriticalSection(&cs); + InitializeCriticalSection(&m_gchook); + m_evWndCreate = ::CreateEvent( NULL, FALSE, FALSE, NULL ); + + CreateProtoService( PS_GETMYAWAYMSG, &CIrcProto::GetMyAwayMsg ); + + CreateProtoService( PS_CREATEACCMGRUI, &CIrcProto::SvcCreateAccMgrUI ); + CreateProtoService( PS_JOINCHAT, &CIrcProto::OnJoinChat ); + CreateProtoService( PS_LEAVECHAT, &CIrcProto::OnLeaveChat ); + + CreateProtoService( IRC_JOINCHANNEL, &CIrcProto::OnJoinMenuCommand ); + CreateProtoService( IRC_QUICKCONNECT, &CIrcProto::OnQuickConnectMenuCommand); + CreateProtoService( IRC_CHANGENICK, &CIrcProto::OnChangeNickMenuCommand ); + CreateProtoService( IRC_SHOWLIST, &CIrcProto::OnShowListMenuCommand ); + CreateProtoService( IRC_SHOWSERVER, &CIrcProto::OnShowServerMenuCommand ); + CreateProtoService( IRC_UM_CHANSETTINGS, &CIrcProto::OnMenuChanSettings ); + CreateProtoService( IRC_UM_WHOIS, &CIrcProto::OnMenuWhois ); + CreateProtoService( IRC_UM_DISCONNECT, &CIrcProto::OnMenuDisconnect ); + CreateProtoService( IRC_UM_IGNORE, &CIrcProto::OnMenuIgnore ); + + CreateProtoService( "/DblClickEvent", &CIrcProto::OnDoubleclicked ); + CreateProtoService( "/InsertRawIn", &CIrcProto::Scripting_InsertRawIn ); + CreateProtoService( "/InsertRawOut", &CIrcProto::Scripting_InsertRawOut ); + CreateProtoService( "/InsertGuiIn", &CIrcProto::Scripting_InsertGuiIn ); + CreateProtoService( "/InsertGuiOut", &CIrcProto::Scripting_InsertGuiOut); + CreateProtoService( "/GetIrcData", &CIrcProto::Scripting_GetIrcData); + + codepage = CP_ACP; + InitializeCriticalSection(&m_resolve); + InitializeCriticalSection(&m_dcc); + + InitPrefs(); + + char text[ MAX_PATH ]; + mir_snprintf( text, sizeof( text ), "%s/Status", m_szProtoName ); + CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text ); + + CList_SetAllOffline(true); + AddIcons(); + + IRC_MAP_ENTRY("PING", PING) + IRC_MAP_ENTRY("JOIN", JOIN) + IRC_MAP_ENTRY("QUIT", QUIT) + IRC_MAP_ENTRY("KICK", KICK) + IRC_MAP_ENTRY("MODE", MODE) + IRC_MAP_ENTRY("NICK", NICK) + IRC_MAP_ENTRY("PART", PART) + IRC_MAP_ENTRY("PRIVMSG", PRIVMSG) + IRC_MAP_ENTRY("TOPIC", TOPIC) + IRC_MAP_ENTRY("NOTICE", NOTICE) + IRC_MAP_ENTRY("PING", PINGPONG) + IRC_MAP_ENTRY("PONG", PINGPONG) + IRC_MAP_ENTRY("INVITE", INVITE) + IRC_MAP_ENTRY("ERROR", ERROR) + IRC_MAP_ENTRY("001", WELCOME) + IRC_MAP_ENTRY("002", YOURHOST) + IRC_MAP_ENTRY("005", SUPPORT) + IRC_MAP_ENTRY("223", WHOIS_OTHER) //CodePage info + IRC_MAP_ENTRY("254", NOOFCHANNELS) + IRC_MAP_ENTRY("263", TRYAGAIN) + IRC_MAP_ENTRY("264", WHOIS_OTHER) //Encryption info (SSL connect) + IRC_MAP_ENTRY("301", WHOIS_AWAY) + IRC_MAP_ENTRY("302", USERHOST_REPLY) + IRC_MAP_ENTRY("305", BACKFROMAWAY) + IRC_MAP_ENTRY("306", SETAWAY) + IRC_MAP_ENTRY("307", WHOIS_AUTH) + IRC_MAP_ENTRY("310", WHOIS_OTHER) + IRC_MAP_ENTRY("311", WHOIS_NAME) + IRC_MAP_ENTRY("312", WHOIS_SERVER) + IRC_MAP_ENTRY("313", WHOIS_OTHER) + IRC_MAP_ENTRY("315", WHO_END) + IRC_MAP_ENTRY("317", WHOIS_IDLE) + IRC_MAP_ENTRY("318", WHOIS_END) + IRC_MAP_ENTRY("319", WHOIS_CHANNELS) + IRC_MAP_ENTRY("320", WHOIS_AUTH) + IRC_MAP_ENTRY("321", LISTSTART) + IRC_MAP_ENTRY("322", LIST) + IRC_MAP_ENTRY("323", LISTEND) + IRC_MAP_ENTRY("324", MODEQUERY) + IRC_MAP_ENTRY("330", WHOIS_AUTH) + IRC_MAP_ENTRY("332", INITIALTOPIC) + IRC_MAP_ENTRY("333", INITIALTOPICNAME) + IRC_MAP_ENTRY("352", WHO_REPLY) + IRC_MAP_ENTRY("353", NAMES) + IRC_MAP_ENTRY("366", ENDNAMES) + IRC_MAP_ENTRY("367", BANLIST) + IRC_MAP_ENTRY("368", BANLISTEND) + IRC_MAP_ENTRY("346", BANLIST) + IRC_MAP_ENTRY("347", BANLISTEND) + IRC_MAP_ENTRY("348", BANLIST) + IRC_MAP_ENTRY("349", BANLISTEND) + IRC_MAP_ENTRY("371", WHOIS_OTHER) + IRC_MAP_ENTRY("376", ENDMOTD) + IRC_MAP_ENTRY("401", WHOIS_NO_USER) + IRC_MAP_ENTRY("403", JOINERROR) + IRC_MAP_ENTRY("416", WHOTOOLONG) + IRC_MAP_ENTRY("421", UNKNOWN) + IRC_MAP_ENTRY("422", ENDMOTD) + IRC_MAP_ENTRY("433", NICK_ERR) + IRC_MAP_ENTRY("471", JOINERROR) + IRC_MAP_ENTRY("473", JOINERROR) + IRC_MAP_ENTRY("474", JOINERROR) + IRC_MAP_ENTRY("475", JOINERROR) + IRC_MAP_ENTRY("671", WHOIS_OTHER) //Encryption info (SSL connect) +} + +CIrcProto::~CIrcProto() +{ + if ( con ) { + Netlib_CloseHandle( con ); + con = NULL; + } + + Netlib_CloseHandle(hNetlib); hNetlib = NULL; + Netlib_CloseHandle(hNetlibDCC); hNetlibDCC = NULL; + + m_dcc_chats.destroy(); + m_dcc_xfers.destroy(); + + DeleteCriticalSection( &cs ); + DeleteCriticalSection( &m_gchook ); + + if (hMenuRoot) + CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )hMenuRoot, 0 ); + + mir_free( m_alias ); + mir_free( m_szModuleName ); + mir_free( m_tszUserName ); + + CloseHandle( m_evWndCreate ); + DeleteCriticalSection(&m_resolve); + DeleteCriticalSection(&m_dcc); + KillChatTimer(OnlineNotifTimer); + KillChatTimer(OnlineNotifTimer3); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// OnModulesLoaded - performs hook registration + +static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + +static int sttCheckPerform( const char *szSetting, LPARAM lParam ) +{ + if ( !_strnicmp( szSetting, "PERFORM:", 8 )) { + String s = szSetting; + s.MakeUpper(); + if ( s != szSetting ) { + OBJLIST* p = ( OBJLIST* )lParam; + p->insert( new String( szSetting )); + } } + return 0; +} + +int CIrcProto::OnModulesLoaded( WPARAM, LPARAM ) +{ + char szTemp3[256]; + NETLIBUSER nlu = {0}; + TCHAR name[128]; + + DBDeleteContactSetting( NULL, m_szModuleName, "JTemp" ); + + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING|NUF_INCOMING|NUF_HTTPCONNS|NUF_TCHAR; + nlu.szSettingsModule = m_szModuleName; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s server connection"), m_tszUserName); + nlu.ptszDescriptiveName = name; + hNetlib=(HANDLE)CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + nlu.flags = NUF_OUTGOING|NUF_INCOMING|NUF_HTTPCONNS|NUF_TCHAR; + char szTemp2[256]; + mir_snprintf(szTemp2, sizeof(szTemp2), "%s DCC", m_szModuleName); + nlu.szSettingsModule = szTemp2; + mir_sntprintf( name, SIZEOF(name), TranslateT("%s client-to-client connections"), m_tszUserName); + nlu.ptszDescriptiveName = name; + hNetlibDCC=(HANDLE)CallService( MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + //add as a known module in DB Editor ++ + CallService( "DBEditorpp/RegisterSingleModule",(WPARAM)m_szModuleName,0); + mir_snprintf(szTemp3, sizeof(szTemp3), "%s DCC", m_szModuleName); + CallService( "DBEditorpp/RegisterSingleModule",(WPARAM)szTemp3,0); + + if ( ServiceExists("MBot/GetFcnTable")) { + CallService( MS_MBOT_REGISTERIRC, 0, (LPARAM)m_szModuleName); + m_bMbotInstalled = TRUE; + } + + if ( ServiceExists( MS_GC_REGISTER )) { + GCREGISTER gcr = {0}; + gcr.cbSize = sizeof(GCREGISTER); + gcr.dwFlags = GC_CHANMGR | GC_BOLD | GC_ITALICS | GC_UNDERLINE | GC_COLOR | GC_BKGCOLOR | GC_TCHAR; + gcr.iMaxText = 0; + gcr.nColors = 16; + gcr.pColors = colors; + gcr.ptszModuleDispName = m_tszUserName; + gcr.pszModule = m_szModuleName; + CallServiceSync( MS_GC_REGISTER, NULL, (LPARAM)&gcr ); + IrcHookEvent( ME_GC_EVENT, &CIrcProto::GCEventHook ); + IrcHookEvent( ME_GC_BUILDMENU, &CIrcProto::GCMenuHook ); + + GCSESSION gcw = {0}; + GCDEST gcd = {0}; + GCEVENT gce = {0}; + + gcw.cbSize = sizeof(GCSESSION); + gcw.dwFlags = GC_TCHAR; + gcw.iType = GCW_SERVER; + gcw.ptszID = SERVERWINDOW; + gcw.pszModule = m_szModuleName; + gcw.ptszName = NEWTSTR_ALLOCA(( TCHAR* )_A2T( m_network )); + CallServiceSync( MS_GC_NEWSESSION, 0, (LPARAM)&gcw ); + + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + gcd.ptszID = SERVERWINDOW; + gcd.pszModule = m_szModuleName; + gcd.iType = GC_EVENT_CONTROL; + + gce.pDest = &gcd; + if ( m_useServer && !m_hideServerWindow ) + CallChatEvent( WINDOW_VISIBLE, (LPARAM)&gce); + else + CallChatEvent( WINDOW_HIDDEN, (LPARAM)&gce); + bChatInstalled = TRUE; + } + else { + if ( IDYES == MessageBox(0,TranslateT("The IRC protocol depends on another plugin called \'Chat\'\n\nDo you want to download it from the Miranda NG web site now?"),TranslateT("Information"),MB_YESNO|MB_ICONINFORMATION )) + CallService( MS_UTILS_OPENURL, 1, (LPARAM) "http://miranda-ng.org/"); + } + + TCHAR szTemp[MAX_PATH]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%miranda_path%%\\Plugins\\") _T(TCHAR_STR_PARAM) _T("_perform.ini"), m_szModuleName); + TCHAR *szLoadFileName = Utils_ReplaceVarsT( szTemp ); + char* pszPerformData = IrcLoadFile( szLoadFileName ); + if ( pszPerformData != NULL ) { + char *p1 = pszPerformData, *p2 = pszPerformData; + while (( p1 = strstr( p2, "NETWORK: " )) != NULL ) { + p1 += 9; + p2 = strchr(p1, '\n'); + String sNetwork( p1, int( p2-p1-1 )); + sNetwork.MakeUpper(); + p1 = p2; + p2 = strstr( ++p1, "\nNETWORK: " ); + if ( !p2 ) + p2 = p1 + lstrlenA( p1 )-1; + if ( p1 == p2 ) + break; + + *p2++ = 0; + setString(("PERFORM:" + sNetwork).c_str(), rtrim( p1 )); + } + delete[] pszPerformData; + ::_tremove( szLoadFileName ); + } + mir_free( szLoadFileName ); + + if ( !getByte( "PerformConversionDone", 0 )) { + OBJLIST performToConvert( 10 ); + DBCONTACTENUMSETTINGS dbces; + dbces.pfnEnumProc = sttCheckPerform; + dbces.lParam = ( LPARAM )&performToConvert; + dbces.szModule = m_szModuleName; + CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); + + for ( int i = 0; i < performToConvert.getCount(); i++ ) { + String s = performToConvert[i]; + DBVARIANT dbv; + if ( !getTString( s, &dbv )) { + DBDeleteContactSetting( NULL, m_szModuleName, s ); + s.MakeUpper(); + setTString( s, dbv.ptszVal ); + DBFreeVariant( &dbv ); + } } + + setByte( "PerformConversionDone", 1 ); + } + + InitIgnore(); + + IrcHookEvent( ME_USERINFO_INITIALISE, &CIrcProto::OnInitUserInfo ); + IrcHookEvent( ME_OPT_INITIALISE, &CIrcProto::OnInitOptionsPages ); + + if ( m_nick[0] ) { + TCHAR szBuf[ 40 ]; + if ( lstrlen( m_alternativeNick ) == 0 ) { + mir_sntprintf( szBuf, SIZEOF(szBuf), _T("%s%u"), m_nick, rand()%9999); + setTString("AlernativeNick", szBuf); + lstrcpyn(m_alternativeNick, szBuf, 30); + } + + if ( lstrlen( m_name ) == 0 ) { + mir_sntprintf( szBuf, SIZEOF(szBuf), _T("Miranda%u"), rand()%9999); + setTString("Name", szBuf); + lstrcpyn( m_name, szBuf, 200 ); + } } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AddToList - adds a contact to the contact list + +HANDLE __cdecl CIrcProto::AddToList( int, PROTOSEARCHRESULT* psr ) +{ + if ( m_iStatus == ID_STATUS_OFFLINE || m_iStatus == ID_STATUS_CONNECTING ) + return 0; + + TCHAR *id = psr->id ? psr->id : psr->nick; + id = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)id) : mir_a2t((char*)id); + + CONTACT user = { id, NULL, NULL, true, false, false }; + HANDLE hContact = CList_AddContact( &user, true, false ); + + if ( hContact ) { + DBVARIANT dbv1; + CMString S = _T("S"); + + if ( getByte( hContact, "AdvancedMode", 0 ) == 0 ) { + S += user.name; + DoUserhostWithReason( 1, S, true, user.name ); + } + else { + if ( !getTString(hContact, "UWildcard", &dbv1 )) { + S += dbv1.ptszVal; + DoUserhostWithReason(2, S, true, dbv1.ptszVal); + DBFreeVariant( &dbv1 ); + } + else { + S += user.name; + DoUserhostWithReason( 2, S, true, user.name ); + } + } + if (getByte( "MirVerAutoRequest", 1)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), user.name); + } + + mir_free(id); + return hContact; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AddToList - adds a contact to the contact list + +HANDLE __cdecl CIrcProto::AddToListByEvent( int, int, HANDLE ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AuthAllow - processes the successful authorization + +int __cdecl CIrcProto::Authorize( HANDLE ) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// AuthDeny - handles the unsuccessful authorization + +int __cdecl CIrcProto::AuthDeny( HANDLE, const TCHAR* ) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AUTH + +int __cdecl CIrcProto::AuthRecv( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AUTHREQUEST + +int __cdecl CIrcProto::AuthRequest( HANDLE, const TCHAR* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// ChangeInfo + +HANDLE __cdecl CIrcProto::ChangeInfo( int, void* ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileAllow - starts a file transfer + +HANDLE __cdecl CIrcProto::FileAllow( HANDLE, HANDLE hTransfer, const TCHAR* szPath ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + + if ( !IsConnected()) { + delete di; + return (HANDLE)szPath; + } + + di->sPath = szPath; + di->sFileAndPath = di->sPath + di->sFile; + + CDccSession* dcc = new CDccSession( this, di ); + AddDCCSession( di, dcc ); + dcc->Connect(); + return di; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileCancel - cancels a file transfer + +int __cdecl CIrcProto::FileCancel( HANDLE, HANDLE hTransfer ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + + CDccSession* dcc = FindDCCSession(di); + if (dcc) { + InterlockedExchange(&dcc->dwWhatNeedsDoing, (long)FILERESUME_CANCEL); + SetEvent(dcc->hEvent); + dcc->Disconnect(); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileDeny - denies a file transfer + +int __cdecl CIrcProto::FileDeny( HANDLE, HANDLE hTransfer, const TCHAR* ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + delete di; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// FileResume - processes file renaming etc + +int __cdecl CIrcProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) +{ + DCCINFO* di = ( DCCINFO* )hTransfer; + + long i = (long)*action; + + CDccSession* dcc = FindDCCSession(di); + if (dcc) { + InterlockedExchange(&dcc->dwWhatNeedsDoing, i); + if (*action == FILERESUME_RENAME) { + TCHAR* szTemp = _tcsdup(*szFilename); + InterlockedExchangePointer((PVOID*)&dcc->NewFileName, szTemp); + } + + if (*action == FILERESUME_RESUME) { + unsigned __int64 dwPos = 0; + + struct _stati64 statbuf; + if (_tstati64(di->sFileAndPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) + dwPos = statbuf.st_size; + + CMString sFileWithQuotes = di->sFile; + + // if spaces in the filename surround witrh quotes + if (sFileWithQuotes.Find( ' ', 0 ) != -1 ) { + sFileWithQuotes.Insert( 0, _T("\"")); + sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); + } + + if (di->bReverse) + PostIrcMessage( _T("/PRIVMSG %s \001DCC RESUME %s 0 %I64u %s\001"), di->sContactName.c_str(), sFileWithQuotes.c_str(), dwPos, dcc->di->sToken.c_str()); + else + PostIrcMessage( _T("/PRIVMSG %s \001DCC RESUME %s %u %I64u\001"), di->sContactName.c_str(), sFileWithQuotes.c_str(), di->iPort, dwPos); + + return 0; + } + + SetEvent(dcc->hEvent); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetCaps - return protocol capabilities bits + +DWORD_PTR __cdecl CIrcProto::GetCaps( int type, HANDLE ) +{ + switch( type ) { + case PFLAGNUM_1: + return PF1_BASICSEARCH | PF1_MODEMSG | PF1_FILE | PF1_CHAT | PF1_CANRENAMEFILE | PF1_PEER2PEER | PF1_IM; + + case PFLAGNUM_2: + return PF2_ONLINE | PF2_SHORTAWAY; + + case PFLAGNUM_3: + return PF2_SHORTAWAY; + + case PFLAGNUM_4: + return PF4_NOAUTHDENYREASON | PF4_NOCUSTOMAUTH | PF4_IMSENDUTF; + + case PFLAG_UNIQUEIDTEXT: + return (DWORD_PTR) Translate("Nickname"); + + case PFLAG_MAXLENOFMESSAGE: + return 400; + + case PFLAG_UNIQUEIDSETTING: + return (DWORD_PTR) "Nick"; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetIcon - loads an icon for the contact list + +HICON __cdecl CIrcProto::GetIcon( int iconIndex ) +{ + if (LOWORD(iconIndex) == PLI_PROTOCOL) + { + if (iconIndex & PLIF_ICOLIBHANDLE) + return (HICON)GetIconHandle(IDI_MAIN); + + bool big = (iconIndex & PLIF_SMALL) == 0; + HICON hIcon = LoadIconEx(IDI_MAIN, big); + + if (iconIndex & PLIF_ICOLIB) + return hIcon; + + HICON hIcon2 = CopyIcon(hIcon); + ReleaseIconEx(hIcon); + return hIcon2; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetInfo - retrieves a contact info + +int __cdecl CIrcProto::GetInfo( HANDLE, int ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchBasic - searches the contact by JID + +struct AckBasicSearchParam +{ + PROTOCHAR buf[ 50 ]; +}; + +void __cdecl CIrcProto::AckBasicSearch( void* param ) +{ + PROTOSEARCHRESULT psr = { 0 }; + psr.cbSize = sizeof(psr); + psr.flags = PSR_TCHAR; + psr.id = (( AckBasicSearchParam* )param )->buf; + psr.nick = (( AckBasicSearchParam* )param )->buf; + ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr); + ProtoBroadcastAck( m_szModuleName, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + delete param; +} + +HANDLE __cdecl CIrcProto::SearchBasic( const PROTOCHAR* szId ) +{ + if ( szId ) { + if (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING && + szId && szId[0] && !IsChannel(szId)) { + AckBasicSearchParam* param = new AckBasicSearchParam; + lstrcpyn( param->buf, szId, 50 ); + ircFork( &CIrcProto::AckBasicSearch, param ); + return ( HANDLE )1; + } } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByEmail - searches the contact by its e-mail + +HANDLE __cdecl CIrcProto::SearchByEmail( const PROTOCHAR* ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// upsupported search functions + +HANDLE __cdecl CIrcProto::SearchByName( const PROTOCHAR*, const PROTOCHAR*, const PROTOCHAR* ) +{ + return NULL; +} + +HWND __cdecl CIrcProto::CreateExtendedSearchUI( HWND ) +{ + return NULL; +} + +HWND __cdecl CIrcProto::SearchAdvanced( HWND ) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvContacts + +int __cdecl CIrcProto::RecvContacts( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvFile + +int __cdecl CIrcProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt ) +{ + return Proto_RecvFile(hContact, evt); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvMsg + +int __cdecl CIrcProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* evt ) +{ + return Proto_RecvMessage(hContact, evt); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvUrl + +int __cdecl CIrcProto::RecvUrl( HANDLE, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendContacts + +int __cdecl CIrcProto::SendContacts( HANDLE, int, int, HANDLE* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendFile - sends a file + +HANDLE __cdecl CIrcProto::SendFile( HANDLE hContact, const TCHAR*, TCHAR** ppszFiles ) +{ + DCCINFO* dci = NULL; + int iPort = 0; + int index= 0; + unsigned __int64 size = 0; + + // do not send to channels :-P + if ( getByte(hContact, "ChatRoom", 0) != 0) + return 0; + + // stop if it is an active type filetransfer and the user's IP is not known + unsigned long ulAdr = 0; + if (m_manualHost) + ulAdr = ConvertIPToInteger(m_mySpecifiedHostIP); + else + ulAdr = ConvertIPToInteger(m_IPFromServer?m_myHost:m_myLocalHost); + + if (!m_DCCPassive && !ulAdr) { + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), TranslateT("DCC ERROR: Unable to automatically resolve external IP"), NULL, NULL, NULL, true, false); + return 0; + } + + if ( ppszFiles[index] ) { + + //get file size + while (ppszFiles[index]) { + struct _stati64 statbuf; + if (_tstati64(ppszFiles[index], &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0) { + size = statbuf.st_size; + break; + } + index++; + } + + if (size == 0) { + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), TranslateT("DCC ERROR: No valid files specified"), NULL, NULL, NULL, true, false); + return 0; + } + + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + // set up a basic DCCINFO struct and pass it to a DCC object + dci = new DCCINFO; + dci->sFileAndPath = ppszFiles[index]; + + int i = dci->sFileAndPath.ReverseFind( '\\' ); + if (i != -1) { + dci->sPath = dci->sFileAndPath.Mid(0, i+1); + dci->sFile = dci->sFileAndPath.Mid(i+1, dci->sFileAndPath.GetLength()); + } + + CMString sFileWithQuotes = dci->sFile; + + // if spaces in the filename surround witrh quotes + if ( sFileWithQuotes.Find( ' ', 0 ) != -1) { + sFileWithQuotes.Insert( 0, _T("\"")); + sFileWithQuotes.Insert( sFileWithQuotes.GetLength(), _T("\"")); + } + + dci->hContact = hContact; + dci->sContactName = dbv.ptszVal; + dci->iType = DCC_SEND; + dci->bReverse = m_DCCPassive?true:false; + dci->bSender = true; + dci->dwSize = size; + + // create new dcc object + CDccSession* dcc = new CDccSession(this,dci); + + // keep track of all objects created + AddDCCSession(dci, dcc); + + // need to make sure that %'s are doubled to avoid having chat interpret as color codes + CMString sFileCorrect = dci->sFile; + ReplaceString(sFileCorrect, _T("%"), _T("%%")); + + // is it an reverse filetransfer (receiver acts as server) + if (dci->bReverse) { + TCHAR szTemp[256]; + PostIrcMessage( _T("/CTCP %s DCC SEND %s 200 0 %I64u %u"), + dci->sContactName.c_str(), sFileWithQuotes.c_str(), dci->dwSize, dcc->iToken); + + mir_sntprintf(szTemp, SIZEOF(szTemp), + TranslateT("DCC reversed file transfer request sent to %s [%s]"), + dci->sContactName.c_str(), sFileCorrect.c_str()); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + + if (m_sendNotice) { + mir_sntprintf(szTemp, SIZEOF(szTemp), + _T("/NOTICE %s I am sending the file \'\002%s\002\' (%I64u kB) to you, please accept it. [Reverse transfer]"), + dci->sContactName.c_str(), sFileCorrect.c_str(), dci->dwSize/1024); + PostIrcMessage(szTemp); + } + } + else { // ... normal filetransfer. + iPort = dcc->Connect(); + if ( iPort ) { + TCHAR szTemp[256]; + PostIrcMessage( _T("/CTCP %s DCC SEND %s %u %u %I64u"), + dci->sContactName.c_str(), sFileWithQuotes.c_str(), ulAdr, iPort, dci->dwSize); + + mir_sntprintf(szTemp, SIZEOF(szTemp), + TranslateT("DCC file transfer request sent to %s [%s]"), + dci->sContactName.c_str(), sFileCorrect.c_str()); + DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), szTemp, NULL, NULL, NULL, true, false); + + if ( m_sendNotice ) { + mir_sntprintf(szTemp, SIZEOF(szTemp), + _T("/NOTICE %s I am sending the file \'\002%s\002\' (%I64u kB) to you, please accept it. [IP: %s]"), + dci->sContactName.c_str(), sFileCorrect.c_str(), dci->dwSize/1024, (TCHAR*)_A2T(ConvertIntegerToIP(ulAdr))); + PostIrcMessage(szTemp); + } + } + else DoEvent(GC_EVENT_INFORMATION, 0, m_info.sNick.c_str(), + TranslateT("DCC ERROR: Unable to bind local port"), NULL, NULL, NULL, true, false); + } + + // fix for sending multiple files + index++; + while( ppszFiles[index] ) { + if ( _taccess(ppszFiles[index], 0) == 0 ) { + PostIrcMessage( _T("/DCC SEND %s ") _T(TCHAR_STR_PARAM), dci->sContactName.c_str(), ppszFiles[index]); + } + index++; + } + + DBFreeVariant( &dbv ); + } } + + if (dci) + return dci; + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendMessage - sends a message + +void __cdecl CIrcProto::AckMessageFail( void* info ) +{ + ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("The protocol is not online")); +} + +void __cdecl CIrcProto::AckMessageFailDcc( void* info ) +{ + ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("The dcc chat connection is not active")); +} + +void __cdecl CIrcProto::AckMessageSuccess( void* info ) +{ + ProtoBroadcastAck( m_szModuleName, info, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) 1, 0); +} + +int __cdecl CIrcProto::SendMsg( HANDLE hContact, int flags, const char* pszSrc ) +{ + BYTE bDcc = getByte( hContact, "DCC", 0) ; + WORD wStatus = getWord( hContact, "Status", ID_STATUS_OFFLINE) ; + if ( m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING && !bDcc || bDcc && wStatus == ID_STATUS_ONLINE ) { + int codepage = getCodepage(); + + TCHAR* result; + if ( flags & PREF_UNICODE ) { + const char* p = strchr( pszSrc, '\0' ); + if ( p != pszSrc ) { + while ( *(++p) == '\0' ) + ; + result = mir_u2t_cp(( wchar_t* )p, codepage ); + } + else result = mir_a2t_cp( pszSrc, codepage ); + } + else if ( flags & PREF_UTF ) { + mir_utf8decode( NEWSTR_ALLOCA(pszSrc), &result ); + } + else result = mir_a2t_cp( pszSrc, codepage ); + + PostIrcMessageWnd(NULL, hContact, result ); + mir_free( result ); + ircFork( &CIrcProto::AckMessageSuccess, hContact ); + } + else { + if ( bDcc ) + ircFork( &CIrcProto::AckMessageFailDcc, hContact ); + else + ircFork( &CIrcProto::AckMessageFail, hContact ); + } + + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendUrl + +int __cdecl CIrcProto::SendUrl( HANDLE, int, const char* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetApparentMode - sets the visibility status + +int __cdecl CIrcProto::SetApparentMode( HANDLE, int ) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetStatus - sets the protocol status + +int __cdecl CIrcProto::SetStatus( int iNewStatus ) +{ + return SetStatusInternal( iNewStatus, false ); +} + +int CIrcProto::SetStatusInternal( int iNewStatus, bool bIsInternal ) +{ + if ( !bChatInstalled ) + return 0; + + if ( iNewStatus != ID_STATUS_OFFLINE && !m_network[0] ) { + if (m_nick[0] && !m_disableDefaultServer) { + CQuickDlg* dlg = new CQuickDlg( this ); + dlg->GetProto()->m_quickComboSelection = dlg->GetProto()->m_serverComboSelection + 1; + dlg->Show(); + HWND hwnd = dlg->GetHwnd(); + SetWindowTextA(hwnd, "Miranda IRC"); + SetWindowText(GetDlgItem(hwnd, IDC_TEXT), TranslateT("Please choose an IRC-network to go online. This network will be the default.")); + SetWindowText(GetDlgItem(hwnd, IDC_CAPTION), TranslateT("Default network")); + WindowSetIcon(hwnd, IDI_MAIN); + ShowWindow(hwnd, SW_SHOW); + SetActiveWindow(hwnd); + } + return 0; + } + + if ( iNewStatus != ID_STATUS_OFFLINE && !m_nick[0] || !m_userID[0] || !m_name[0]) { + MIRANDASYSTRAYNOTIFY msn; + msn.cbSize = sizeof( MIRANDASYSTRAYNOTIFY ); + msn.szProto = m_szModuleName; + msn.tszInfoTitle = TranslateT( "IRC error" ); + msn.tszInfo = TranslateT( "Connection can not be established! You have not completed all necessary fields (Nickname, User ID and m_name)." ); + msn.dwInfoFlags = NIIF_ERROR | NIIF_INTERN_UNICODE; + msn.uTimeout = 15000; + CallService( MS_CLIST_SYSTRAY_NOTIFY, (WPARAM)NULL,(LPARAM) &msn); + return 0; + } + + if ( !bIsInternal ) + m_iDesiredStatus = iNewStatus; + + if (( iNewStatus == ID_STATUS_ONLINE || iNewStatus == ID_STATUS_AWAY || iNewStatus == ID_STATUS_FREECHAT) && !IsConnected()) //go from offline to online + { + if (!m_bConnectThreadRunning) + ConnectToServer(); + } + else if (( iNewStatus == ID_STATUS_ONLINE || iNewStatus == ID_STATUS_FREECHAT) && IsConnected() && m_iStatus == ID_STATUS_AWAY) //go to online while connected + { + m_statusMessage = _T(""); + PostIrcMessage( _T("/AWAY")); + return 0; + } + else if ( iNewStatus == ID_STATUS_OFFLINE && IsConnected()) //go from online/away to offline + DisconnectFromServer(); + else if ( iNewStatus == ID_STATUS_OFFLINE && !IsConnected()) //offline to offline + { + KillChatTimer( RetryTimer); + return 0; + } + else if ( iNewStatus == ID_STATUS_AWAY && IsConnected()) //go to away while connected + { + PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); + return 0; + } + else if ( iNewStatus == ID_STATUS_ONLINE && IsConnected()) //already online + return 0; + else + SetStatusInternal(ID_STATUS_AWAY, true); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetAwayMsg - returns a contact's away message + +HANDLE __cdecl CIrcProto::GetAwayMsg( HANDLE hContact ) +{ + WhoisAwayReply = _T(""); + DBVARIANT dbv; + + // bypass chat contacts. + if ( getByte( hContact, "ChatRoom", 0 ) == 0) { + if ( hContact && !getTString( hContact, "Nick", &dbv)) { + int i = getWord( hContact, "Status", ID_STATUS_OFFLINE ); + if ( i != ID_STATUS_AWAY) { + DBFreeVariant( &dbv); + return 0; + } + CMString S = _T("WHOIS "); + S += dbv.ptszVal; + if (IsConnected()) + SendIrcMessage( S.c_str(), false); + DBFreeVariant( &dbv); + } } + + return (HANDLE)1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AWAYMSG + +int __cdecl CIrcProto::RecvAwayMsg( HANDLE, int, PROTORECVEVENT* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AWAYMSG + +int __cdecl CIrcProto::SendAwayMsg( HANDLE, HANDLE, const char* ) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SetAwayMsg - sets the away status message + +int __cdecl CIrcProto::SetAwayMsg( int status, const TCHAR* msg ) +{ + switch( status ) { + case ID_STATUS_ONLINE: case ID_STATUS_INVISIBLE: case ID_STATUS_FREECHAT: + case ID_STATUS_CONNECTING: case ID_STATUS_OFFLINE: + break; + + default: + CMString newStatus = msg; + ReplaceString( newStatus, _T("\r\n"), _T(" ")); + if ( m_statusMessage.IsEmpty() || msg == NULL || m_statusMessage != newStatus ) { + if ( msg == NULL || *msg == 0 ) + m_statusMessage = _T(STR_AWAYMESSAGE); + else + m_statusMessage = newStatus; + + if ( m_iStatus == ID_STATUS_AWAY ) + PostIrcMessage( _T("/AWAY %s"), m_statusMessage.Mid(0,450).c_str()); + } } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// UserIsTyping - sends a UTN notification + +int __cdecl CIrcProto::UserIsTyping( HANDLE, int ) +{ + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// OnEvent - maintain protocol events + +int __cdecl CIrcProto::OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ) +{ + switch( eventType ) { + case EV_PROTO_ONLOAD: return OnModulesLoaded( 0, 0 ); + case EV_PROTO_ONEXIT: return OnPreShutdown( 0, 0 ); + case EV_PROTO_ONOPTIONS: return OnInitOptionsPages( wParam, lParam ); + + case EV_PROTO_ONMENU: + InitMainMenus(); + break; + + case EV_PROTO_ONRENAME: + if ( hMenuRoot ) { + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + clmi.ptszName = m_tszUserName; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuRoot, ( LPARAM )&clmi ); + } + break; + + case EV_PROTO_ONCONTACTDELETED: + return OnContactDeleted(wParam, lParam); + + case EV_PROTO_DBSETTINGSCHANGED: + return OnDbSettingChanged(wParam, lParam); + } + return 1; +} diff --git a/protocols/IRCG/src/main.cpp b/protocols/IRCG/src/main.cpp new file mode 100644 index 0000000000..ea802d43cd --- /dev/null +++ b/protocols/IRCG/src/main.cpp @@ -0,0 +1,122 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" +#include "version.h" + +HINSTANCE hInst = NULL; + +int hLangpack; + +static int CompareServers( const SERVER_INFO* p1, const SERVER_INFO* p2 ) +{ + return lstrcmpA( p1->m_name, p2->m_name ); +} + +OBJLIST g_servers( 20, CompareServers ); + +static int sttCompareProtocols(const CIrcProto *p1, const CIrcProto *p2) +{ + return strcmp(p1->m_szModuleName, p2->m_szModuleName); +} + +LIST g_Instances(1, sttCompareProtocols); + +void InitTimers( void ); +void UninitTimers( void ); + +// Information about the plugin +PLUGININFOEX pluginInfo = +{ + sizeof( PLUGININFOEX ), + __PLUGIN_NAME, + __VERSION_DWORD, + __DESC, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + {0x92382b4d, 0x5572, 0x48a0, {0xb0, 0xb9, 0x13, 0x36, 0xa6, 0x1, 0xd6, 0x89}} // {92382B4D-5572-48a0-B0B9-1336A601D689} +}; + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD, LPVOID) +{ + hInst = hinstDLL; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static CIrcProto* ircProtoInit( const char* pszProtoName, const TCHAR* tszUserName ) +{ + CIrcProto* ppro = new CIrcProto( pszProtoName, tszUserName ); + g_Instances.insert( ppro ); + return ppro; +} + +static int ircProtoUninit( CIrcProto* ppro ) +{ + g_Instances.remove(( CIrcProto* )ppro); + delete ppro; + return 0; +} + +extern "C" int __declspec(dllexport) Load( ) +{ + + mir_getLP( &pluginInfo ); + + AddIcons(); + InitTimers(); + InitServers(); + InitContactMenus(); + + // register protocol + PROTOCOLDESCRIPTOR pd = { 0 }; + pd.cbSize = sizeof( pd ); + pd.szName = "IRC"; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = ( pfnInitProto )ircProtoInit; + pd.fnUninit = ( pfnUninitProto )ircProtoUninit; + CallService( MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd ); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +extern "C" int __declspec(dllexport) Unload(void) +{ + UninitContactMenus(); + UninitIcons(); + UninitTimers(); + + g_Instances.destroy(); + + return 0; +} diff --git a/protocols/IRCG/src/options.cpp b/protocols/IRCG/src/options.cpp new file mode 100644 index 0000000000..69a991374b --- /dev/null +++ b/protocols/IRCG/src/options.cpp @@ -0,0 +1,1962 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" +#include + +#include "ui_utils.h" + +static WNDPROC OldProc; +static WNDPROC OldListViewProc; + +static HANDLE* hIconLibItems; + +static const CIrcProto* pZero = NULL; + +void CIrcProto::ReadSettings( TDbSetting* sets, int count ) +{ + BYTE* base = ( BYTE* )this; + + DBVARIANT dbv; + for ( int i=0; i < count; i++ ) { + TDbSetting* p = &sets[i]; + BYTE* ptr = base + p->offset; + switch( p->type ) { + case DBVT_BYTE: + *( BYTE* )ptr = getByte( p->name, p->defValue ); + break; + case DBVT_WORD: + *( WORD* )ptr = getWord( p->name, p->defValue ); + break; + case DBVT_DWORD: + *( DWORD* )ptr = getDword( p->name, p->defValue ); + break; + case DBVT_ASCIIZ: + if ( !getString( p->name, &dbv )) { + if ( p->size != -1 ) { + size_t len = min( p->size-1, strlen( dbv.pszVal )); + memcpy( ptr, dbv.pszVal, len ); + ptr[len] = 0; + } + else *( char** )ptr = mir_strdup( dbv.pszVal ); + DBFreeVariant( &dbv ); + } + else { + if ( p->size != -1 ) + *ptr = 0; + else + *( char** )ptr = NULL; + } + break; + case DBVT_TCHAR: + if ( !getTString( p->name, &dbv )) { + if ( p->size != -1 ) { + size_t len = min( p->size-1, _tcslen( dbv.ptszVal )); + memcpy( ptr, dbv.pszVal, len*sizeof(TCHAR)); + *( TCHAR* )&ptr[len*sizeof(TCHAR)] = 0; + } + else *( TCHAR** )ptr = mir_tstrdup( dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + else { + if ( p->size != -1 ) { + if ( p->defStr == NULL ) + *ptr = 0; + else + lstrcpyn(( TCHAR* )ptr, p->defStr, (int)p->size ); + } + else *( TCHAR** )ptr = mir_tstrdup( p->defStr ); + } + break; +} } } + +void CIrcProto::WriteSettings( TDbSetting* sets, int count ) +{ + BYTE* base = ( BYTE* )this; + + for ( int i=0; i < count; i++ ) { + TDbSetting* p = &sets[i]; + BYTE* ptr = base + p->offset; + switch( p->type ) { + case DBVT_BYTE: setByte( p->name, *( BYTE* )ptr ); break; + case DBVT_WORD: setWord( p->name, *( WORD* )ptr ); break; + case DBVT_DWORD: setDword( p->name, *( DWORD* )ptr ); break; + + case DBVT_ASCIIZ: + if ( p->size == -1 ) + setString( p->name, *(char**)ptr ); + else + setString( p->name, (char*)ptr ); + break; + + case DBVT_TCHAR: + if ( p->size == -1 ) + setTString( p->name, *(TCHAR**)ptr ); + else + setTString( p->name, (TCHAR*)ptr ); + break; +} } } + +///////////////////////////////////////////////////////////////////////////////////////// + +static int sttServerEnum( const char* szSetting, LPARAM ) +{ + DBVARIANT dbv; + if ( DBGetContactSettingString( NULL, SERVERSMODULE, szSetting, &dbv )) + return 0; + + SERVER_INFO* pData = new SERVER_INFO; + pData->m_name = mir_strdup( szSetting ); + + char* p1 = strchr( dbv.pszVal, ':' )+1; + pData->m_iSSL = 0; + if ( !_strnicmp( p1, "SSL", 3 )) { + p1 +=3; + if ( *p1 == '1' ) + pData->m_iSSL = 1; + else if ( *p1 == '2' ) + pData->m_iSSL = 2; + p1++; + } + char* p2 = strchr(p1, ':'); + pData->m_address = ( char* )mir_alloc( p2-p1+1 ); + lstrcpynA( pData->m_address, p1, p2-p1+1 ); + + p1 = p2+1; + while (*p2 !='G' && *p2 != '-') + p2++; + + char* buf = ( char* )alloca( p2-p1+1 ); + lstrcpynA( buf, p1, p2-p1+1 ); + pData->m_portStart = atoi( buf ); + + if ( *p2 == 'G' ) + pData->m_portEnd = pData->m_portStart; + else { + p1 = p2+1; + p2 = strchr(p1, 'G'); + buf = ( char* )alloca( p2-p1+1 ); + lstrcpynA( buf, p1, p2-p1+1 ); + pData->m_portEnd = atoi( buf ); + } + + p1 = strchr(p2, ':')+1; + p2 = strchr(p1, '\0'); + pData->m_group = ( char* )mir_alloc( p2-p1+1 ); + lstrcpynA( pData->m_group, p1, p2-p1+1 ); + + g_servers.insert( pData ); + DBFreeVariant( &dbv ); + return 0; +} + +void RereadServers() +{ + g_servers.destroy(); + + DBCONTACTENUMSETTINGS dbces; + dbces.pfnEnumProc = sttServerEnum; + dbces.szModule = SERVERSMODULE; + CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void removeSpaces( TCHAR* p ) +{ + while ( *p ) { + if ( *p == ' ' ) + memmove( p, p+1, sizeof(TCHAR)*lstrlen(p)); + p++; +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// add icons to the skinning module + +struct +{ + char* szDescr; + char* szName; + int iSize; + int defIconID; +} +static iconList[] = +{ + { LPGEN("Main"), "main", 0, IDI_MAIN }, + { LPGEN("Add"), "add", 0, IDI_ADD }, + { LPGEN("Apply"), "apply", 0, IDI_APPLY }, + { LPGEN("Rename"), "rename", 0, IDI_RENAME }, + { LPGEN("Edit"), "edit", 0, IDI_EDIT }, + { LPGEN("Cancel"), "delete", 0, IDI_DELETE }, + { LPGEN("Ignore"), "block", 0, IDI_BLOCK }, + { LPGEN("Channel list"), "list", 0, IDI_LIST }, + { LPGEN("Channel manager"), "manager", 0, IDI_MANAGER }, + { LPGEN("Quick connect"), "quick", 0, IDI_QUICK }, + { LPGEN("Server window"), "server", 0, IDI_SERVER }, + { LPGEN("Show channel"), "show", 0, IDI_SHOW }, + { LPGEN("Question"), "question", 0, IDI_IRCQUESTION}, + { LPGEN("WhoIs"), "whois", 0, IDI_WHOIS }, + { LPGEN("Incoming DCC Chat"), "dcc", 0, IDI_DCC }, + { LPGEN("Logo (48x48)"), "logo", 48, IDI_LOGO } +}; + +void AddIcons(void) +{ + TCHAR szFile[MAX_PATH]; + GetModuleFileName(hInst, szFile, MAX_PATH); + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.pszSection = "Protocols/IRC"; + sid.ptszDefaultFile = szFile; + sid.flags = SIDF_PATH_TCHAR; + hIconLibItems = new HANDLE[ SIZEOF(iconList) ]; + + // add them one by one + for ( int i=0; i < SIZEOF(iconList); i++ ) { + char szTemp[255]; + mir_snprintf(szTemp, sizeof(szTemp), "IRC_%s", iconList[i].szName ); + sid.pszName = szTemp; + sid.pszDescription = iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + sid.cx = sid.cy = iconList[i].iSize; + hIconLibItems[i] = Skin_AddIcon(&sid ); + } +} + +void UninitIcons(void) +{ + delete[] hIconLibItems; +} + +HICON LoadIconEx( int iconId, bool big ) +{ + for ( int i=0; i < SIZEOF(iconList); i++ ) + if ( iconList[i].defIconID == iconId ) + return ( HICON )CallService( MS_SKIN2_GETICONBYHANDLE, big, (LPARAM)hIconLibItems[i] ); + + return NULL; +} + +HANDLE GetIconHandle( int iconId ) +{ + for ( int i=0; i < SIZEOF(iconList); i++ ) + if ( iconList[i].defIconID == iconId ) + return hIconLibItems[i]; + + return NULL; +} + +void ReleaseIconEx( HICON hIcon ) +{ + if ( hIcon ) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); +} + +void WindowSetIcon( HWND hWnd, int iconId ) +{ + SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadIconEx( iconId, true )); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadIconEx( iconId )); +} + +void WindowFreeIcon( HWND hWnd ) +{ + ReleaseIconEx(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0)); + ReleaseIconEx(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0)); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// code page handler + +struct { UINT cpId; TCHAR *cpName; } static cpTable[] = +{ + { 874, LPGENT("Thai") }, + { 932, LPGENT("Japanese") }, + { 936, LPGENT("Simplified Chinese") }, + { 949, LPGENT("Korean") }, + { 950, LPGENT("Traditional Chinese") }, + { 1250, LPGENT("Central European") }, + { 1251, LPGENT("Cyrillic (Windows)") }, + { 20866, LPGENT("Cyrillic (KOI8R)") }, + { 1252, LPGENT("Latin I") }, + { 1253, LPGENT("Greek") }, + { 1254, LPGENT("Turkish") }, + { 1255, LPGENT("Hebrew") }, + { 1256, LPGENT("Arabic") }, + { 1257, LPGENT("Baltic") }, + { 1258, LPGENT("Vietnamese") }, + { 1361, LPGENT("Korean (Johab)") } +}; + +static CCtrlCombo* sttCombo; + +typedef BOOL ( WINAPI *pfnGetCPInfoEx )( UINT, DWORD, LPCPINFOEX ); +static pfnGetCPInfoEx fnGetCPInfoEx = NULL; + +static BOOL CALLBACK sttLangAddCallback( CHAR* str ) +{ + UINT cp = atoi(str); + if ( fnGetCPInfoEx == NULL ) { + int i; + for ( i=0; i < SIZEOF(cpTable) && cpTable[i].cpId != cp; i++ ); + if ( i < SIZEOF(cpTable)) + sttCombo->AddString( TranslateTS( cpTable[i].cpName ), cp ); + } + else { + CPINFOEX cpinfo; + if ( fnGetCPInfoEx( cp, 0, &cpinfo )) { + TCHAR* b = _tcschr( cpinfo.CodePageName, '(' ); + if ( b ) { + TCHAR* e = _tcsrchr( cpinfo.CodePageName, ')' ); + if ( e ) { + *e = 0; + sttCombo->AddString( b+1, cp ); + } + else sttCombo->AddString( cpinfo.CodePageName, cp ); + } + else sttCombo->AddString( cpinfo.CodePageName, cp ); + } } + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Add server' dialog + +static int sttRequiredFields[] = { IDC_ADD_SERVER, IDC_ADD_ADDRESS, IDC_ADD_PORT, IDC_ADD_PORT2, IDC_ADD_COMBO }; + +struct CServerDlg : public CProtoDlgBase +{ + CConnectPrefsDlg* m_owner; + int m_action; + + CCtrlButton m_OK; + CCtrlEdit m_server, m_address, m_port, m_port2; + CCtrlCombo m_groupCombo; + + CServerDlg( CIrcProto* _pro, CConnectPrefsDlg* _owner, int _action ) : + CProtoDlgBase( _pro, IDD_ADDSERVER, _owner->GetHwnd()), + m_owner( _owner ), + m_action( _action ), + m_OK( this, IDOK ), + m_groupCombo( this, IDC_ADD_COMBO ), + m_address( this, IDC_ADD_ADDRESS ), + m_server( this, IDC_ADD_SERVER ), + m_port( this, IDC_ADD_PORT ), + m_port2( this, IDC_ADD_PORT2 ) + { + m_OK.OnClick = Callback( this, &CServerDlg::OnOk ); + m_autoClose = CLOSE_ON_CANCEL; + } + + virtual void OnInitDialog() + { + int i = m_owner->m_serverCombo.GetCount(); + for ( int index = 0; index < i; index++ ) { + SERVER_INFO* pData = ( SERVER_INFO* )m_owner->m_serverCombo.GetItemData( index ); + if ( m_groupCombo.FindStringA( pData->m_group, -1, true ) == CB_ERR ) + m_groupCombo.AddStringA( pData->m_group ); + } + + if ( m_action == 2 ) { + int j = m_owner->m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_owner->m_serverCombo.GetItemData( j ); + m_address.SetTextA( pData->m_address ); + m_groupCombo.SetTextA( pData->m_group ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + + char* p = strstr( pData->m_name, ": "); + if ( p ) + m_server.SetTextA( p+2 ); + + if ( pData->m_iSSL == 0 ) + CheckDlgButton( m_hwnd, IDC_OFF, BST_CHECKED ); + if ( pData->m_iSSL == 1 ) + CheckDlgButton( m_hwnd, IDC_AUTO, BST_CHECKED ); + if ( pData->m_iSSL == 2 ) + CheckDlgButton( m_hwnd, IDC_ON, BST_CHECKED ); + } + else { + CheckDlgButton( m_hwnd, IDC_OFF, BST_CHECKED); + m_port.SetInt( 6667 ); + m_port2.SetInt( 6667 ); + } + + int bEnableSsl = TRUE; + EnableWindow(GetDlgItem( m_hwnd, IDC_ON), bEnableSsl ); + EnableWindow(GetDlgItem( m_hwnd, IDC_OFF), bEnableSsl ); + EnableWindow(GetDlgItem( m_hwnd, IDC_AUTO), bEnableSsl ); + + SetFocus( m_groupCombo.GetHwnd()); + } + + virtual void OnClose() + { + m_owner->m_serverCombo.Enable(); + m_owner->m_add.Enable(); + m_owner->m_edit.Enable(); + m_owner->m_del.Enable(); + } + + void OnOk( CCtrlButton* ) + { + for ( int k = 0; k < SIZEOF(sttRequiredFields); k++ ) + if ( !GetWindowTextLength( GetDlgItem( m_hwnd, sttRequiredFields[k] ))) { + MessageBox( m_hwnd, TranslateT("Please complete all fields"), TranslateT("IRC error"), MB_OK | MB_ICONERROR ); + return; + } + + if ( m_action == 2 ) { + int i = m_owner->m_serverCombo.GetCurSel(); + m_owner->m_serverCombo.DeleteString( i ); + } + + SERVER_INFO* pData = new SERVER_INFO; + pData->m_iSSL = 0; + if(IsDlgButtonChecked( m_hwnd, IDC_ON)) + pData->m_iSSL = 2; + if(IsDlgButtonChecked( m_hwnd, IDC_AUTO)) + pData->m_iSSL = 1; + + pData->m_portStart = m_port.GetInt(); + pData->m_portEnd = m_port2.GetInt(); + pData->m_address = rtrim(m_address.GetTextA()); + pData->m_group = m_groupCombo.GetTextA(); + pData->m_name = m_server.GetTextA(); + + char temp[255]; + mir_snprintf( temp, sizeof(temp), "%s: %s", pData->m_group, pData->m_name ); + mir_free( pData->m_name ); + pData->m_name = mir_strdup( temp ); + + int iItem = m_owner->m_serverCombo.AddStringA( pData->m_name, ( LPARAM )pData ); + m_owner->m_serverCombo.SetCurSel( iItem ); + m_owner->OnServerCombo( NULL ); + + m_owner->m_serverlistModified = true; + Close(); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Connect preferences' dialog + +static TDbSetting ConnectSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_userID), "UserID", DBVT_TCHAR, SIZEOF(pZero->m_userID) }, + { FIELD_OFFSET(CIrcProto, m_identSystem), "IdentSystem", DBVT_TCHAR, SIZEOF(pZero->m_identSystem) }, + { FIELD_OFFSET(CIrcProto, m_identPort), "IdentPort", DBVT_TCHAR, SIZEOF(pZero->m_identPort) }, + { FIELD_OFFSET(CIrcProto, m_retryWait), "RetryWait", DBVT_TCHAR, SIZEOF(pZero->m_retryWait) }, + { FIELD_OFFSET(CIrcProto, m_retryCount), "RetryCount", DBVT_TCHAR, SIZEOF(pZero->m_retryCount) }, + + { FIELD_OFFSET(CIrcProto, m_serverName ), "ServerName", DBVT_ASCIIZ, SIZEOF(pZero->m_serverName) }, + { FIELD_OFFSET(CIrcProto, m_portStart ), "PortStart", DBVT_ASCIIZ, SIZEOF(pZero->m_portStart) }, + { FIELD_OFFSET(CIrcProto, m_portEnd ), "PortEnd", DBVT_ASCIIZ, SIZEOF(pZero->m_portEnd ) }, + { FIELD_OFFSET(CIrcProto, m_password ), "Password", DBVT_ASCIIZ, SIZEOF(pZero->m_password ) }, + { FIELD_OFFSET(CIrcProto, m_joinOnInvite ), "JoinOnInvite", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_network ), "Network", DBVT_ASCIIZ, SIZEOF(pZero->m_network ) }, + { FIELD_OFFSET(CIrcProto, m_iSSL ), "UseSSL", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_onlineNotificationTime) , "OnlineNotificationTime", DBVT_WORD, 0, 30 }, + { FIELD_OFFSET(CIrcProto, m_onlineNotificationLimit) , "OnlineNotificationLimit", DBVT_WORD, 0, 50 }, + { FIELD_OFFSET(CIrcProto, m_channelAwayNotification), "ChannelAwayNotification", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_nick), "Nick", DBVT_TCHAR, SIZEOF(pZero->m_nick) }, + { FIELD_OFFSET(CIrcProto, m_pNick), "PNick", DBVT_TCHAR, SIZEOF(pZero->m_pNick) }, + { FIELD_OFFSET(CIrcProto, m_alternativeNick), "AlernativeNick", DBVT_TCHAR, SIZEOF(pZero->m_alternativeNick) }, + { FIELD_OFFSET(CIrcProto, m_name), "Name", DBVT_TCHAR, SIZEOF(pZero->m_name) }, + { FIELD_OFFSET(CIrcProto, m_disableDefaultServer), "DisableDefaultServer", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_ident), "Ident", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_identTimer), "IdentTimer", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_forceVisible), "ForceVisible", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_disableErrorPopups), "DisableErrorPopups", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_rejoinChannels), "RejoinChannels", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_rejoinIfKicked), "RejoinIfKicked", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_retry), "Retry", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_showAddresses), "ShowAddresses", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_oldStyleModes), "OldStyleModes", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_useServer), "UseServer", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_hideServerWindow), "HideServerWindow", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_serverComboSelection), "ServerComboSelection", DBVT_DWORD, 0 }, + { FIELD_OFFSET(CIrcProto, m_sendKeepAlive), "SendKeepAlive", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_autoOnlineNotification), "AutoOnlineNotification", DBVT_BYTE }, +}; + +CConnectPrefsDlg::CConnectPrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_CONNECT, NULL ), + m_serverCombo( this, IDC_SERVERCOMBO ), + m_server( this, IDC_SERVER ), + m_port( this, IDC_PORT ), + m_port2( this, IDC_PORT2 ), + m_pass( this, IDC_PASS ), + m_add( this, IDC_ADDSERVER, LoadIconEx(IDI_ADD), LPGEN("Add a new network")), + m_edit( this, IDC_EDITSERVER, LoadIconEx(IDI_EDIT), LPGEN("Edit this network")), + m_del( this, IDC_DELETESERVER, LoadIconEx(IDI_DELETE), LPGEN("Delete this network")), + m_nick( this, IDC_NICK ), + m_nick2( this, IDC_NICK2 ), + m_name( this, IDC_NAME ), + m_userID( this, IDC_USERID ), + m_ident( this, IDC_IDENT ), + m_identSystem( this, IDC_IDENTSYSTEM ), + m_identPort( this, IDC_IDENTPORT ), + m_identTimer( this, IDC_IDENT_TIMED ), + m_retry( this, IDC_RETRY ), + m_retryWait( this, IDC_RETRYWAIT ), + m_retryCount( this, IDC_RETRYCOUNT ), + m_forceVisible( this, IDC_FORCEVISIBLE ), + m_rejoinOnKick( this, IDC_REJOINONKICK ), + m_rejoinChannels( this, IDC_REJOINCHANNELS ), + m_disableError( this, IDC_DISABLEERROR ), + m_address( this, IDC_ADDRESS ), + m_useServer( this, IDC_USESERVER ), + m_showServer( this, IDC_SHOWSERVER ), + m_keepAlive( this, IDC_KEEPALIVE ), + m_autoJoin( this, IDC_AUTOJOIN ), + m_oldStyle( this, IDC_OLDSTYLE ), + m_onlineNotif( this, IDC_ONLINENOTIF ), + m_channelAway( this, IDC_CHANNELAWAY ), + m_enableServer( this, IDC_STARTUP ), + m_onlineTimer( this, IDC_ONLINETIMER ), + m_limit( this, IDC_LIMIT ), + m_spin1( this, IDC_SPIN1 ), + m_spin2( this, IDC_SPIN2 ), + m_ssl( this, IDC_SSL ), + m_serverlistModified( false ) +{ + m_serverCombo.OnChange = Callback( this, &CConnectPrefsDlg::OnServerCombo ); + m_add.OnClick = Callback( this, &CConnectPrefsDlg::OnAddServer ); + m_del.OnClick = Callback( this, &CConnectPrefsDlg::OnDeleteServer ); + m_edit.OnClick = Callback( this, &CConnectPrefsDlg::OnEditServer ); + m_enableServer.OnChange = Callback( this, &CConnectPrefsDlg::OnStartup ); + m_ident.OnChange = Callback( this, &CConnectPrefsDlg::OnIdent ); + m_useServer.OnChange = Callback( this, &CConnectPrefsDlg::OnUseServer ); + m_onlineNotif.OnChange = Callback( this, &CConnectPrefsDlg::OnOnlineNotif ); + m_channelAway.OnChange = Callback( this, &CConnectPrefsDlg::OnChannelAway ); + m_retry.OnChange = Callback( this, &CConnectPrefsDlg::OnRetry ); +} + +void CConnectPrefsDlg::OnInitDialog() +{ + m_proto->m_hwndConnect = m_hwnd; + + // Fill the servers combo box and create SERVER_INFO structures + for ( int i=0; i < g_servers.getCount(); i++ ) { + SERVER_INFO& si = g_servers[i]; + m_serverCombo.AddStringA( si.m_name, LPARAM( &si )); + } + + m_serverCombo.SetCurSel( m_proto->m_serverComboSelection ); + m_server.SetTextA( m_proto->m_serverName ); + m_port.SetTextA( m_proto->m_portStart ); + m_port2.SetTextA( m_proto->m_portEnd ); + + if ( m_proto->m_iSSL == 0 ) + m_ssl.SetText( TranslateT( "Off" )); + if ( m_proto->m_iSSL == 1 ) + m_ssl.SetText( TranslateT( "Auto" )); + if ( m_proto->m_iSSL == 2 ) + m_ssl.SetText( TranslateT( "On" )); + + if ( m_proto->m_serverComboSelection != -1 ) { + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( m_proto->m_serverComboSelection ); + if ((INT_PTR)pData != CB_ERR) { + m_server.SetTextA( pData->m_address ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + } } + + m_spin1.SendMsg( UDM_SETRANGE,0,MAKELONG(999,20)); + m_spin1.SendMsg( UDM_SETPOS,0,MAKELONG(m_proto->m_onlineNotificationTime,0)); + m_spin2.SendMsg( UDM_SETRANGE,0,MAKELONG(200,0)); + m_spin2.SendMsg( UDM_SETPOS,0,MAKELONG(m_proto->m_onlineNotificationLimit,0)); + m_nick.SetText( m_proto->m_nick); + m_nick2.SetText( m_proto->m_alternativeNick ); + m_userID.SetText( m_proto->m_userID); + m_name.SetText( m_proto->m_name); + m_pass.SetTextA( m_proto->m_password); + m_identSystem.SetText( m_proto->m_identSystem ); + m_identPort.SetText( m_proto->m_identPort ); + m_retryWait.SetText( m_proto->m_retryWait); + m_retryCount.SetText( m_proto->m_retryCount); + m_address.SetState( m_proto->m_showAddresses ); + m_oldStyle.SetState( m_proto->m_oldStyleModes ); + m_channelAway.SetState( m_proto->m_channelAwayNotification ); + m_onlineNotif.SetState( m_proto->m_autoOnlineNotification ); + m_onlineTimer.Enable( m_proto->m_autoOnlineNotification); + m_channelAway.Enable( m_proto->m_autoOnlineNotification); + m_spin1.Enable( m_proto->m_autoOnlineNotification ); + m_spin2.Enable( m_proto->m_autoOnlineNotification && m_proto->m_channelAwayNotification ); + m_limit.Enable( m_proto->m_autoOnlineNotification && m_proto->m_channelAwayNotification ); + m_ident.SetState( m_proto->m_ident ); + m_identSystem.Enable( m_proto->m_ident ); + m_identPort.Enable( m_proto->m_ident ); + m_identTimer.Enable( m_proto->m_ident ); + m_identTimer.SetState( m_proto->m_identTimer ); + m_disableError.SetState( m_proto->m_disableErrorPopups ); + m_forceVisible.SetState( m_proto->m_forceVisible ); + m_rejoinChannels.SetState( m_proto->m_rejoinChannels ); + m_rejoinOnKick.SetState( m_proto->m_rejoinIfKicked ); + m_retry.SetState( m_proto->m_retry ); + m_retryWait.Enable( m_proto->m_retry ); + m_retryCount.Enable( m_proto->m_retry ); + m_enableServer.SetState( !m_proto->m_disableDefaultServer ); + m_keepAlive.SetState( m_proto->m_sendKeepAlive ); + m_useServer.SetState( m_proto->m_useServer ); + m_showServer.SetState( !m_proto->m_hideServerWindow ); + m_showServer.Enable( m_proto->m_useServer ); + m_autoJoin.SetState( m_proto->m_joinOnInvite ); + + m_serverCombo.Enable( !m_proto->m_disableDefaultServer ); + m_add.Enable( !m_proto->m_disableDefaultServer ); + m_edit.Enable( !m_proto->m_disableDefaultServer ); + m_del.Enable( !m_proto->m_disableDefaultServer ); + m_server.Enable( !m_proto->m_disableDefaultServer ); + m_port.Enable( !m_proto->m_disableDefaultServer ); + m_port2.Enable( !m_proto->m_disableDefaultServer ); + m_pass.Enable( !m_proto->m_disableDefaultServer ); +} + +void CConnectPrefsDlg::OnServerCombo( CCtrlData* ) +{ + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + m_server.SetTextA( pData->m_address ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + m_pass.SetTextA( "" ); + + if ( pData->m_iSSL == 0 ) + m_ssl.SetText( TranslateT( "Off" )); + if ( pData->m_iSSL == 1 ) + m_ssl.SetText( TranslateT( "Auto" )); + if ( pData->m_iSSL == 2 ) + m_ssl.SetText( TranslateT( "On" )); + + SendMessage(GetParent( m_hwnd), PSM_CHANGED,0,0); +} } + +void CConnectPrefsDlg::OnAddServer( CCtrlButton* ) +{ + m_serverCombo.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); + CServerDlg* dlg = new CServerDlg( m_proto, this, 1 ); + dlg->Show(); +} + +void CConnectPrefsDlg::OnDeleteServer( CCtrlButton* ) +{ + int i = m_serverCombo.GetCurSel(); + if ( i == CB_ERR) + return; + + m_serverCombo.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); + + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + TCHAR temp[200]; + mir_sntprintf( temp, SIZEOF(temp), TranslateT("Do you want to delete\r\n%s"), (TCHAR*)_A2T(pData->m_name)); + if ( MessageBox( m_hwnd, temp, TranslateT("Delete server"), MB_YESNO | MB_ICONQUESTION ) == IDYES ) { + g_servers.remove( pData ); + + m_serverCombo.DeleteString( i ); + if ( i >= m_serverCombo.GetCount()) + i--; + m_serverCombo.SetCurSel( i ); + OnServerCombo( NULL ); + SendMessage(GetParent( m_hwnd), PSM_CHANGED,0,0); + m_serverlistModified = true; + } + + m_serverCombo.Enable(); + m_add.Enable(); + m_edit.Enable(); + m_del.Enable(); +} + +void CConnectPrefsDlg::OnEditServer( CCtrlButton* ) +{ + int i = m_serverCombo.GetCurSel(); + if ( i == CB_ERR ) + return; + + m_serverCombo.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); + CServerDlg* dlg = new CServerDlg( m_proto, this, 2 ); + dlg->Show(); + SetWindowText( dlg->GetHwnd(), TranslateT( "Edit server" )); +} + +void CConnectPrefsDlg::OnStartup( CCtrlData* ) +{ + m_serverCombo.Enable( m_enableServer.GetState()); + m_add.Enable( m_enableServer.GetState()); + m_edit.Enable( m_enableServer.GetState()); + m_del.Enable( m_enableServer.GetState()); + m_server.Enable( m_enableServer.GetState()); + m_port.Enable( m_enableServer.GetState()); + m_port2.Enable( m_enableServer.GetState()); + m_pass.Enable( m_enableServer.GetState()); + m_ssl.Enable( m_enableServer.GetState()); +} + +void CConnectPrefsDlg::OnIdent( CCtrlData* ) +{ + m_identSystem.Enable( m_ident.GetState()); + m_identPort.Enable( m_ident.GetState()); + m_identTimer.Enable( m_ident.GetState()); +} + +void CConnectPrefsDlg::OnUseServer( CCtrlData* ) +{ + EnableWindow(GetDlgItem( m_hwnd, IDC_SHOWSERVER), m_useServer.GetState()); +} + +void CConnectPrefsDlg::OnOnlineNotif( CCtrlData* ) +{ + m_channelAway.Enable( m_onlineNotif.GetState()); + m_onlineTimer.Enable( m_onlineNotif.GetState()); + m_spin1.Enable( m_onlineNotif.GetState()); + m_spin2.Enable( m_onlineNotif.GetState()); + m_limit.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); +} + +void CConnectPrefsDlg::OnChannelAway( CCtrlData* ) +{ + m_spin2.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); + m_limit.Enable( m_onlineNotif.GetState() && m_channelAway.GetState()); +} + +void CConnectPrefsDlg::OnRetry( CCtrlData* ) +{ + m_retryWait.Enable( m_retry.GetState()); + m_retryCount.Enable( m_retry.GetState()); +} + +void CConnectPrefsDlg::OnApply() +{ + //Save the setting in the CONNECT dialog + if(m_enableServer.GetState()) { + m_server.GetTextA( m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); + m_port.GetTextA( m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); + m_port2.GetTextA( m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); + m_pass.GetTextA( m_proto->m_password, SIZEOF(m_proto->m_password)); + CallService( MS_DB_CRYPT_ENCODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); + } + else m_proto->m_serverName[0] = m_proto->m_portStart[0] = m_proto->m_portEnd[0] = m_proto->m_password[0] = 0; + + m_proto->m_onlineNotificationTime = SendDlgItemMessage( m_hwnd,IDC_SPIN1,UDM_GETPOS,0,0); + m_proto->m_onlineNotificationLimit = SendDlgItemMessage( m_hwnd,IDC_SPIN2,UDM_GETPOS,0,0); + m_proto->m_channelAwayNotification = m_channelAway.GetState(); + + m_nick.GetText( m_proto->m_nick, SIZEOF(m_proto->m_nick)); + removeSpaces(m_proto->m_nick); + mir_sntprintf(m_proto->m_pNick, SIZEOF(m_proto->m_pNick), _T("%s"), m_proto->m_nick); + m_nick2.GetText( m_proto->m_alternativeNick, SIZEOF(m_proto->m_alternativeNick)); + removeSpaces(m_proto->m_alternativeNick); + m_userID.GetText( m_proto->m_userID, SIZEOF(m_proto->m_userID)); + removeSpaces(m_proto->m_userID); + m_name.GetText( m_proto->m_name, SIZEOF(m_proto->m_name)); + m_identSystem.GetText( m_proto->m_identSystem, SIZEOF(m_proto->m_identSystem)); + m_identPort.GetText( m_proto->m_identPort, SIZEOF(m_proto->m_identPort)); + m_retryWait.GetText( m_proto->m_retryWait, SIZEOF(m_proto->m_retryWait)); + m_retryCount.GetText( m_proto->m_retryCount, SIZEOF(m_proto->m_retryCount)); + m_proto->m_disableDefaultServer = !m_enableServer.GetState(); + m_proto->m_ident = m_ident.GetState(); + m_proto->m_identTimer = m_identTimer.GetState(); + m_proto->m_forceVisible = m_forceVisible.GetState(); + m_proto->m_disableErrorPopups = m_disableError.GetState(); + m_proto->m_rejoinChannels = m_rejoinChannels.GetState(); + m_proto->m_rejoinIfKicked = m_rejoinOnKick.GetState(); + m_proto->m_retry = m_retry.GetState(); + m_proto->m_showAddresses = m_address.GetState(); + m_proto->m_oldStyleModes = m_oldStyle.GetState(); + m_proto->m_useServer = m_useServer.GetState(); + + CLISTMENUITEM clmi; + memset( &clmi, 0, sizeof( clmi )); + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS; + if ( !m_proto->m_useServer ) + clmi.flags |= CMIF_GRAYED; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )m_proto->hMenuServer, ( LPARAM )&clmi ); + + m_proto->m_joinOnInvite = m_autoJoin.GetState(); + m_proto->m_hideServerWindow = !m_showServer.GetState(); + m_proto->m_serverComboSelection = m_serverCombo.GetCurSel(); + if ( m_proto->m_sendKeepAlive = m_keepAlive.GetState()) + m_proto->SetChatTimer(m_proto->KeepAliveTimer, 60*1000, KeepAliveTimerProc); + else + m_proto->KillChatTimer(m_proto->KeepAliveTimer); + + m_proto->m_autoOnlineNotification = m_onlineNotif.GetState(); + if ( m_proto->m_autoOnlineNotification ) { + if ( !m_proto->bTempDisableCheck ) { + m_proto->SetChatTimer(m_proto->OnlineNotifTimer, 500, OnlineNotifTimerProc ); + if ( m_proto->m_channelAwayNotification ) + m_proto->SetChatTimer( m_proto->OnlineNotifTimer3, 1500, OnlineNotifTimerProc3 ); + } + } + else if ( !m_proto->bTempForceCheck ) { + m_proto->KillChatTimer( m_proto->OnlineNotifTimer ); + m_proto->KillChatTimer( m_proto->OnlineNotifTimer3 ); + } + + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + if ( m_enableServer.GetState()) + lstrcpyA(m_proto->m_network, pData->m_group); + else + lstrcpyA(m_proto->m_network, ""); + m_proto->m_iSSL = pData->m_iSSL; + } + + if ( m_serverlistModified ) { + m_serverlistModified = false; + CallService( MS_DB_MODULE_DELETE, 0, (LPARAM)SERVERSMODULE ); + + int j = m_serverCombo.GetCount(); + if (j != CB_ERR && j != 0) { + for (int index2 = 0; index2 < j; index2++) { + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( index2 ); + if ( pData == NULL || (INT_PTR)pData == CB_ERR ) + continue; + + char TextLine[512]; + if ( pData->m_iSSL > 0 ) + mir_snprintf(TextLine, sizeof(TextLine), "SERVER:SSL%u%s:%d-%dGROUP:%s", pData->m_iSSL, pData->m_address, pData->m_portStart, pData->m_portEnd, pData->m_group); + else + mir_snprintf(TextLine, sizeof(TextLine), "SERVER:%s:%d-%dGROUP:%s", pData->m_address, pData->m_portStart, pData->m_portEnd, pData->m_group); + DBWriteContactSettingString( NULL, SERVERSMODULE, pData->m_name, TextLine ); + + // combobox might contain new items + if ( g_servers.find( pData ) == NULL ) + g_servers.insert( pData ); + } } } + + m_proto->WriteSettings( ConnectSettings, SIZEOF( ConnectSettings )); + + CallService( MS_DB_CRYPT_DECODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'CTCP preferences' dialog + +static TDbSetting CtcpSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_userInfo ), "UserInfo", DBVT_TCHAR, SIZEOF(pZero->m_userInfo) }, + { FIELD_OFFSET(CIrcProto, m_DCCPacketSize ), "DccPacketSize", DBVT_WORD, 0, 4096 }, + { FIELD_OFFSET(CIrcProto, m_DCCPassive ), "DccPassive", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_DCCMode ), "DCCMode", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_manualHost ), "ManualHost", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_IPFromServer ), "IPFromServer", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_disconnectDCCChats ), "DisconnectDCCChats", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_mySpecifiedHost ), "SpecHost", DBVT_ASCIIZ, SIZEOF(pZero->m_mySpecifiedHost) }, + { FIELD_OFFSET(CIrcProto, m_DCCChatAccept ), "CtcpChatAccept", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_sendNotice ), "SendNotice", DBVT_BYTE, 0, 1 } +}; + +CCtcpPrefsDlg::CCtcpPrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_CTCP, NULL ), + m_enableIP( this, IDC_ENABLEIP ), + m_fromServer( this, IDC_FROMSERVER ), + m_combo( this, IDC_COMBO ), + m_slow( this, IDC_SLOW ), + m_fast( this, IDC_FAST ), + m_disc( this, IDC_DISC ), + m_passive( this, IDC_PASSIVE ), + m_sendNotice( this, IDC_SENDNOTICE ), + m_ip( this, IDC_IP ), + m_userInfo( this, IDC_USERINFO), + m_radio1( this, IDC_RADIO1 ), + m_radio2( this, IDC_RADIO2 ), + m_radio3( this, IDC_RADIO3 ) +{ + m_enableIP.OnChange = Callback( this, &CCtcpPrefsDlg::OnClicked ); + m_fromServer.OnChange = Callback( this, &CCtcpPrefsDlg::OnClicked ); +} + +void CCtcpPrefsDlg::OnInitDialog() +{ + m_userInfo.SetText(m_proto->m_userInfo); + + m_slow.SetState( m_proto->m_DCCMode == 0 ); + m_fast.SetState( m_proto->m_DCCMode == 1 ); + m_disc.SetState( m_proto->m_disconnectDCCChats ); + m_passive.SetState( m_proto->m_DCCPassive ); + m_sendNotice.SetState( m_proto->m_sendNotice ); + + m_combo.AddStringA( "256" ); + m_combo.AddStringA( "512" ); + m_combo.AddStringA( "1024" ); + m_combo.AddStringA( "2048" ); + m_combo.AddStringA( "4096" ); + m_combo.AddStringA( "8192" ); + + TCHAR szTemp[10]; + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%u"), m_proto->m_DCCPacketSize ); + int i = m_combo.SelectString( szTemp ); + if ( i == CB_ERR ) + m_combo.SelectString( _T("4096")); + + if ( m_proto->m_DCCChatAccept == 1 ) + m_radio1.SetState( true ); + if ( m_proto->m_DCCChatAccept == 2 ) + m_radio2.SetState( true ); + if ( m_proto->m_DCCChatAccept == 3 ) + m_radio3.SetState( true ); + + m_fromServer.SetState( m_proto->m_IPFromServer ); + m_enableIP.SetState( m_proto->m_manualHost ); + m_ip.Enable( m_proto->m_manualHost ); + m_fromServer.Enable( !m_proto->m_manualHost ); + if (m_proto->m_manualHost) + m_ip.SetTextA( m_proto->m_mySpecifiedHost ); + else { + if ( m_proto->m_IPFromServer ) { + if ( m_proto->m_myHost[0] ) { + CMString s = (CMString)TranslateT("m_myHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); + } + else { + if ( m_proto->m_myLocalHost[0] ) { + CMString s = ( CMString )TranslateT( "m_myLocalHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); +} } } + +void CCtcpPrefsDlg::OnClicked( CCtrlData* ) +{ + m_ip.Enable( m_enableIP.GetState()); + m_fromServer.Enable( !m_enableIP.GetState()); + + if ( m_enableIP.GetState()) + m_ip.SetTextA( m_proto->m_mySpecifiedHost ); + else { + if ( m_fromServer.GetState()) { + if ( m_proto->m_myHost[0] ) { + CMString s = (CMString)TranslateT( "m_myHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); + } + else { + if ( m_proto->m_myLocalHost[0] ) { + CMString s = ( CMString )TranslateT( "m_myLocalHost) + _T(">"); + m_ip.SetText( s.c_str()); + } + else m_ip.SetText( TranslateT( "" )); +} } } + +void CCtcpPrefsDlg::OnApply() +{ + m_userInfo.GetText( m_proto->m_userInfo, SIZEOF( m_proto->m_userInfo )); + + m_proto->m_DCCPacketSize = m_combo.GetInt(); + m_proto->m_DCCPassive = m_passive.GetState(); + m_proto->m_sendNotice = m_sendNotice.GetState(); + m_proto->m_DCCMode = m_fast.GetState(); + m_proto->m_manualHost = m_enableIP.GetState(); + m_proto->m_IPFromServer = m_fromServer.GetState(); + m_proto->m_disconnectDCCChats = m_disc.GetState(); + + if ( m_enableIP.GetState()) { + char szTemp[500]; + m_ip.GetTextA( szTemp, sizeof( szTemp )); + lstrcpynA(m_proto->m_mySpecifiedHost, GetWord(szTemp, 0).c_str(), 499); + if ( lstrlenA( m_proto->m_mySpecifiedHost )) + m_proto->ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( m_proto->m_mySpecifiedHost, IP_MANUAL )); + } + else m_proto->m_mySpecifiedHost[0] = 0; + + if ( m_radio1.GetState()) + m_proto->m_DCCChatAccept = 1; + if ( m_radio2.GetState()) + m_proto->m_DCCChatAccept = 2; + if ( m_radio3.GetState()) + m_proto->m_DCCChatAccept = 3; + + m_proto->WriteSettings( CtcpSettings, SIZEOF( CtcpSettings )); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Advanced preferences' dialog + +static TDbSetting OtherSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_quitMessage ), "QuitMessage", DBVT_TCHAR, SIZEOF(pZero->m_quitMessage) }, + { FIELD_OFFSET(CIrcProto, m_alias ), "Alias", DBVT_TCHAR, -1 }, + { FIELD_OFFSET(CIrcProto, m_codepage ), "Codepage", DBVT_DWORD, 0, CP_ACP }, + { FIELD_OFFSET(CIrcProto, m_utfAutodetect ), "UtfAutodetect", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_perform ), "Perform", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_scriptingEnabled ), "ScriptingEnabled", DBVT_BYTE } +}; + +static char* sttPerformEvents[] = { + "Event: Available", + "Event: Away", + "Event: N/A", + "Event: Occupied", + "Event: DND", + "Event: Free for chat", + "Event: On the phone", + "Event: Out for lunch", + "Event: Disconnect", + "ALL NETWORKS" +}; + +static LRESULT CALLBACK EditSubclassProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + case WM_CHAR : + if (wParam == 21 || wParam == 11 || wParam == 2) { + char w[2]; + w[1] = '\0'; + if (wParam == 11) + w[0] = 3; + if (wParam == 2) + w[0] = 2; + if (wParam == 21) + w[0] = 31; + SendMessage( hwndDlg, EM_REPLACESEL, false, (LPARAM) w); + SendMessage( hwndDlg, EM_SCROLLCARET, 0,0); + return 0; + } + break; + } + + return CallWindowProc(OldProc, hwndDlg, msg, wParam, lParam); +} + +COtherPrefsDlg::COtherPrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_OTHER, NULL ), + m_url( this, IDC_CUSTOM ), + m_performCombo( this, IDC_PERFORMCOMBO ), + m_codepage( this, IDC_CODEPAGE ), + m_pertormEdit( this, IDC_PERFORMEDIT ), + m_perform( this, IDC_PERFORM ), + m_scripting( this, IDC_SCRIPT ), + m_autodetect( this, IDC_UTF_AUTODETECT ), + m_quitMessage( this, IDC_QUITMESSAGE ), + m_alias( this, IDC_ALIASEDIT ), + m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Click to set commands that will be performed for this event")), + m_delete( this, IDC_DELETE, LoadIconEx(IDI_DELETE), LPGEN("Click to delete the commands for this event")), + m_performlistModified( false ) +{ + m_url.OnClick = Callback( this, &COtherPrefsDlg::OnUrl ); + m_performCombo.OnChange = Callback( this, &COtherPrefsDlg::OnPerformCombo ); + m_codepage.OnChange = Callback( this, &COtherPrefsDlg::OnCodePage ); + m_pertormEdit.OnChange = Callback( this, &COtherPrefsDlg::OnPerformEdit ); + m_perform.OnChange = Callback( this, &COtherPrefsDlg::OnPerform ); + m_add.OnClick = Callback( this, &COtherPrefsDlg::OnAdd ); + m_delete.OnClick = Callback( this, &COtherPrefsDlg::OnDelete ); +} + +void COtherPrefsDlg::OnInitDialog() +{ + OldProc = (WNDPROC)SetWindowLongPtr( m_alias.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); + SetWindowLongPtr( m_quitMessage.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); + SetWindowLongPtr( m_pertormEdit.GetHwnd(), GWLP_WNDPROC,(LONG_PTR)EditSubclassProc); + + m_alias.SetText( m_proto->m_alias ); + m_quitMessage.SetText( m_proto->m_quitMessage ); + m_perform.SetState( m_proto->m_perform ); + m_scripting.SetState( m_proto->m_scriptingEnabled ); + m_scripting.Enable( m_bMbotInstalled ); + m_performCombo.Enable( m_proto->m_perform ); + m_pertormEdit.Enable( m_proto->m_perform ); + m_add.Enable( m_proto->m_perform ); + m_delete.Enable( m_proto->m_perform ); + + fnGetCPInfoEx = ( pfnGetCPInfoEx )GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetCPInfoExW" ); + + m_codepage.AddString( TranslateT("Default ANSI codepage"), CP_ACP ); + if ( fnGetCPInfoEx == NULL ) + m_codepage.AddString( TranslateT("UTF-8"), CP_UTF8 ); + + sttCombo = &m_codepage; + EnumSystemCodePagesA(sttLangAddCallback, CP_INSTALLED); + + int i; + for ( i = m_codepage.GetCount(); i >= 0; i-- ) { + if ( m_codepage.GetItemData( i ) == m_proto->getCodepage()) { + m_codepage.SetCurSel( i ); + break; + } } + + + if ( m_proto->m_codepage == CP_UTF8 ) + m_autodetect.Disable(); + + for ( i=0; i < g_servers.getCount(); i++ ) { + SERVER_INFO& si = g_servers[i]; + int idx = m_performCombo.FindStringA( si.m_group, -1, true ); + if ( idx == CB_ERR ) { + idx = m_performCombo.AddStringA( si.m_group ); + addPerformComboValue( idx, si.m_group ); + } } + + for ( i=0; i < SIZEOF(sttPerformEvents); i++ ) { + int idx = m_performCombo.InsertString( _A2T( sttPerformEvents[i] ), i ); + addPerformComboValue( idx, sttPerformEvents[i] ); + } + + m_performCombo.SetCurSel( 0 ); + OnPerformCombo( NULL ); + m_autodetect.SetState( m_proto->m_utfAutodetect ); +} + +void COtherPrefsDlg::OnUrl( CCtrlButton* ) +{ + CallService( MS_UTILS_OPENURL,0,(LPARAM) "http://members.chello.se/matrix/index.html" ); +} + +void COtherPrefsDlg::OnPerformCombo( CCtrlData* ) +{ + int i = m_performCombo.GetCurSel(); + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); + if (pPerf == 0) + m_pertormEdit.SetTextA( "" ); + else + m_pertormEdit.SetText( pPerf->mText.c_str()); + m_add.Disable(); + if ( GetWindowTextLength( m_pertormEdit.GetHwnd()) != 0) + m_delete.Enable(); + else + m_delete.Disable(); +} + +void COtherPrefsDlg::OnCodePage( CCtrlData* ) +{ + int curSel = m_codepage.GetCurSel(); + m_autodetect.Enable( m_codepage.GetItemData(curSel) != CP_UTF8 ); +} + +void COtherPrefsDlg::OnPerformEdit( CCtrlData* ) +{ + m_add.Enable(); + + if ( GetWindowTextLength( m_pertormEdit.GetHwnd()) != 0) + m_delete.Enable(); + else + m_delete.Disable(); +} + +void COtherPrefsDlg::OnPerform( CCtrlData* ) +{ + m_performCombo.Enable( m_perform.GetState()); + m_pertormEdit.Enable( m_perform.GetState()); + m_add.Enable( m_perform.GetState()); + m_delete.Enable( m_perform.GetState()); +} + +void COtherPrefsDlg::OnAdd( CCtrlButton* ) +{ + TCHAR* temp = m_pertormEdit.GetText(); + + if ( my_strstri( temp, _T("/away"))) + MessageBox( NULL, TranslateT("The usage of /AWAY in your perform buffer is restricted\n as IRC sends this command automatically."), TranslateT("IRC Error"), MB_OK); + else { + int i = m_performCombo.GetCurSel(); + if ( i != CB_ERR ) { + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); + if ( pPerf != NULL ) + pPerf->mText = temp; + + m_add.Disable(); + m_performlistModified = true; + } } + mir_free( temp ); +} + +void COtherPrefsDlg::OnDelete( CCtrlButton* ) +{ + int i = m_performCombo.GetCurSel(); + if ( i != CB_ERR ) { + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( i ); + if ( pPerf != NULL ) { + pPerf->mText = _T(""); + m_pertormEdit.SetTextA( "" ); + m_delete.Disable(); + m_add.Disable(); + } + + m_performlistModified = true; +} } + +void COtherPrefsDlg::OnDestroy() +{ + int i = m_performCombo.GetCount(); + if ( i != CB_ERR && i != 0 ) { + for (int index = 0; index < i; index++) { + PERFORM_INFO* pPerf = (PERFORM_INFO*)m_performCombo.GetItemData( index ); + if (( INT_PTR )pPerf != CB_ERR && pPerf != NULL ) + delete pPerf; +} } } + +void COtherPrefsDlg::OnApply() +{ + mir_free( m_proto->m_alias ); + m_proto->m_alias = m_alias.GetText(); + m_quitMessage.GetText( m_proto->m_quitMessage, SIZEOF( m_proto->m_quitMessage )); + + int curSel = m_codepage.GetCurSel(); + m_proto->m_codepage = m_codepage.GetItemData( curSel ); + if ( m_proto->IsConnected()) + m_proto->setCodepage( m_proto->m_codepage ); + + m_proto->m_utfAutodetect = m_autodetect.GetState(); + m_proto->m_perform = m_perform.GetState(); + m_proto->m_scriptingEnabled = m_scripting.GetState(); + if ( m_add.Enabled()) + OnAdd( NULL ); + + if ( m_performlistModified ) { + int count = m_performCombo.GetCount(); + for ( int i = 0; i < count; i++ ) { + PERFORM_INFO* pPerf = ( PERFORM_INFO* )m_performCombo.GetItemData( i ); + if (( INT_PTR )pPerf == CB_ERR ) + continue; + + if ( !pPerf->mText.IsEmpty()) + m_proto->setTString( pPerf->mSetting.c_str(), pPerf->mText.c_str()); + else + DBDeleteContactSetting( NULL, m_proto->m_szModuleName, pPerf->mSetting.c_str()); + } } + m_proto->WriteSettings( OtherSettings, SIZEOF( OtherSettings )); +} + +void COtherPrefsDlg::addPerformComboValue( int idx, const char* szValueName ) +{ + String sSetting = String("PERFORM:") + szValueName; + sSetting.MakeUpper(); + + PERFORM_INFO* pPref; + DBVARIANT dbv; + if ( !m_proto->getTString( sSetting.c_str(), &dbv )) { + pPref = new PERFORM_INFO( sSetting.c_str(), dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + else pPref = new PERFORM_INFO( sSetting.c_str(), _T("")); + m_performCombo.SetItemData( idx, ( LPARAM )pPref ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'add ignore' preferences dialog + +CAddIgnoreDlg::CAddIgnoreDlg( CIrcProto* _pro, const TCHAR* mask, CIgnorePrefsDlg* _owner ) : + CProtoDlgBase( _pro, IDD_ADDIGNORE, _owner->GetHwnd()), + m_Ok( this, IDOK ), + m_owner( _owner ) +{ + if ( mask == NULL ) + szOldMask[0] = 0; + else + _tcsncpy( szOldMask, mask, SIZEOF(szOldMask)); + + m_Ok.OnClick = Callback( this, &CAddIgnoreDlg::OnOk ); +} + +void CAddIgnoreDlg::OnInitDialog() +{ + if ( szOldMask[0] == 0 ) { + if ( m_proto->IsConnected()) + SetWindowText(GetDlgItem( m_hwnd, IDC_NETWORK), m_proto->m_info.sNetwork.c_str()); + CheckDlgButton( m_hwnd, IDC_Q, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_N, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_I, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_D, BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_C, BST_CHECKED); +} } + +void CAddIgnoreDlg::OnOk( CCtrlButton* ) +{ + TCHAR szMask[500]; + TCHAR szNetwork[500]; + CMString flags; + if ( IsDlgButtonChecked( m_hwnd, IDC_Q ) == BST_CHECKED ) flags += 'q'; + if ( IsDlgButtonChecked( m_hwnd, IDC_N ) == BST_CHECKED ) flags += 'n'; + if ( IsDlgButtonChecked( m_hwnd, IDC_I ) == BST_CHECKED ) flags += 'i'; + if ( IsDlgButtonChecked( m_hwnd, IDC_D ) == BST_CHECKED ) flags += 'd'; + if ( IsDlgButtonChecked( m_hwnd, IDC_C ) == BST_CHECKED ) flags += 'c'; + if ( IsDlgButtonChecked( m_hwnd, IDC_M ) == BST_CHECKED ) flags += 'm'; + + GetWindowText( GetDlgItem( m_hwnd, IDC_MASK), szMask, SIZEOF(szMask)); + GetWindowText( GetDlgItem( m_hwnd, IDC_NETWORK), szNetwork, SIZEOF(szNetwork)); + + CMString Mask = GetWord(szMask, 0); + if ( Mask.GetLength() != 0 ) { + if ( !_tcschr(Mask.c_str(), '!') && !_tcschr(Mask.c_str(), '@')) + Mask += _T("!*@*"); + + if ( !flags.IsEmpty()) { + if ( *szOldMask ) + m_proto->RemoveIgnore( szOldMask ); + m_proto->AddIgnore(Mask.c_str(), flags.c_str(), szNetwork); +} } } + +void CAddIgnoreDlg::OnClose() +{ + m_owner->FixButtons(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Ignore' preferences dialog + +static TDbSetting IgnoreSettings[] = +{ + { FIELD_OFFSET(CIrcProto, m_DCCFileEnabled ), "EnableCtcpFile", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_DCCChatEnabled ), "EnableCtcpChat", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_DCCChatIgnore), "CtcpChatIgnore", DBVT_BYTE, 0, 1 }, + { FIELD_OFFSET(CIrcProto, m_ignore ), "Ignore", DBVT_BYTE }, + { FIELD_OFFSET(CIrcProto, m_ignoreChannelDefault ), "IgnoreChannelDefault", DBVT_BYTE }, +}; + +static int CALLBACK IgnoreListSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + CIgnorePrefsDlg* hwndDlg = ( CIgnorePrefsDlg* )lParamSort; + if ( !hwndDlg->GetHwnd()) + return 1; + + TCHAR temp1[512]; + TCHAR temp2[512]; + + LVITEM lvm; + lvm.mask = LVIF_TEXT; + lvm.iSubItem = 0; + lvm.cchTextMax = SIZEOF(temp1); + + lvm.iItem = lParam1; + lvm.pszText = temp1; + hwndDlg->m_list.GetItem( &lvm ); + + lvm.iItem = lParam2; + lvm.pszText = temp2; + hwndDlg->m_list.GetItem( &lvm ); + + if ( temp1[0] && temp2[0] ) + return lstrcmpi( temp1, temp2 ); + + return ( temp1[0] == 0 ) ? 1 : -1; +} + +static LRESULT CALLBACK ListviewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_KEYUP : + if ( ListView_GetSelectionMark(GetDlgItem(GetParent(hwnd), IDC_LIST)) != -1) { + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_EDIT), true); + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_DELETE), true); + } + else { + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_EDIT), false); + EnableWindow(GetDlgItem(GetParent(hwnd), IDC_DELETE), false); + } + + if (wParam == VK_DELETE) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_DELETE, BN_CLICKED), 0); + + if (wParam == VK_SPACE) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_EDIT, BN_CLICKED), 0); + break; + } + + return CallWindowProc(OldListViewProc, hwnd, msg, wParam, lParam); +} + +// Callback for the 'Add ignore' dialog + +void CIrcProto::InitIgnore( void ) +{ + TCHAR szTemp[ MAX_PATH ]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%miranda_path%%\\Plugins\\") _T(TCHAR_STR_PARAM) _T("_ignore.ini"), m_szModuleName); + TCHAR *szLoadFileName = Utils_ReplaceVarsT( szTemp ); + char* pszIgnoreData = IrcLoadFile(szLoadFileName); + if ( pszIgnoreData != NULL ) { + char *p1 = pszIgnoreData; + while ( *p1 != '\0' ) { + while ( *p1 == '\r' || *p1 == '\n' ) + p1++; + if ( *p1 == '\0' ) + break; + + char* p2 = strstr( p1, "\r\n" ); + if ( !p2 ) + p2 = strchr( p1, '\0' ); + + char* pTemp = p2; + while ( pTemp > p1 && (*pTemp == '\r' || *pTemp == '\n' ||*pTemp == '\0' || *pTemp == ' ' )) + pTemp--; + *++pTemp = 0; + + String mask = GetWord(p1, 0); + String flags = GetWord(p1, 1); + String network = GetWord(p1, 2); + if ( !mask.IsEmpty()) + m_ignoreItems.insert( new CIrcIgnoreItem( getCodepage(), mask.c_str(), flags.c_str(), network.c_str())); + + p1 = p2; + } + + RewriteIgnoreSettings(); + delete[] pszIgnoreData; + ::_tremove( szLoadFileName ); + } + mir_free( szLoadFileName ); + + int idx = 0; + char settingName[40]; + for ( ;; ) { + mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", idx++ ); + + DBVARIANT dbv; + if ( getTString( settingName, &dbv )) + break; + + CMString mask = GetWord( dbv.ptszVal, 0 ); + CMString flags = GetWord( dbv.ptszVal, 1 ); + CMString network = GetWord( dbv.ptszVal, 2 ); + m_ignoreItems.insert( new CIrcIgnoreItem( mask.c_str(), flags.c_str(), network.c_str())); + DBFreeVariant( &dbv ); +} } + +void CIrcProto::RewriteIgnoreSettings( void ) +{ + char settingName[ 40 ]; + + int i=0; + for ( ;; ) { + mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", i++ ); + if ( DBDeleteContactSetting( NULL, m_szModuleName, settingName )) + break; + } + + for ( i=0; i < m_ignoreItems.getCount(); i++ ) { + mir_snprintf( settingName, sizeof(settingName), "IGNORE:%d", i ); + + CIrcIgnoreItem& C = m_ignoreItems[i]; + setTString( settingName, ( C.mask + _T(" ") + C.flags + _T(" ") + C.network ).c_str()); +} } + +CIgnorePrefsDlg::CIgnorePrefsDlg( CIrcProto* _pro ) : + CProtoDlgBase( _pro, IDD_PREFS_IGNORE, NULL ), + m_list( this, IDC_LIST ), + m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Add new ignore")), + m_edit( this, IDC_EDIT, LoadIconEx(IDI_EDIT), LPGEN("Edit this ignore")), + m_del( this, IDC_DELETE, LoadIconEx(IDI_DELETE), LPGEN("Delete this ignore")), + m_enable( this, IDC_ENABLEIGNORE ), + m_ignoreChat( this, IDC_IGNORECHAT ), + m_ignoreFile( this, IDC_IGNOREFILE ), + m_ignoreChannel( this, IDC_IGNORECHANNEL ), + m_ignoreUnknown( this, IDC_IGNOREUNKNOWN ) +{ + m_enable.OnChange = Callback( this, &CIgnorePrefsDlg::OnEnableIgnore ); + m_ignoreChat.OnChange = Callback( this, &CIgnorePrefsDlg::OnIgnoreChat ); + m_add.OnClick = Callback( this, &CIgnorePrefsDlg::OnAdd ); + m_list.OnDoubleClick = m_edit.OnClick = Callback( this, &CIgnorePrefsDlg::OnEdit ); + m_del.OnClick = Callback( this, &CIgnorePrefsDlg::OnDelete ); + m_list.OnColumnClick = Callback( this, &CIgnorePrefsDlg::List_OnColumnClick ); +} + +void CIgnorePrefsDlg::OnInitDialog() +{ + m_proto->m_ignoreDlg = this; + OldListViewProc = (WNDPROC)SetWindowLongPtr( m_list.GetHwnd(),GWLP_WNDPROC, (LONG_PTR)ListviewSubclassProc ); + + m_enable.SetState( m_proto->m_ignore ); + m_ignoreFile.SetState( !m_proto->m_DCCFileEnabled ); + m_ignoreChat.SetState( !m_proto->m_DCCChatEnabled ); + m_ignoreChannel.SetState( m_proto->m_ignoreChannelDefault ); + if ( m_proto->m_DCCChatIgnore == 2 ) + m_ignoreUnknown.SetState( BST_CHECKED ); + + m_ignoreUnknown.Enable( m_proto->m_DCCChatEnabled ); + m_list.Enable( m_proto->m_ignore ); + m_ignoreChannel.Enable( m_proto->m_ignore); + m_add.Enable( m_proto->m_ignore ); + + static int COLUMNS_SIZES[3] = {195, 60, 80}; + LV_COLUMN lvC; + lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvC.fmt = LVCFMT_LEFT; + for ( int index=0; index < 3; index++ ) { + lvC.iSubItem = index; + lvC.cx = COLUMNS_SIZES[index]; + + TCHAR* text = NULL; + switch (index) { + case 0: text = TranslateT("Ignore mask"); break; + case 1: text = TranslateT("Flags"); break; + case 2: text = TranslateT("Network"); break; + } + lvC.pszText = text; + ListView_InsertColumn(GetDlgItem( m_hwnd, IDC_INFO_LISTVIEW),index,&lvC); + } + + ListView_SetExtendedListViewStyle(GetDlgItem( m_hwnd, IDC_INFO_LISTVIEW), LVS_EX_FULLROWSELECT); + RebuildList(); +} + +INT_PTR CIgnorePrefsDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch( msg ) { + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) { + case IDC_LIST: + switch (((NMHDR*)lParam)->code) { + case NM_CLICK: + case NM_RCLICK: + if ( m_list.GetSelectionMark() != -1 ) + FixButtons(); + break; + } } + break; + } + return CDlgBase::DlgProc(msg, wParam, lParam); +} + +void CIgnorePrefsDlg::OnEnableIgnore( CCtrlData* ) +{ + m_ignoreChannel.Enable( m_enable.GetState()); + m_list.Enable( m_enable.GetState()); + m_add.Enable( m_enable.GetState()); +} + +void CIgnorePrefsDlg::OnIgnoreChat( CCtrlData* ) +{ + m_ignoreUnknown.Enable( m_ignoreChat.GetState() == BST_UNCHECKED ); +} + +void CIgnorePrefsDlg::OnAdd( CCtrlButton* ) +{ + CAddIgnoreDlg* dlg = new CAddIgnoreDlg( m_proto, NULL, this ); + dlg->Show(); + SetWindowText( dlg->GetHwnd(), TranslateT( "Add ignore" )); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); +} + +void CIgnorePrefsDlg::OnEdit( CCtrlButton* ) +{ + if ( !m_add.Enabled()) + return; + + TCHAR szMask[512]; + TCHAR szFlags[512]; + TCHAR szNetwork[512]; + int i = m_list.GetSelectionMark(); + m_list.GetItemText( i, 0, szMask, 511 ); + m_list.GetItemText( i, 1, szFlags, 511 ); + m_list.GetItemText( i, 2, szNetwork, 511 ); + CAddIgnoreDlg* dlg = new CAddIgnoreDlg( m_proto, szMask, this ); + dlg->Show(); + HWND hWnd = dlg->GetHwnd(); + SetWindowText(hWnd, TranslateT("Edit ignore")); + if ( szFlags[0] ) { + if ( _tcschr(szFlags, 'q')) + CheckDlgButton(hWnd, IDC_Q, BST_CHECKED); + if ( _tcschr(szFlags, 'n')) + CheckDlgButton(hWnd, IDC_N, BST_CHECKED); + if ( _tcschr(szFlags, 'i')) + CheckDlgButton(hWnd, IDC_I, BST_CHECKED); + if ( _tcschr(szFlags, 'd')) + CheckDlgButton(hWnd, IDC_D, BST_CHECKED); + if ( _tcschr(szFlags, 'c')) + CheckDlgButton(hWnd, IDC_C, BST_CHECKED); + if ( _tcschr(szFlags, 'm')) + CheckDlgButton(hWnd, IDC_M, BST_CHECKED); + } + SetWindowText(GetDlgItem(hWnd, IDC_MASK), szMask); + SetWindowText(GetDlgItem(hWnd, IDC_NETWORK), szNetwork); + m_add.Disable(); + m_edit.Disable(); + m_del.Disable(); +} + +void CIgnorePrefsDlg::OnDelete( CCtrlButton* ) +{ + if ( !m_del.Enabled()) + return; + + TCHAR szMask[512]; + int i = m_list.GetSelectionMark(); + m_list.GetItemText( i, 0, szMask, SIZEOF(szMask)); + m_proto->RemoveIgnore( szMask ); +} + +void CIgnorePrefsDlg::List_OnColumnClick( CCtrlListView::TEventInfo* ) +{ + m_list.SortItems( IgnoreListSort, (LPARAM)this ); + UpdateList(); +} + +void CIgnorePrefsDlg::OnApply() +{ + m_proto->m_DCCFileEnabled = !m_ignoreFile.GetState(); + m_proto->m_DCCChatEnabled = !m_ignoreChat.GetState(); + m_proto->m_ignore = m_enable.GetState(); + m_proto->m_ignoreChannelDefault = m_ignoreChannel.GetState(); + m_proto->m_DCCChatIgnore = m_ignoreUnknown.GetState() ? 2 : 1; + m_proto->WriteSettings( IgnoreSettings, SIZEOF( IgnoreSettings )); +} + +void CIgnorePrefsDlg::OnDestroy() +{ + m_proto->m_ignoreDlg = NULL; + m_proto->m_ignoreItems.destroy(); + + int i = m_list.GetItemCount(); + for ( int j = 0; j < i; j++ ) { + TCHAR szMask[512], szFlags[40], szNetwork[100]; + m_list.GetItemText( j, 0, szMask, SIZEOF(szMask)); + m_list.GetItemText( j, 1, szFlags, SIZEOF(szFlags)); + m_list.GetItemText( j, 2, szNetwork, SIZEOF(szNetwork)); + m_proto->m_ignoreItems.insert( new CIrcIgnoreItem( szMask, szFlags, szNetwork )); + } + + m_proto->RewriteIgnoreSettings(); + SetWindowLongPtr( m_list.GetHwnd(), GWLP_WNDPROC, (LONG_PTR)OldListViewProc ); +} + +void CIgnorePrefsDlg::FixButtons() +{ + m_add.Enable( m_enable.GetState()); + if ( m_list.GetSelectionMark() != -1 ) { + m_edit.Enable(); + m_del.Enable(); + } + else { + m_edit.Disable(); + m_del.Disable(); +} } + +void CIgnorePrefsDlg::RebuildList() +{ + m_list.DeleteAllItems(); + + for ( int i=0; i < m_proto->m_ignoreItems.getCount(); i++ ) { + CIrcIgnoreItem& C = m_proto->m_ignoreItems[i]; + if ( C.mask.IsEmpty() || C.flags[0] != '+' ) + continue; + + LVITEM lvItem; + lvItem.iItem = m_list.GetItemCount(); + lvItem.mask = LVIF_TEXT|LVIF_PARAM ; + lvItem.iSubItem = 0; + lvItem.lParam = lvItem.iItem; + lvItem.pszText = (TCHAR*)C.mask.c_str(); + lvItem.iItem = m_list.InsertItem( &lvItem ); + + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem = 1; + lvItem.pszText = (TCHAR*)C.flags.c_str(); + m_list.SetItem( &lvItem ); + + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem =2; + lvItem.pszText = (TCHAR*)C.network.c_str(); + m_list.SetItem( &lvItem ); + } + + UpdateList(); + m_list.SortItems( IgnoreListSort, ( LPARAM )this ); + UpdateList(); + + FixButtons(); +} + +void CIgnorePrefsDlg::UpdateList() +{ + int j = m_list.GetItemCount(); + if (j > 0 ) { + LVITEM lvm; + lvm.mask= LVIF_PARAM; + lvm.iSubItem = 0; + for ( int i =0; i < j; i++) { + lvm.iItem = i; + lvm.lParam = i; + m_list.SetItem( &lvm ); +} } } + +///////////////////////////////////////////////////////////////////////////////////////// + +int CIrcProto::OnInitOptionsPages(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_CONNECT); + odp.ptszTitle = m_tszUserName; + odp.ptszGroup = LPGENT("Network"); + odp.ptszTab = LPGENT("Account"); + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; + odp.pfnDlgProc = CDlgBase::DynamicDlgProc; + odp.dwInitParam = (LPARAM)&OptCreateAccount; + OptCreateAccount.create = CConnectPrefsDlg::Create; + OptCreateAccount.param = this; + Options_AddPage(wParam, &odp); + + odp.flags |= ODPF_EXPERTONLY; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_CTCP); + odp.ptszTab = LPGENT("DCC'n CTCP"); + odp.dwInitParam = (LPARAM)&OptCreateConn; + OptCreateConn.create = CCtcpPrefsDlg::Create; + OptCreateConn.param = this; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_OTHER); + odp.ptszTab = LPGENT("Advanced"); + odp.dwInitParam = (LPARAM)&OptCreateOther; + OptCreateOther.create = COtherPrefsDlg::Create; + OptCreateOther.param = this; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PREFS_IGNORE); + odp.ptszTab = LPGENT("Ignore"); + odp.dwInitParam = (LPARAM)&OptCreateIgnore; + OptCreateIgnore.create = CIgnorePrefsDlg::Create; + OptCreateIgnore.param = this; + Options_AddPage(wParam, &odp); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIrcProto::InitPrefs(void) +{ + ConnectSettings[0].defStr = _T("Miranda"); + ConnectSettings[1].defStr = _T("UNIX"); + ConnectSettings[2].defStr = _T("113"); + ConnectSettings[3].defStr = _T("30"); + ConnectSettings[4].defStr = _T("10"); + + CtcpSettings[0].defStr = _T(STR_USERINFO); + + OtherSettings[0].defStr = _T(STR_QUITMESSAGE); + + ReadSettings( ConnectSettings, SIZEOF( ConnectSettings )); + ReadSettings( CtcpSettings, SIZEOF( CtcpSettings )); + ReadSettings( OtherSettings, SIZEOF( OtherSettings )); + ReadSettings( IgnoreSettings, SIZEOF( IgnoreSettings )); + + CallService( MS_DB_CRYPT_DECODESTRING, 499, (LPARAM)m_password); + + int x = getDword( "SizeOfListBottom", -1 ); + if ( x != -1 ) { + DBDeleteContactSetting( NULL, m_szModuleName, "SizeOfListBottom" ); + setDword( "channelList_height", x ); + } + if (( x = getDword( "SizeOfListWidth", -1 )) != -1 ) { + DBDeleteContactSetting( NULL, m_szModuleName, "SizeOfListWidth" ); + setDword( "channelList_width", x ); + } + + if ( m_pNick[0] == 0 ) { + if ( m_nick[0] != 0 ) { + memcpy( m_pNick, m_nick, sizeof( m_pNick )); + setTString("PNick", m_nick); + } + } + else { + memcpy( m_nick, m_pNick, sizeof( m_nick )); + setTString("Nick", m_nick); + } + + m_mySpecifiedHostIP[0] = 0; + + if ( m_alias == NULL ) + m_alias = mir_tstrdup( _T("/op /mode ## +ooo $1 $2 $3\r\n/dop /mode ## -ooo $1 $2 $3\r\n/voice /mode ## +vvv $1 $2 $3\r\n/dvoice /mode ## -vvv $1 $2 $3\r\n/j /join #$1 $2-\r\n/p /part ## $1-\r\n/w /whois $1\r\n/k /kick ## $1 $2-\r\n/q /query $1\r\n/logon /log on ##\r\n/logoff /log off ##\r\n/save /log buffer $1\r\n/slap /me slaps $1 around a bit with a large trout" )); + + m_quickComboSelection = getDword( "QuickComboSelection", m_serverComboSelection + 1); + m_myHost[0] = '\0'; + + colors[0] = RGB(255,255,255); + colors[1] = RGB(0,0,0); + colors[2] = RGB(0,0,127); + colors[3] = RGB(0,147,0); + colors[4] = RGB(255,0,0); + colors[5] = RGB(127,0,0); + colors[6] = RGB(156,0,156); + colors[7] = RGB(252,127,0); + colors[8] = RGB(255,255,0); + colors[9] = RGB(0,252,0); + colors[10] = RGB(0,147,147); + colors[11] = RGB(0,255,255); + colors[12] = RGB(0,0,252); + colors[13] = RGB(255,0,255); + colors[14] = RGB(127,127,127); + colors[15] = RGB(210,210,210); +} + +/////////////////////////////////////////////////////////////////////////////// +// Account manager UI + +struct CDlgAccMgrUI : public CProtoDlgBase +{ + CCtrlCombo m_serverCombo; + CCtrlEdit m_server, m_port, m_port2, m_pass, m_nick, m_nick2, m_name, m_userID, m_ssl; + + CDlgAccMgrUI( CIrcProto* _pro, HWND _owner ) : + CProtoDlgBase( _pro, IDD_ACCMGRUI, _owner ), + m_serverCombo( this, IDC_SERVERCOMBO ), + m_server( this, IDC_SERVER ), + m_port( this, IDC_PORT ), + m_port2( this, IDC_PORT2 ), + m_pass( this, IDC_PASS ), + m_nick( this, IDC_NICK ), + m_nick2( this, IDC_NICK2 ), + m_name( this, IDC_NAME ), + m_ssl( this, IDC_SSL ), + m_userID( this, IDC_USERID ) + { + m_serverCombo.OnChange = Callback( this, &CDlgAccMgrUI::OnChangeCombo ); + } + + virtual void OnInitDialog() + { + for ( int i=0; i < g_servers.getCount(); i++ ) { + SERVER_INFO& si = g_servers[i]; + m_serverCombo.AddStringA( si.m_name, LPARAM( &si )); + } + m_serverCombo.SetCurSel( m_proto->m_serverComboSelection ); + m_server.SetTextA( m_proto->m_serverName ); + m_port.SetTextA( m_proto->m_portStart ); + m_port2.SetTextA( m_proto->m_portEnd ); + m_pass.SetTextA( m_proto->m_password); + switch ( m_proto->m_iSSL ) { + case 0: m_ssl.SetTextA( "Off" ); break; + case 1: m_ssl.SetTextA( "Auto" ); break; + case 2: m_ssl.SetTextA( "On" ); break; + } + + m_nick.SetText( m_proto->m_nick); + m_nick2.SetText( m_proto->m_alternativeNick ); + m_userID.SetText( m_proto->m_userID); + m_name.SetText( m_proto->m_name); + } + + virtual void OnApply() + { + m_proto->m_serverComboSelection = m_serverCombo.GetCurSel(); + m_server.GetTextA( m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); + m_port.GetTextA( m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); + m_port2.GetTextA( m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); + m_pass.GetTextA( m_proto->m_password, SIZEOF(m_proto->m_password)); + CallService( MS_DB_CRYPT_ENCODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); + + m_nick.GetText( m_proto->m_nick, SIZEOF(m_proto->m_nick)); + removeSpaces(m_proto->m_nick); + mir_sntprintf(m_proto->m_pNick, 30, _T("%s"), m_proto->m_nick); + m_nick2.GetText( m_proto->m_alternativeNick, SIZEOF(m_proto->m_alternativeNick)); + removeSpaces(m_proto->m_alternativeNick); + m_userID.GetText( m_proto->m_userID, SIZEOF(m_proto->m_userID)); + removeSpaces(m_proto->m_userID); + m_name.GetText( m_proto->m_name, SIZEOF(m_proto->m_name)); + m_proto->WriteSettings( ConnectSettings, SIZEOF( ConnectSettings )); + CallService( MS_DB_CRYPT_DECODESTRING, SIZEOF(m_proto->m_password), (LPARAM)m_proto->m_password); + } + + void OnChangeCombo( CCtrlCombo* ) + { + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + m_server.SetTextA( pData->m_address ); + m_port.SetInt( pData->m_portStart ); + m_port2.SetInt( pData->m_portEnd ); + m_pass.SetTextA( "" ); + switch ( pData->m_iSSL ) { + case 0: m_ssl.SetTextA( "Off" ); break; + case 1: m_ssl.SetTextA( "Auto" ); break; + case 2: m_ssl.SetTextA( "On" ); break; + } } } +}; + +INT_PTR CIrcProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) +{ + CDlgAccMgrUI *dlg = new CDlgAccMgrUI(this, (HWND)lParam); + dlg->Show(); + return (INT_PTR)dlg->GetHwnd(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Initialize servers list + +static void sttImportIni( const TCHAR* szIniFile ) +{ + FILE* serverFile = _tfopen( szIniFile, _T("r")); + if ( serverFile == NULL ) + return; + + char buf1[ 500 ], buf2[ 200 ]; + while ( fgets( buf1, sizeof( buf1 ), serverFile )) { + char* p = strchr( buf1, '=' ); + if ( !p ) + continue; + + p++; + rtrim( p ); + char* p1 = strstr( p, "SERVER:" ); + if ( !p1 ) + continue; + + memcpy( buf2, p, int(p1-p)); + buf2[ int(p1-p) ] = 0; + DBWriteContactSettingString( NULL, SERVERSMODULE, buf2, p1 ); + } + fclose( serverFile ); + ::_tremove( szIniFile ); +} + +void InitServers() +{ + TCHAR *szTemp = Utils_ReplaceVarsT(_T("%miranda_path%\\Plugins\\IRC_servers.ini")); + sttImportIni( szTemp ); + mir_free( szTemp ); + + RereadServers(); + + if ( g_servers.getCount() == 0 ) { + TCHAR *szIniFile = Utils_ReplaceVarsT(_T("%temp%\\default_servers.ini")); + FILE *serverFile = _tfopen( szIniFile, _T("a")); + if (serverFile) { + char* pszSvrs = ( char* )LockResource(LoadResource(hInst,FindResource(hInst,MAKEINTRESOURCE(IDR_SERVERS),_T("TEXT")))); + if (pszSvrs) + fwrite(pszSvrs , 1 , lstrlenA(pszSvrs) + 1 , serverFile ); + fclose(serverFile); + + sttImportIni( szIniFile ); + RereadServers(); + } + mir_free(szIniFile); + } +} diff --git a/protocols/IRCG/src/output.cpp b/protocols/IRCG/src/output.cpp new file mode 100644 index 0000000000..6a97f45baf --- /dev/null +++ b/protocols/IRCG/src/output.cpp @@ -0,0 +1,158 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +static CMString FormatOutput (const CIrcMessage* pmsg) +{ + CMString sMessage; + + if ( pmsg->m_bIncoming ) { // Is it an incoming message? + if ( pmsg->sCommand == _T("WALLOPS") && pmsg->parameters.getCount() > 0 ) { + TCHAR temp[200]; *temp = '\0'; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("WallOps from %s: "), pmsg->prefix.sNick.c_str()); + sMessage = temp; + for ( int i=0; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += pmsg->parameters[i]; + if (i != pmsg->parameters.getCount()-1) + sMessage += _T(" "); + } + goto THE_END; + } + + if ( pmsg->sCommand == _T("INVITE") && pmsg->parameters.getCount() > 1 ) { + TCHAR temp[256]; *temp = '\0'; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s invites you to %s"), pmsg->prefix.sNick.c_str(), pmsg->parameters[1].c_str()); + sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += _T(": ") + pmsg->parameters[i]; + if ( i != pmsg->parameters.getCount()-1 ) + sMessage += _T(" "); + } + goto THE_END; + } + + int index = StrToInt( pmsg->sCommand.c_str()); + if ( index == 301 && pmsg->parameters.getCount() > 0 ) { + TCHAR temp[500]; *temp = '\0'; + mir_sntprintf(temp, SIZEOF(temp), TranslateT("%s is away"), pmsg->parameters[1].c_str()); + sMessage = temp; + for ( int i=2; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += _T(": ") + pmsg->parameters[i]; + if ( i != pmsg->parameters.getCount()-1 ) + sMessage += _T(" "); + } + goto THE_END; + } + + if (( index == 443 || index == 441 ) && pmsg->parameters.getCount() > 3 ) + return pmsg->parameters[1] + _T(" ") + pmsg->parameters[3] + _T(": ") + pmsg->parameters[2]; + + if ( index == 303 ) { // ISON command + sMessage = TranslateT("These are online: "); + for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += pmsg->parameters[i]; + if (i != pmsg->parameters.getCount()-1) + sMessage += _T(", "); + } + goto THE_END; + } + + if (( index > 400 || index < 500) && pmsg->parameters.getCount() > 2 && pmsg->sCommand[0] == '4' ) //all error messages + return pmsg->parameters[2] + _T(": ") + pmsg->parameters[1]; + } + else if ( pmsg->sCommand == _T("NOTICE") && pmsg->parameters.getCount() > 1 ) { + TCHAR temp[500]; *temp = '\0'; + + int l = pmsg->parameters[1].GetLength(); + if ( l > 3 && pmsg->parameters[1][0] == 1 && pmsg->parameters[1][ l-1 ] == 1 ) { + // CTCP reply + CMString tempstr = pmsg->parameters[1]; + tempstr.Delete(0,1); + tempstr.Delete(tempstr.GetLength()-1,1); + CMString type = GetWord(tempstr.c_str(), 0); + if ( lstrcmpi(type.c_str(), _T("ping")) == 0) + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s reply sent to %s"), type.c_str(), pmsg->parameters[0].c_str()); + else + mir_sntprintf(temp, SIZEOF(temp), TranslateT("CTCP %s reply sent to %s: %s"), type.c_str(), pmsg->parameters[0].c_str(), GetWordAddress(tempstr.c_str(), 1)); + sMessage = temp; + } + else { + mir_sntprintf(temp, SIZEOF(temp), TranslateT("Notice to %s: "), pmsg->parameters[0].c_str()); + sMessage = temp; + for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) { + sMessage += pmsg->parameters[i]; + if (i != pmsg->parameters.getCount()-1) + sMessage += _T(" "); + } } + goto THE_END; + } + + // Default Message handler. + + if ( pmsg->m_bIncoming ) { + if ( pmsg->parameters.getCount() < 2 && pmsg->parameters.getCount() > 0 ) + return pmsg->sCommand + _T(" : ") + pmsg->parameters[0]; + + if ( pmsg->parameters.getCount() > 1 ) + for ( int i=1; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += pmsg->parameters[i] + _T(" "); + } + else { + if ( pmsg->prefix.sNick.GetLength()) + sMessage = pmsg->prefix.sNick + _T(" "); + sMessage += pmsg->sCommand + _T(" "); + for ( int i=0; i < (int)pmsg->parameters.getCount(); i++ ) + sMessage += pmsg->parameters[i] + _T(" "); + } + +THE_END: + return sMessage; +} + +BOOL CIrcProto::ShowMessage (const CIrcMessage* pmsg) +{ + CMString mess = FormatOutput(pmsg); + + if ( !pmsg->m_bIncoming ) + ReplaceString( mess, _T("%%"), _T("%")); + + int iTemp = StrToInt( pmsg->sCommand.c_str()); + + //To active window + if (( iTemp > 400 || iTemp < 500 ) && pmsg->sCommand[0] == '4' //all error messages + || pmsg->sCommand == _T("303") //ISON command + || pmsg->sCommand == _T("INVITE") + || ( (pmsg->sCommand == _T("NOTICE")) && ( (pmsg->parameters.getCount() > 2) ? (_tcsstr(pmsg->parameters[1].c_str(), _T("\001"))==NULL) : false)) // CTCP answers should go to m_network Log window! + || pmsg->sCommand == _T("515")) //chanserv error + { + DoEvent(GC_EVENT_INFORMATION, NULL, pmsg->m_bIncoming?pmsg->prefix.sNick.c_str():m_info.sNick.c_str(), mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming?false:true); + return TRUE; + } + + if ( m_useServer ) { + DoEvent( GC_EVENT_INFORMATION, SERVERWINDOW, + ( pmsg->m_bIncoming ) ? pmsg->prefix.sNick.c_str() : m_info.sNick.c_str(), + mess.c_str(), NULL, NULL, NULL, true, pmsg->m_bIncoming ? false : true ); + return true; + } + return false; +} diff --git a/protocols/IRCG/src/resource.h b/protocols/IRCG/src/resource.h new file mode 100644 index 0000000000..948b3a4085 --- /dev/null +++ b/protocols/IRCG/src/resource.h @@ -0,0 +1,253 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by IRC.rc +// +#define ID_INFO_QUERY 3 +#define IDD_PREFS_MAIN 101 +#define IDC_OPTIONSTAB 102 +#define IDD_PREFS_CONNECT 103 +#define IDD_INFO 106 +#define IDD_NICK 107 +#define IDD_PREFS_OTHER 113 +#define IDD_ADDSERVER 120 +#define IDD_LIST 123 +#define IDR_MENU 129 +#define IDD_QUICKCONN 133 +#define IDI_MAIN 136 +#define IDD_USERINFO 154 +#define IDD_CHANMANAGER 155 +#define IDD_QUESTION 156 +#define IDD_PREFS_CTCP 158 +#define IDD_MESSAGEBOX 159 +#define IDD_PREFS_IGNORE 160 +#define IDD_ADDIGNORE 161 +#define IDD_ACCMGRUI 162 +#define IDI_ADD 175 +#define IDI_BLOCK 176 +#define IDI_DELETE 177 +#define IDI_WHOIS 179 +#define IDI_LIST 181 +#define IDI_MANAGER 182 +#define IDI_QUICK 184 +#define IDI_GO 185 +#define IDI_APPLY 185 +#define IDI_SHOW 186 +#define IDI_LOGO 187 +#define IDI_RENAME 188 +#define IDI_SERVER 189 +#define IDI_DCC 196 +#define IDR_SERVERS 200 +#define IDI_EDIT 201 +#define IDI_IRCQUESTION 202 +#define IDC_ENICK 1000 +#define IDC_USERID 1001 +#define IDC_INFO_NAME 1001 +#define IDC_NICK 1002 +#define IDC_LIST 1002 +#define IDC_INFO_AUTH 1002 +#define IDC_INFO_LISTVIEW 1002 +#define IDC_PORT 1003 +#define IDC_INFO_CHANNELS 1003 +#define IDC_INFO_LISTVIEW2 1003 +#define IDC_NAME 1004 +#define IDC_INFO_ADDRESS 1004 +#define IDC_PASS 1005 +#define IDC_INFO_SERVER 1005 +#define IDC_SERVER 1006 +#define IDC_INFO_ID 1006 +#define IDC_PERFORMEDIT 1007 +#define IDC_PORT2 1008 +#define IDC_INFO_AWAY2 1008 +#define IDC_NICK2 1009 +#define IDC_REPLY 1009 +#define IDC_SSL 1010 +#define IDC_PORT3 1010 +#define IDC_INFO_OTHER 1011 +#define IDC_EDIT 1012 +#define IDC_RETRYCOUNT 1013 +#define IDC_INFO_NICK 1013 +#define IDC_EDIT2 1013 +#define ID_INFO_GO 1017 +#define IDC_SERVERCOMBO 1022 +#define IDC_IDENT 1023 +#define IDC_IDENT_TIMED 1024 +#define IDC_RETRY 1029 +#define IDC_ADDSERVER 1031 +#define IDC_EDITSERVER 1032 +#define IDC_RETRYWAIT 1035 +#define IDC_IDENTSYSTEM 1036 +#define IDC_IDENTPORT 1037 +#define IDC_ONLINETIMER 1038 +#define IDC_FORCEVISIBLE 1039 +#define IDC_REJOINCHANNELS 1041 +#define IDC_REJOINONKICK 1042 +#define IDC_PERFORM 1043 +#define IDC_PERFORMCOMBO 1044 +#define IDC_DISABLEERROR 1044 +#define IDC_KEEPALIVE 1045 +#define IDC_ENABLEIP 1045 +#define IDC_ONLINENOTIF 1046 +#define IDC_CHANNELAWAY 1047 +#define IDC_USESERVER 1048 +#define IDC_SHOWSERVER 1049 +#define IDC_ADDRESS 1050 +#define IDC_AUTOJOIN 1051 +#define IDC_OLDSTYLE 1052 +#define IDC_ADD 1090 +#define IDC_DELETE 1091 +#define IDC_ALIASEDIT 1094 +#define IDC_REMOVE 1094 +#define IDC_APPLYTOPIC 1095 +#define IDC_APPLYMODES 1096 +#define IDC_DELETESERVER 1097 +#define IDC_ADD_COMBO 1100 +#define IDC_ADD_SERVER 1101 +#define IDC_ADD_ADDRESS 1102 +#define IDC_ADD_PORT 1103 +#define IDC_ADD_PORT2 1104 +#define IDC_CLOSE 1108 +#define IDC_JOIN 1109 +#define ID_INFO_OK 1110 +#define IDC_STARTUP 1133 +#define IDC_TEXT 1134 +#define IDC_DEFAULT 1139 +#define IDC_WILDCARD 1140 +#define IDC_USER 1141 +#define IDC_HOST 1142 +#define IDC_BUTTON 1143 +#define IDC_BUTTON2 1144 +#define IDC_CHECK1 1147 +#define IDC_CHECK2 1148 +#define IDC_CHECK3 1149 +#define IDC_CHECK4 1150 +#define IDC_CHECK5 1151 +#define IDC_CHECK6 1152 +#define IDC_CHECK7 1153 +#define IDC_CHECK8 1154 +#define IDC_KEY 1159 +#define IDC_LIMIT 1160 +#define IDC_TOPIC 1161 +#define IDC_RADIO1 1170 +#define IDC_RADIO2 1171 +#define IDC_RADIO3 1172 +#define IDC_HIDDENEDIT 1175 +#define IDC_NOTOP 1176 +#define IDC_WHITERECT 1179 +#define IDC_LOGO 1180 +#define IDC_CAPTION 1181 +#define IDC_OFF 1184 +#define IDC_AUTO 1185 +#define IDC_ON 1186 +#define IDC_QUITMESSAGE 1187 +#define IDC_USERINFO 1189 +#define IDC_PING 1190 +#define IDC_IP 1190 +#define IDC_VERSION 1191 +#define IDN_YES 1191 +#define IDC_PASSIVE 1191 +#define IDC_TIME 1192 +#define IDN_NO 1192 +#define IDC_PASSIVE2 1192 +#define IDC_SENDNOTICE 1192 +#define IDC_SLOW 1193 +#define IDC_FAST 1194 +#define IDC_COMBO 1196 +#define IDC_DISC 1197 +#define IDC_FROMSERVER 1201 +#define IDC_SCRIPT 1202 +#define IDC_MASK 1204 +#define IDC_Q 1205 +#define IDC_M 1206 +#define IDC_N 1207 +#define IDC_I 1208 +#define IDC_C 1209 +#define IDC_D 1210 +#define IDC_NETWORK 1211 +#define IDC_IGNORECHANNEL 1212 +#define IDC_ENABLEIGNORE 1213 +#define IDC_IGNOREFILE 1214 +#define IDC_IGNORECHAT 1215 +#define IDC_IGNOREUNKNOWN 1216 +#define IDC_CUSTOM 1218 +#define IDC_SPIN1 1219 +#define IDC_SPIN2 1220 +#define IDC_CODEPAGE 1222 +#define IDC_COMBO1 1223 +#define IDC_CHECK9 1224 +#define IDC_UTF_AUTODETECT 1225 +#define IDC_AWAYTIME 1226 +#define IDC_SSL_ON 1227 +#define IDC_SSL_AUTO 1228 +#define IDC_SSL_OFF 1229 +#define IDC_GRBOX_SSL 1230 +#define IDC_LIST1 1231 +#define IDC_EDIT1 1232 +#define IDC_STATICTEXT1 1233 +#define IDC_STATICTEXT2 1234 +#define IDC_FILTER_STRING 1235 +#define IDC_BUTTON1 1236 +#define IDC_FILTER_BTN 1237 +#define ID_MENU1_OP 40013 +#define ID_MENU1_DEOP 40014 +#define ID_MENU1_VOICE 40015 +#define ID_MENU1_DEVOICE 40016 +#define ID_MENU1_KICK 40017 +#define ID_MENU1_QUERY 40018 +#define ID_MENU1_WHOIS 40019 +#define IDM_COPYALL 40020 +#define IDM_SELECTALL 40022 +#define IDM_CLEAR 40023 +#define IDM_OPENNEW 40024 +#define IDM_OPENEXISTING 40025 +#define IDM_COPYLINK 40026 +#define IDM_COPY 40027 +#define IDM_JOIN 40028 +#define IDM_CHANGENICK 40029 +#define IDM_SHOWSERVER 40030 +#define IDM_LEAVECHAN 40031 +#define ID_MENU1_ADDCONTACT 40032 +#define IDM_CHANMANAGER 40033 +#define ID_MENU1_KICKREASON 40034 +#define ID_MENU1_BAN 40035 +#define ID_MENU1_BANKICK 40036 +#define ID_MENU1_BANKICKREASON 40037 +#define ID_MENU1_IGNORE_ON 40038 +#define ID_MENU1_IGNORE_OFF 40039 +#define ID_MENU1_OWNER 40040 +#define ID_MENU1_DEOWNER 40041 +#define ID_MENU1_ADMIN 40042 +#define ID_MENU1_DEADMIN 40043 +#define ID_MENU1_SENDNOTICE 40044 +#define ID_MENU1_INVITETOCHANNEL 40045 +#define ID_MENU1_SLAP 40046 +#define ID_MENU1_NICKSERV 40047 +#define ID_NICKSERV_REGISTERNICK 40048 +#define ID_NICKSERV_AUTHNICK 40049 +#define ID_NICKSERV_DELETENICK 40050 +#define ID_NICKSERV_IDENTIFY 40051 +#define ID_NICKSERV_SENDPASSWORD 40052 +#define ID_NICKSERV_SETTINGS 40053 +#define ID_SETTINGS_LANGUAGE 40054 +#define ID_SETTINGS_E 40055 +#define ID_SETTINGS_INFO 40056 +#define ID_SETTINGS_KILL 40057 +#define ID_NICKSERV_KILL 40058 +#define ID_KILL_OFF 40059 +#define ID_KILL_ON 40060 +#define ID_KILL_QUICK 40061 +#define ID_NICKSERV_PRIVATE 40062 +#define ID_PRIVATE_ON 40063 +#define ID_PRIVATE_OFF 40064 +#define ID_NICKSERV_SETNEWPASSWORD 40065 +#define ID_NICKSERV_ 40066 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 203 +#define _APS_NEXT_COMMAND_VALUE 40067 +#define _APS_NEXT_CONTROL_VALUE 1238 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/IRCG/src/scripting.cpp b/protocols/IRCG/src/scripting.cpp new file mode 100644 index 0000000000..26c6bc2a55 --- /dev/null +++ b/protocols/IRCG/src/scripting.cpp @@ -0,0 +1,265 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +INT_PTR __cdecl CIrcProto::Scripting_InsertRawIn(WPARAM, LPARAM lParam) +{ + char* pszRaw = ( char* ) lParam; + + if ( m_bMbotInstalled && m_scriptingEnabled && pszRaw && IsConnected()) { + TCHAR* p = mir_a2t( pszRaw ); + InsertIncomingEvent( p ); + mir_free( p ); + return 0; + } + + return 1; +} + +INT_PTR __cdecl CIrcProto::Scripting_InsertRawOut( WPARAM, LPARAM lParam ) +{ + char* pszRaw = ( char* ) lParam; + if ( m_bMbotInstalled && m_scriptingEnabled && pszRaw && IsConnected()) { + String S = pszRaw; + ReplaceString( S, "%", "%%%%"); + NLSendNoScript((const unsigned char *)S.c_str(), lstrlenA(S.c_str())); + return 0; + } + + return 1; +} + +INT_PTR __cdecl CIrcProto::Scripting_InsertGuiIn(WPARAM wParam,LPARAM lParam) +{ + GCEVENT* gce = (GCEVENT *) lParam; + WPARAM_GUI_IN * wgi = (WPARAM_GUI_IN *) wParam; + + + if ( m_bMbotInstalled && m_scriptingEnabled && gce ) { + TCHAR* p1 = NULL; + CMString S; + if ( gce->pDest && gce->pDest->ptszID ) { + p1 = gce->pDest->ptszID; + S = MakeWndID(gce->pDest->ptszID); + gce->pDest->ptszID = ( TCHAR* )S.c_str(); + } + gce->cbSize = sizeof(GCEVENT); + + CallServiceSync( MS_GC_EVENT, wgi?wgi->wParam:0, (LPARAM)gce); + + if ( p1 ) + gce->pDest->ptszID = p1; + return 0; + } + + return 1; +} + +//helper functions +static void __stdcall OnHook(void * pi) +{ + GCHOOK* gch = ( GCHOOK* )pi; + + //Service_GCEventHook(1, (LPARAM) gch); + + if(gch->pszUID) + free(gch->pszUID); + if(gch->pszText) + free(gch->pszText); + if(gch->pDest->ptszID) + free(gch->pDest->ptszID); + if(gch->pDest->pszModule) + free(gch->pDest->pszModule); + delete gch->pDest; + delete gch; +} + +static void __cdecl GuiOutThread(LPVOID di) +{ + GCHOOK* gch = ( GCHOOK* )di; + CallFunctionAsync( OnHook, ( void* )gch ); +} + +INT_PTR __cdecl CIrcProto::Scripting_InsertGuiOut( WPARAM, LPARAM lParam ) +{ + GCHOOK* gch = ( GCHOOK* )lParam; + + if ( m_bMbotInstalled && m_scriptingEnabled && gch ) { + GCHOOK* gchook = new GCHOOK; + gchook->pDest = new GCDEST; + + gchook->dwData = gch->dwData; + gchook->pDest->iType = gch->pDest->iType; + if ( gch->ptszText ) + gchook->ptszText = _tcsdup( gch->ptszText ); + else gchook->pszText = NULL; + + if ( gch->ptszUID ) + gchook->ptszUID = _tcsdup( gch->ptszUID ); + else gchook->pszUID = NULL; + + if ( gch->pDest->ptszID ) { + CMString S = MakeWndID( gch->pDest->ptszID ); + gchook->pDest->ptszID = _tcsdup( S.c_str()); + } + else gchook->pDest->ptszID = NULL; + + if ( gch->pDest->pszModule ) + gchook->pDest->pszModule = _strdup(gch->pDest->pszModule); + else gchook->pDest->pszModule = NULL; + + mir_forkthread( GuiOutThread, gchook ); + return 0; + } + + return 1; +} + +BOOL CIrcProto::Scripting_TriggerMSPRawIn( char** pszRaw ) +{ + int iVal = CallService( MS_MBOT_IRC_RAW_IN, (WPARAM)m_szModuleName, (LPARAM)pszRaw); + if ( iVal == 0 ) + return TRUE; + + return iVal > 0 ? FALSE : TRUE; +} + +BOOL CIrcProto::Scripting_TriggerMSPRawOut(char ** pszRaw) +{ + int iVal = CallService( MS_MBOT_IRC_RAW_OUT, (WPARAM)m_szModuleName, (LPARAM)pszRaw); + if ( iVal == 0 ) + return TRUE; + + return iVal > 0 ? FALSE : TRUE; +} + +BOOL CIrcProto::Scripting_TriggerMSPGuiIn(WPARAM * wparam, GCEVENT * gce) +{ + WPARAM_GUI_IN wgi = {0}; + + wgi.pszModule = m_szModuleName; + wgi.wParam = *wparam; + if (gce->time == 0) + gce->time = time(0); + + int iVal = CallService( MS_MBOT_IRC_GUI_IN, (WPARAM)&wgi, (LPARAM)gce); + if ( iVal == 0 ) { + *wparam = wgi.wParam; + return TRUE; + } + + return iVal > 0 ? FALSE : TRUE; +} + +BOOL CIrcProto::Scripting_TriggerMSPGuiOut(GCHOOK* gch) +{ + int iVal = CallService( MS_MBOT_IRC_GUI_OUT, (WPARAM)m_szModuleName, (LPARAM)gch); + if ( iVal == 0 ) + return TRUE; + + return iVal > 0 ? FALSE : TRUE; +} + +INT_PTR __cdecl CIrcProto::Scripting_GetIrcData(WPARAM, LPARAM lparam) +{ + if ( m_bMbotInstalled && m_scriptingEnabled && lparam ) { + String sString = ( char* ) lparam, sRequest; + CMString sOutput, sChannel; + + int i = sString.Find("|"); + if ( i != -1 ) { + sRequest = sString.Mid(0, i); + TCHAR* p = mir_a2t(( char* )sString.Mid(i+1, sString.GetLength()).c_str()); + sChannel = p; + mir_free( p ); + } + else sRequest = sString; + + sRequest.MakeLower(); + + if (sRequest == "ownnick" && IsConnected()) + sOutput = m_info.sNick; + + else if (sRequest == "network" && IsConnected()) + sOutput = m_info.sNetwork; + + else if (sRequest == "primarynick") + sOutput = m_nick; + + else if (sRequest == "secondarynick") + sOutput = m_alternativeNick; + + else if (sRequest == "myip") + return ( INT_PTR )mir_strdup( m_manualHost ? m_mySpecifiedHostIP : + ( m_IPFromServer ) ? m_myHost : m_myLocalHost); + + else if (sRequest == "usercount" && !sChannel.IsEmpty()) { + CMString S = MakeWndID(sChannel.c_str()); + GC_INFO gci = {0}; + gci.Flags = BYID|COUNT; + gci.pszModule = m_szModuleName; + gci.pszID = (TCHAR*)S.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci )) { + TCHAR szTemp[40]; + _sntprintf( szTemp, 35, _T("%u"), gci.iCount); + sOutput = szTemp; + } + } + else if (sRequest == "userlist" && !sChannel.IsEmpty()) { + CMString S = MakeWndID(sChannel.c_str()); + GC_INFO gci = {0}; + gci.Flags = BYID|USERS; + gci.pszModule = m_szModuleName; + gci.pszID = ( TCHAR* )S.c_str(); + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci )) + return (INT_PTR)mir_strdup( gci.pszUsers ); + } + else if (sRequest == "channellist") { + CMString S = _T(""); + int i = CallServiceSync( MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_szModuleName); + if ( i >= 0 ) { + int j = 0; + while (j < i) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX|ID; + gci.pszModule = m_szModuleName; + gci.iItem = j; + if ( !CallServiceSync( MS_GC_GETINFO, 0, ( LPARAM )&gci )) { + if ( lstrcmpi( gci.pszID, SERVERWINDOW)) { + CMString S1 = gci.pszID; + int k = S1.Find(_T(" ")); + if ( k != -1 ) + S1 = S1.Mid(0, k); + S += S1 + _T(" "); + } } + j++; + } } + + if ( !S.IsEmpty()) + sOutput = ( TCHAR* )S.c_str(); + } + // send it to mbot + if ( !sOutput.IsEmpty()) + return ( INT_PTR )mir_t2a( sOutput.c_str()); + } + return 0; +} diff --git a/protocols/IRCG/src/services.cpp b/protocols/IRCG/src/services.cpp new file mode 100644 index 0000000000..e3b363ac15 --- /dev/null +++ b/protocols/IRCG/src/services.cpp @@ -0,0 +1,1254 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +BOOL bChatInstalled = FALSE, m_bMbotInstalled = FALSE; + +void CIrcProto::InitMainMenus(void) +{ + char temp[ MAXMODULELABELLENGTH ]; + char *d = temp + sprintf( temp, m_szModuleName ); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof( mi ); + mi.pszService = temp; + + if ( bChatInstalled ) { + HGENMENU hRoot = MO_GetProtoRootMenu( m_szModuleName ); + if ( hRoot == NULL ) { + // Root popupmenuitem + mi.ptszName = m_tszUserName; + mi.position = -1999901010; + mi.hParentMenu = HGENMENU_ROOT; + mi.flags = CMIF_ICONFROMICOLIB | CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.icolibItem = GetIconHandle(IDI_MAIN); + hRoot = hMenuRoot = Menu_AddProtoMenuItem(&mi); + } + else { + if (hMenuRoot) + CallService( MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )hMenuRoot, 0 ); + hMenuRoot = NULL; + } + + mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; + mi.pszName = LPGEN("&Quick connect"); + mi.icolibItem = GetIconHandle(IDI_QUICK); + strcpy( d, IRC_QUICKCONNECT ); + mi.position = 201001; + mi.hParentMenu = hRoot; + hMenuQuick = Menu_AddProtoMenuItem(&mi); + + if (m_iStatus != ID_STATUS_OFFLINE) mi.flags |= CMIF_GRAYED; + + mi.pszName = LPGEN("&Join channel"); + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_CHAT_JOIN);//GetIconHandle(IDI_JOIN); + strcpy( d, IRC_JOINCHANNEL ); + mi.position = 201002; + hMenuJoin = Menu_AddProtoMenuItem(&mi); + + mi.pszName = LPGEN("&Change your nickname"); + mi.icolibItem = GetIconHandle(IDI_RENAME); + strcpy( d, IRC_CHANGENICK ); + mi.position = 201003; + hMenuNick = Menu_AddProtoMenuItem(&mi); + + mi.pszName = LPGEN("Show the &list of available channels"); + mi.icolibItem = GetIconHandle(IDI_LIST); + strcpy( d, IRC_SHOWLIST ); + mi.position = 201004; + hMenuList = Menu_AddProtoMenuItem(&mi); + + if (m_useServer) mi.flags &= ~CMIF_GRAYED; + mi.pszName = LPGEN("&Show the server window"); + mi.icolibItem = GetIconHandle(IDI_SERVER); + strcpy( d, IRC_SHOWSERVER ); + mi.position = 201005; + hMenuServer = Menu_AddProtoMenuItem(&mi); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static HGENMENU hUMenuChanSettings, hUMenuWhois, hUMenuDisconnect, hUMenuIgnore; +static HANDLE hPreBuildContactMenu, hMenuChanSettings, hMenuWhois, hMenuDisconnect, hMenuIgnore; + +static CIrcProto* IrcGetInstanceByHContact(HANDLE hContact) +{ + char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL) + return NULL; + + for (int i = 0; i < g_Instances.getCount(); i++) + if (!strcmp(szProto, g_Instances[i]->m_szModuleName)) + return g_Instances[i]; + + return NULL; +} + +static INT_PTR IrcMenuChanSettings(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuChanSettings(wParam, lParam) : 0; +} + +static INT_PTR IrcMenuWhois(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuWhois(wParam, lParam) : 0; +} + +static INT_PTR IrcMenuDisconnect(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuDisconnect(wParam, lParam) : 0; +} + +static INT_PTR IrcMenuIgnore(WPARAM wParam, LPARAM lParam) +{ + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuIgnore(wParam, lParam) : 0; +} + +int IrcPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) +{ + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuWhois, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuDisconnect, ( LPARAM )&clmi ); + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuIgnore, ( LPARAM )&clmi ); + + CIrcProto* ppro = IrcGetInstanceByHContact((HANDLE)wParam); + return (ppro) ? ppro->OnMenuPreBuild(wParam, lParam) : 0; +} + +void InitContactMenus(void) +{ + char temp[MAXMODULELABELLENGTH]; + char *d = temp + sprintf(temp, "IRC"); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.pszService = temp; + mi.flags = CMIF_ICONFROMICOLIB; + + mi.pszName = LPGEN("Channel &settings"); + mi.icolibItem = GetIconHandle(IDI_MANAGER); + strcpy(d, IRC_UM_CHANSETTINGS); + mi.popupPosition = 500090002; + hUMenuChanSettings = Menu_AddContactMenuItem(&mi); + hMenuChanSettings = CreateServiceFunction(temp, IrcMenuChanSettings); + + mi.pszName = LPGEN("&WhoIs info"); + mi.icolibItem = GetIconHandle(IDI_WHOIS); + strcpy(d, IRC_UM_WHOIS); + mi.popupPosition = 500090001; + hUMenuWhois = Menu_AddContactMenuItem(&mi); + hMenuWhois = CreateServiceFunction(temp, IrcMenuWhois); + + mi.pszName = LPGEN("Di&sconnect"); + mi.icolibItem = GetIconHandle(IDI_DELETE); + strcpy(d, IRC_UM_DISCONNECT); + mi.popupPosition = 500090001; + hUMenuDisconnect = Menu_AddContactMenuItem(&mi); + hMenuDisconnect = CreateServiceFunction(temp, IrcMenuDisconnect); + + mi.pszName = LPGEN("&Add to ignore list"); + mi.icolibItem = GetIconHandle(IDI_BLOCK); + strcpy(d, IRC_UM_IGNORE); + mi.popupPosition = 500090002; + hUMenuIgnore = Menu_AddContactMenuItem(&mi); + hMenuIgnore = CreateServiceFunction( temp, IrcMenuIgnore ); + + hPreBuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, IrcPrebuildContactMenu); +} + +void UninitContactMenus(void) +{ + UnhookEvent(hPreBuildContactMenu); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuChanSettings, 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuWhois, 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuDisconnect, 0); + CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hUMenuIgnore, 0); + DestroyServiceFunction(hMenuChanSettings); + DestroyServiceFunction(hMenuWhois); + DestroyServiceFunction(hMenuDisconnect); + DestroyServiceFunction(hMenuIgnore); +} + +INT_PTR __cdecl CIrcProto::OnDoubleclicked(WPARAM, LPARAM lParam) +{ + if (!lParam) + return 0; + + CLISTEVENT* pcle = (CLISTEVENT*)lParam; + + if ( getByte((HANDLE) pcle->hContact, "DCC", 0) != 0) { + DCCINFO* pdci = ( DCCINFO* )pcle->lParam; + CMessageBoxDlg* dlg = new CMessageBoxDlg( this, pdci ); + dlg->Show(); + HWND hWnd = dlg->GetHwnd(); + TCHAR szTemp[500]; + mir_sntprintf( szTemp, SIZEOF(szTemp), TranslateT("%s (%s) is requesting a client-to-client chat connection."), + pdci->sContactName.c_str(), pdci->sHostmask.c_str()); + SetDlgItemText( hWnd, IDC_TEXT, szTemp ); + ShowWindow( hWnd, SW_SHOW ); + return 1; + } + return 0; +} + +int __cdecl CIrcProto::OnContactDeleted(WPARAM wp, LPARAM) +{ + HANDLE hContact = ( HANDLE )wp; + if ( !hContact ) + return 0; + + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + int type = getByte( hContact, "ChatRoom", 0 ); + if ( type != 0 ) { + GCEVENT gce = {0}; + GCDEST gcd = {0}; + CMString S = _T(""); + if (type == GCW_CHATROOM) + S = MakeWndID( dbv.ptszVal ); + if (type == GCW_SERVER) + S = SERVERWINDOW; + gce.cbSize = sizeof(GCEVENT); + gce.dwItemData = 0; + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + gcd.ptszID = ( TCHAR* )S.c_str(); + int i = CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + if (i && type == GCW_CHATROOM) + PostIrcMessage( _T("/PART %s %s"), dbv.ptszVal, m_userInfo); + } + else { + BYTE bDCC = getByte(( HANDLE )wp, "DCC", 0) ; + if ( bDCC ) { + CDccSession* dcc = FindDCCSession((HANDLE)wp); + if ( dcc ) + dcc->Disconnect(); + } } + + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnJoinChat(WPARAM wp, LPARAM) +{ + if (!wp ) + return 0; + + DBVARIANT dbv; + if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { + if ( getByte(( HANDLE )wp, "ChatRoom", 0) == GCW_CHATROOM) + PostIrcMessage( _T("/JOIN %s"), dbv.ptszVal); + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnLeaveChat(WPARAM wp, LPARAM) +{ + if (!wp ) + return 0; + + DBVARIANT dbv; + if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { + if ( getByte(( HANDLE )wp, "ChatRoom", 0) == GCW_CHATROOM) { + PostIrcMessage( _T("/PART %s %s"), dbv.ptszVal, m_userInfo); + + GCEVENT gce = {0}; + GCDEST gcd = {0}; + CMString S = MakeWndID(dbv.ptszVal); + gce.cbSize = sizeof(GCEVENT); + gce.dwFlags = GC_TCHAR; + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.pDest = &gcd; + gcd.ptszID = ( TCHAR* )S.c_str(); + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + } + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuChanSettings(WPARAM wp, LPARAM) +{ + if (!wp ) + return 0; + + HANDLE hContact = (HANDLE) wp; + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + PostIrcMessageWnd(dbv.ptszVal, NULL, _T("/CHANNELMANAGER")); + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuWhois(WPARAM wp, LPARAM) +{ + if ( !wp ) + return 0; + + DBVARIANT dbv; + + if ( !getTString(( HANDLE )wp, "Nick", &dbv)) { + PostIrcMessage( _T("/WHOIS %s %s"), dbv.ptszVal, dbv.ptszVal); + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuDisconnect(WPARAM wp, LPARAM) +{ + CDccSession* dcc = FindDCCSession((HANDLE)wp); + if ( dcc ) + dcc->Disconnect(); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnMenuIgnore(WPARAM wp, LPARAM) +{ + if ( !wp ) + return 0; + + HANDLE hContact = (HANDLE) wp; + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + if ( getByte(( HANDLE )wp, "ChatRoom", 0) == 0 ) { + char* host = NULL; + DBVARIANT dbv1; + if ( !getString((HANDLE) wp, "Host", &dbv1)) + host = dbv1.pszVal; + + if ( host ) { + String S; + if (m_ignoreChannelDefault) + S = "+qnidcm"; + else + S = "+qnidc"; + PostIrcMessage( _T("/IGNORE %%question=\"%s\",\"%s\",\"*!*@") _T(TCHAR_STR_PARAM) _T("\" %s"), + TranslateT("Please enter the hostmask (nick!user@host) \nNOTE! Contacts on your contact list are never ignored"), + TranslateT("Ignore"), host, S.c_str()); + DBFreeVariant(&dbv1); + } + } + DBFreeVariant(&dbv); + } + return 0; +} + +INT_PTR __cdecl CIrcProto::OnJoinMenuCommand(WPARAM, LPARAM) +{ + if ( !m_joinDlg ) { + m_joinDlg = new CJoinDlg( this ); + m_joinDlg->Show(); + } + + SetDlgItemText( m_joinDlg->GetHwnd(), IDC_CAPTION, TranslateT("Join channel")); + SetWindowText( GetDlgItem( m_joinDlg->GetHwnd(), IDC_TEXT), TranslateT("Please enter a channel to join")); + SendMessage( GetDlgItem( m_joinDlg->GetHwnd(), IDC_ENICK), EM_SETSEL, 0,MAKELPARAM(0,-1)); + ShowWindow( m_joinDlg->GetHwnd(), SW_SHOW); + SetActiveWindow( m_joinDlg->GetHwnd()); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnQuickConnectMenuCommand(WPARAM, LPARAM) +{ + if ( !m_quickDlg ) { + m_quickDlg = new CQuickDlg( this ); + m_quickDlg->Show(); + + SetWindowText( m_quickDlg->GetHwnd(), TranslateT( "Quick connect" )); + SetDlgItemText( m_quickDlg->GetHwnd(), IDC_TEXT, TranslateT( "Please select IRC network and enter the password if needed" )); + SetDlgItemText( m_quickDlg->GetHwnd(), IDC_CAPTION, TranslateT( "Quick connect" )); + WindowSetIcon( m_quickDlg->GetHwnd(), IDI_QUICK ); + } + + ShowWindow( m_quickDlg->GetHwnd(), SW_SHOW ); + SetActiveWindow( m_quickDlg->GetHwnd()); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnShowListMenuCommand(WPARAM, LPARAM) +{ + PostIrcMessage( _T("/LIST")); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnShowServerMenuCommand(WPARAM, LPARAM) +{ + GCEVENT gce = {0}; + GCDEST gcd = {0}; + gcd.iType = GC_EVENT_CONTROL; + gcd.ptszID = SERVERWINDOW; + gce.dwFlags = GC_TCHAR; + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + CallChatEvent( WINDOW_VISIBLE, (LPARAM)&gce); + return 0; +} + +INT_PTR __cdecl CIrcProto::OnChangeNickMenuCommand(WPARAM, LPARAM) +{ + if ( !m_nickDlg ) { + m_nickDlg = new CNickDlg( this ); + m_nickDlg->Show(); + } + + SetDlgItemText( m_nickDlg->GetHwnd(), IDC_CAPTION, TranslateT("Change nick name")); + SetWindowText( GetDlgItem( m_nickDlg->GetHwnd(), IDC_TEXT), TranslateT("Please enter a unique nickname")); + m_nickDlg->m_Enick.SetText( m_info.sNick.c_str()); + m_nickDlg->m_Enick.SendMsg( CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); + ShowWindow( m_nickDlg->GetHwnd(), SW_SHOW); + SetActiveWindow( m_nickDlg->GetHwnd()); + return 0; +} + +static void DoChatFormatting( TCHAR* pszText ) +{ + TCHAR* p1 = pszText; + int iFG = -1; + int iRemoveChars; + TCHAR InsertThis[50]; + + while (*p1 != '\0') { + iRemoveChars = 0; + InsertThis[0] = 0; + + if ( *p1 == '%' ) { + switch ( p1[1] ) { + case 'B': + case 'b': + lstrcpy(InsertThis, _T("\002")); + iRemoveChars = 2; + break; + case 'I': + case 'i': + lstrcpy(InsertThis, _T("\026")); + iRemoveChars = 2; + break; + case 'U': + case 'u': + lstrcpy(InsertThis, _T("\037")); + iRemoveChars = 2; + break; + case 'c': + { + lstrcpy(InsertThis, _T("\003")); + iRemoveChars = 2; + + TCHAR szTemp[3]; + lstrcpyn(szTemp, p1 + 2, 3); + iFG = _ttoi(szTemp); + } + break; + case 'C': + if ( p1[2] == '%' && p1[3] == 'F') { + lstrcpy(InsertThis, _T("\00399,99")); + iRemoveChars = 4; + } + else { + lstrcpy(InsertThis, _T("\00399")); + iRemoveChars = 2; + } + iFG = -1; + break; + case 'f': + if (p1 - 3 >= pszText && p1[-3] == '\003') + lstrcpy(InsertThis, _T(",")); + else if ( iFG >= 0 ) + mir_sntprintf(InsertThis, SIZEOF(InsertThis), _T("\003%u,"), iFG); + else + lstrcpy(InsertThis, _T("\00399,")); + + iRemoveChars = 2; + break; + + case 'F': + if (iFG >= 0) + mir_sntprintf(InsertThis, SIZEOF(InsertThis), _T("\003%u,99"), iFG); + else + lstrcpy(InsertThis, _T("\00399,99")); + iRemoveChars = 2; + break; + + case '%': + lstrcpy(InsertThis, _T("%")); + iRemoveChars = 2; + break; + + default: + iRemoveChars = 2; + break; + } + + MoveMemory(p1 + lstrlen(InsertThis), p1 + iRemoveChars, sizeof(TCHAR)*(lstrlen(p1) - iRemoveChars + 1)); + CopyMemory(p1, InsertThis, sizeof(TCHAR)*lstrlen(InsertThis)); + if (iRemoveChars || lstrlen(InsertThis)) + p1 += lstrlen(InsertThis); + else + p1++; + } + else p1++; +} } + +int __cdecl CIrcProto::GCEventHook(WPARAM wParam,LPARAM lParam) +{ + GCHOOK *gchook= (GCHOOK*) lParam; + GCHOOK *gchtemp = NULL; + GCHOOK *gch = NULL; + CMString S = _T(""); + + EnterCriticalSection(&m_gchook); + + // handle the hook + if ( gchook ) { + if (!lstrcmpiA(gchook->pDest->pszModule, m_szModuleName)) { + + // first see if the scripting module should modify or stop this event + if (m_bMbotInstalled && m_scriptingEnabled && wParam == NULL) { + gchtemp = (GCHOOK *)mir_alloc(sizeof(GCHOOK)); + gchtemp->pDest = (GCDEST *)mir_alloc(sizeof(GCDEST)); + gchtemp->pDest->iType = gchook->pDest->iType; + gchtemp->dwData = gchook->dwData; + + if ( gchook->pDest->ptszID ) { + gchtemp->pDest->ptszID = mir_tstrdup( gchook->pDest->ptszID ); + TCHAR* pTemp = _tcschr(gchtemp->pDest->ptszID, ' '); + if ( pTemp ) + *pTemp = '\0'; + } + else gchtemp->pDest->ptszID = NULL; + + //MBOT CORRECTIONS + gchook->pDest->pszModule = mir_strdup( gchook->pDest->pszModule ); + gchook->ptszText = mir_tstrdup( gchook->ptszText ); + gchook->ptszUID = mir_tstrdup( gchook->ptszUID ); + + if ( Scripting_TriggerMSPGuiOut(gchtemp) && gchtemp) + gch = gchtemp; + else + gch = NULL; + } + else gch = gchook; + + if ( gch ) { + TCHAR* p1 = mir_tstrdup( gch->pDest->ptszID ); + TCHAR* p2 = _tcsstr( p1, _T(" - ")); + if ( p2 ) + *p2 = '\0'; + + switch( gch->pDest->iType ) { + case GC_SESSION_TERMINATE: + FreeWindowItemData(p1, (CHANNELINFO*)gch->dwData); + break; + + case GC_USER_MESSAGE: + if (gch && gch->pszText && lstrlen(gch->ptszText) > 0 ) { + TCHAR* pszText = new TCHAR[lstrlen(gch->ptszText)+1000]; + lstrcpy(pszText, gch->ptszText); + DoChatFormatting(pszText); + PostIrcMessageWnd(p1, NULL, pszText); + delete []pszText; + } + break; + + case GC_USER_CHANMGR: + PostIrcMessageWnd(p1, NULL, _T("/CHANNELMANAGER")); + break; + + case GC_USER_PRIVMESS: + { + TCHAR szTemp[4000]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("/QUERY %s"), gch->ptszUID ); + PostIrcMessageWnd(p1, NULL, szTemp); + } + break; + + case GC_USER_LOGMENU: + switch( gch->dwData ) { + case 1: + OnChangeNickMenuCommand(NULL, NULL); + break; + case 2: + PostIrcMessageWnd(p1, NULL, _T("/CHANNELMANAGER")); + break; + + case 3: + PostIrcMessage( _T("/PART %s %s"), p1, m_userInfo ); + { GCEVENT gce = {0}; + GCDEST gcd = {0}; + S = MakeWndID(p1); + gce.cbSize = sizeof(GCEVENT); + gcd.iType = GC_EVENT_CONTROL; + gcd.pszModule = m_szModuleName; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + gcd.ptszID = ( TCHAR* )S.c_str(); + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + } + break; + case 4: // show server window + PostIrcMessageWnd(p1, NULL, _T("/SERVERSHOW")); + break; +/* case 5: // nickserv register nick + PostIrcMessage( _T("/nickserv REGISTER %%question=\"%s\",\"%s\""), + TranslateT("Please enter your authentification code"), TranslateT("Authentificate nick")); + break; +*/ case 6: // nickserv Identify + PostIrcMessage( _T("/nickserv AUTH %%question=\"%s\",\"%s\""), + TranslateT("Please enter your authentification code"), TranslateT("Authentificate nick")); + break; + case 7: // nickserv drop nick + if (MessageBox(0, TranslateT("Are you sure you want to unregister your current nick?"), TranslateT("Delete nick"), + MB_ICONERROR + MB_YESNO + MB_DEFBUTTON2) == IDYES) + PostIrcMessage( _T("/nickserv DROP")); + break; + case 8: // nickserv Identify + { + CQuestionDlg* dlg = new CQuestionDlg( this ); + dlg->Show(); + HWND question_hWnd = dlg->GetHwnd(); + HWND hEditCtrl = GetDlgItem( question_hWnd, IDC_EDIT); + SetDlgItemText( question_hWnd, IDC_CAPTION, TranslateT("Identify nick")); + SetWindowText( GetDlgItem( question_hWnd, IDC_TEXT), TranslateT("Please enter your password")); + SetDlgItemText( question_hWnd, IDC_HIDDENEDIT, _T("/nickserv IDENTIFY %question=\"%s\",\"%s\"")); + SetWindowLongPtr(GetDlgItem( question_hWnd, IDC_EDIT), GWL_STYLE, + (LONG)GetWindowLongPtr(GetDlgItem( question_hWnd, IDC_EDIT), GWL_STYLE) | ES_PASSWORD); + SendMessage(hEditCtrl, EM_SETPASSWORDCHAR,(WPARAM)_T('*'),0 ); + SetFocus(hEditCtrl); + dlg->Activate(); + } + break; + case 9: // nickserv remind password + { + DBVARIANT dbv; + if ( !getTString( "Nick", &dbv )) { + PostIrcMessage( _T("/nickserv SENDPASS %s"), dbv.ptszVal); + DBFreeVariant( &dbv ); + } } + break; + case 10: // nickserv set new password + PostIrcMessage( _T("/nickserv SET PASSWORD %%question=\"%s\",\"%s\""), + TranslateT("Please enter your new password"), TranslateT("Set new password")); + break; + case 11: // nickserv set language + PostIrcMessage( _T("/nickserv SET LANGUAGE %%question=\"%s\",\"%s\""), + TranslateT("Please enter desired languageID (numeric value, depends on server)"), TranslateT("Change language of NickServ messages")); + break; + case 12: // nickserv set homepage + PostIrcMessage( _T("/nickserv SET URL %%question=\"%s\",\"%s\""), + TranslateT("Please enter URL that will be linked to your nick"), TranslateT("Set URL, linked to nick")); + break; + case 13: // nickserv set email + PostIrcMessage( _T("/nickserv SET EMAIL %%question=\"%s\",\"%s\""), + TranslateT("Please enter your e-mail, that will be linked to your nick"), TranslateT("Set e-mail, linked to nick")); + break; + case 14: // nickserv set info + PostIrcMessage( _T("/nickserv SET INFO %%question=\"%s\",\"%s\""), + TranslateT("Please enter some information about your nick"), TranslateT("Set information for nick")); + break; + case 15: // nickserv kill unauth off + PostIrcMessage( _T("/nickserv SET KILL OFF")); + break; + case 16: // nickserv kill unauth on + PostIrcMessage( _T("/nickserv SET KILL ON")); + break; + case 17: // nickserv kill unauth quick + PostIrcMessage( _T("/nickserv SET KILL QUICK")); + break; + case 18: // nickserv hide nick from /LIST + PostIrcMessage( _T("/nickserv SET PRIVATE ON")); + break; + case 19: // nickserv show nick to /LIST + PostIrcMessage( _T("/nickserv SET PRIVATE OFF")); + break; + case 20: // nickserv Hide e-mail from info + PostIrcMessage( _T("/nickserv SET HIDE EMAIL ON")); + break; + case 21: // nickserv Show e-mail in info + PostIrcMessage( _T("/nickserv SET HIDE EMAIL OFF")); + break; + case 22: // nickserv Set security for nick + PostIrcMessage( _T("/nickserv SET SECURE ON")); + break; + case 23: // nickserv Remove security for nick + PostIrcMessage( _T("/nickserv SET SECURE OFF")); + break; + case 24: // nickserv Link nick to current + PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), + TranslateT("Please enter nick you want to link to your current nick"), TranslateT("Link another nick to current nick")); + break; + case 25: // nickserv Unlink nick from current + PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), + TranslateT("Please enter nick you want to unlink from your current nick"), TranslateT("Unlink another nick from current nick")); + break; + case 26: // nickserv Set main nick + PostIrcMessage( _T("/nickserv LINK %%question=\"%s\",\"%s\""), + TranslateT("Please enter nick you want to set as your main nick"), TranslateT("Set main nick")); + break; + case 27: // nickserv list all linked nicks + PostIrcMessage( _T("/nickserv LISTLINKS")); + break; + case 28: // nickserv list all channels owned + PostIrcMessage( _T("/nickserv LISTCHANS")); + break; + } + break; + + case GC_USER_NICKLISTMENU: + switch(gch->dwData) { + case 1: + PostIrcMessage( _T("/MODE %s +o %s"), p1, gch->ptszUID ); + break; + case 2: + PostIrcMessage( _T("/MODE %s -o %s"), p1, gch->ptszUID ); + break; + case 3: + PostIrcMessage( _T("/MODE %s +v %s"), p1, gch->ptszUID ); + break; + case 4: + PostIrcMessage( _T("/MODE %s -v %s"), p1, gch->ptszUID ); + break; + case 5: + PostIrcMessage( _T("/KICK %s %s"), p1, gch->ptszUID ); + break; + case 6: + PostIrcMessage( _T("/KICK %s %s %%question=\"%s\",\"%s\",\"%s\""), + p1, gch->ptszUID, TranslateT("Please enter the reason"), TranslateT("Kick"), TranslateT("Jerk")); + break; + case 7: + DoUserhostWithReason(1, _T("B") + (CMString)p1, true, _T("%s"), gch->ptszUID ); + break; + case 8: + DoUserhostWithReason(1, _T("K") + (CMString)p1, true, _T("%s"), gch->ptszUID ); + break; + case 9: + DoUserhostWithReason(1, _T("L") + (CMString)p1, true, _T("%s"), gch->ptszUID ); + break; + case 10: + PostIrcMessage( _T("/WHOIS %s %s"), gch->ptszUID, gch->ptszUID ); + break; + // case 11: + // DoUserhostWithReason(1, "I", true, "%s", gch->ptszUID ); + // break; + // case 12: + // DoUserhostWithReason(1, "J", true, "%s", gch->ptszUID ); + // break; + case 13: + PostIrcMessage( _T("/DCC CHAT %s"), gch->ptszUID ); + break; + case 14: + PostIrcMessage( _T("/DCC SEND %s"), gch->ptszUID ); + break; + case 15: + DoUserhostWithReason(1, _T("I"), true, _T("%s"), gch->ptszUID ); + break; + case 16: + PostIrcMessage( _T("/MODE %s +h %s"), p1, gch->ptszUID ); + break; + case 17: + PostIrcMessage( _T("/MODE %s -h %s"), p1, gch->ptszUID ); + break; + case 18: + PostIrcMessage( _T("/MODE %s +q %s"), p1, gch->ptszUID ); + break; + case 19: + PostIrcMessage( _T("/MODE %s -q %s"), p1, gch->ptszUID ); + break; + case 20: + PostIrcMessage( _T("/MODE %s +a %s"), p1, gch->ptszUID ); + break; + case 21: + PostIrcMessage( _T("/MODE %s -a %s"), p1, gch->ptszUID ); + break; + case 22: + PostIrcMessage( _T("/NOTICE %s %%question=\"%s\",\"%s\""), + gch->ptszUID, TranslateT("Please enter the notice text"), TranslateT("Send notice")); + break; + case 23: + PostIrcMessage( _T("/INVITE %s %%question=\"%s\",\"%s\""), + gch->ptszUID, TranslateT("Please enter the channel name to invite to"), TranslateT("Invite to channel")); + break; + case 30: + { + PROTOSEARCHRESULT psr = { 0 }; + psr.cbSize = sizeof(psr); + psr.flags = PSR_TCHAR; + psr.id = gch->ptszUID; + psr.nick = gch->ptszUID; + + ADDCONTACTSTRUCT acs = { 0 }; + acs.handleType = HANDLE_SEARCHRESULT; + acs.szProto = m_szModuleName; + acs.psr = &psr; + CallService( MS_ADDCONTACT_SHOW, (WPARAM)NULL, (LPARAM)&acs); + } + break; + case 31: //slap + { + TCHAR tszTemp[4000]; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/slap %s"), gch->ptszUID); + PostIrcMessageWnd(p1, NULL, tszTemp); + } + break; + case 32: //nickserv info + { + TCHAR tszTemp[4000]; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/nickserv INFO %s ALL"), gch->ptszUID); + PostIrcMessageWnd(p1, NULL, tszTemp); + } + break; + case 33: //nickserv ghost + { + TCHAR tszTemp[4000]; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("/nickserv GHOST %s"), gch->ptszUID); + PostIrcMessageWnd(p1, NULL, tszTemp); + } + break; + } + break; + } + mir_free( p1 ); + } } } + + if ( gchtemp ) { + mir_free(gchtemp->pszUID); + mir_free(gchtemp->pszText); + mir_free(gchtemp->pDest->ptszID); + mir_free(gchtemp->pDest->pszModule); + mir_free(gchtemp->pDest); + mir_free(gchtemp); + } + LeaveCriticalSection(&m_gchook); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static gc_item logItems[] = { + { LPGENT("&Change your nickname" ), 1, MENU_ITEM, FALSE }, + { LPGENT("Channel &settings" ), 2, MENU_ITEM, FALSE }, + { _T(""), 0, MENU_SEPARATOR, FALSE }, + { LPGENT("NickServ"), 0, MENU_NEWPOPUP, FALSE }, + { LPGENT("Register nick" ), 5, MENU_POPUPITEM, TRUE }, + { LPGENT("Auth nick" ), 6, MENU_POPUPITEM, FALSE }, + { LPGENT("Delete nick" ), 7, MENU_POPUPITEM, FALSE }, + { LPGENT("Identify nick" ), 8, MENU_POPUPITEM, FALSE }, + { LPGENT("Remind password " ), 9, MENU_POPUPITEM, FALSE }, + { LPGENT("Set new password" ), 10, MENU_POPUPITEM, TRUE }, + { LPGENT("Set language" ), 11, MENU_POPUPITEM, FALSE }, + { LPGENT("Set homepage" ), 12, MENU_POPUPITEM, FALSE }, + { LPGENT("Set e-mail" ), 13, MENU_POPUPITEM, FALSE }, + { LPGENT("Set info" ), 14, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Hide e-mail from info" ), 20, MENU_POPUPITEM, FALSE }, + { LPGENT("Show e-mail in info" ), 21, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Set security for nick" ), 22, MENU_POPUPITEM, FALSE }, + { LPGENT("Remove security for nick" ), 23, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Link nick to current" ), 24, MENU_POPUPITEM, FALSE }, + { LPGENT("Unlink nick from current" ), 25, MENU_POPUPITEM, FALSE }, + { LPGENT("Set main nick" ), 26, MENU_POPUPITEM, FALSE }, + { LPGENT("List all your nicks" ), 27, MENU_POPUPITEM, FALSE }, + { LPGENT("List your channels" ), 28, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Kill unauthorized: off" ), 15, MENU_POPUPITEM, FALSE }, + { LPGENT("Kill unauthorized: on" ), 16, MENU_POPUPITEM, FALSE }, + { LPGENT("Kill unauthorized: quick" ), 17, MENU_POPUPITEM, FALSE }, + { _T("" ), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("Hide nick from list" ), 18, MENU_POPUPITEM, FALSE }, + { LPGENT("Show nick to list" ), 19, MENU_POPUPITEM, FALSE }, + { LPGENT("Show the server &window" ), 4, MENU_ITEM, FALSE }, + { _T(""), 0, MENU_SEPARATOR, FALSE }, + { LPGENT("&Leave the channel" ), 3, MENU_ITEM, FALSE } +}; + +static gc_item nickItems[] = { + { LPGENT("&WhoIs info"), 10, MENU_ITEM, FALSE }, //0 + { LPGENT("&Invite to channel"), 23, MENU_ITEM, FALSE }, + { LPGENT("Send ¬ice"), 22, MENU_ITEM, FALSE }, + { LPGENT("&Slap"), 31, MENU_ITEM, FALSE }, + { LPGENT("Nickserv info"), 32, MENU_ITEM, FALSE }, + { LPGENT("Nickserv kill ghost"), 33, MENU_ITEM, FALSE }, //5 + { LPGENT("&Control"), 0, MENU_NEWPOPUP, FALSE }, + { LPGENT("Give Owner"), 18, MENU_POPUPITEM, FALSE }, //7 + { LPGENT("Take Owner"), 19, MENU_POPUPITEM, FALSE }, + { LPGENT("Give Admin"), 20, MENU_POPUPITEM, FALSE }, + { LPGENT("Take Admin"), 21, MENU_POPUPITEM, FALSE }, //10 + { LPGENT("Give &Op"), 1, MENU_POPUPITEM, FALSE }, + { LPGENT("Take O&p"), 2, MENU_POPUPITEM, FALSE }, + { LPGENT("Give &Halfop"), 16, MENU_POPUPITEM, FALSE }, + { LPGENT("Take H&alfop"), 17, MENU_POPUPITEM, FALSE }, + { LPGENT("Give &Voice"), 3, MENU_POPUPITEM, FALSE }, //15 + { LPGENT("Take V&oice"), 4, MENU_POPUPITEM, FALSE }, + { _T(""), 0, MENU_POPUPSEPARATOR, FALSE }, + { LPGENT("&Kick"), 5, MENU_POPUPITEM, FALSE }, + { LPGENT("Ki&ck (reason)"), 6, MENU_POPUPITEM, FALSE }, + { LPGENT("&Ban"), 7, MENU_POPUPITEM, FALSE }, //20 + { LPGENT("Ban'&n kick"), 8, MENU_POPUPITEM, FALSE }, + { LPGENT("Ban'n kick (&reason)"), 9, MENU_POPUPITEM, FALSE }, + { LPGENT("&Direct Connection"), 0, MENU_NEWPOPUP, FALSE }, + { LPGENT("Request &Chat"), 13, MENU_POPUPITEM, FALSE }, + { LPGENT("Send &File"), 14, MENU_POPUPITEM, FALSE }, //25 + { LPGENT("Add to &ignore list"), 15, MENU_ITEM, FALSE }, + { _T(""), 12, MENU_SEPARATOR, FALSE }, + { LPGENT("&Add User"), 30, MENU_ITEM, FALSE } +}; + +int __cdecl CIrcProto::GCMenuHook(WPARAM, LPARAM lParam) +{ + GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam; + if ( gcmi ) { + if ( !lstrcmpiA( gcmi->pszModule, m_szModuleName )) { + if ( gcmi->Type == MENU_ON_LOG ) { + if ( lstrcmpi( gcmi->pszID, SERVERWINDOW)) { + gcmi->nItems = SIZEOF(logItems); + gcmi->Item = logItems; + } + else gcmi->nItems = 0; + } + + if (gcmi->Type == MENU_ON_NICKLIST) { + CONTACT user ={ (TCHAR*)gcmi->pszUID, NULL, NULL, false, false, false}; + HANDLE hContact = CList_FindContact(&user); + + gcmi->nItems = SIZEOF(nickItems); + gcmi->Item = nickItems; + BOOL bIsInList = (hContact && DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) == 0); + gcmi->Item[gcmi->nItems-1].bDisabled = bIsInList; + + unsigned long ulAdr = 0; + if (m_manualHost) + ulAdr = ConvertIPToInteger(m_mySpecifiedHostIP); + else + ulAdr = ConvertIPToInteger(m_IPFromServer?m_myHost:m_myLocalHost); + gcmi->Item[23].bDisabled = ulAdr == 0?TRUE:FALSE; //DCC submenu + + TCHAR stzChanName[100]; + const TCHAR* temp = _tcschr( gcmi->pszID, ' ' ); + int len = min((( temp == NULL ) ? lstrlen( gcmi->pszID ) : ( int )( temp - gcmi->pszID + 1 )), SIZEOF(stzChanName)-1 ); + lstrcpyn( stzChanName, gcmi->pszID, len ); + stzChanName[ len ] = 0; + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA,stzChanName, NULL, NULL, NULL, NULL, NULL, false, false, 0); + BOOL bServOwner = strchr(sUserModes.c_str(), 'q') == NULL?FALSE:TRUE; + BOOL bServAdmin = strchr(sUserModes.c_str(), 'a') == NULL?FALSE:TRUE; + BOOL bOwner = bServOwner?((wi->OwnMode>>4)&01):FALSE; + BOOL bAdmin = bServAdmin?((wi->OwnMode>>3)&01):FALSE; + BOOL bOp = strchr(sUserModes.c_str(), 'o') == NULL?FALSE:((wi->OwnMode>>2)&01); + BOOL bHalfop = strchr(sUserModes.c_str(), 'h') == NULL?FALSE:((wi->OwnMode>>1)&01); + + BOOL bForceEnable = GetAsyncKeyState(VK_CONTROL); + + gcmi->Item[6].bDisabled /* "Control" submenu */ = !(bForceEnable|| bHalfop || bOp || bAdmin || bOwner); + gcmi->Item[7].uType = gcmi->Item[8].uType = /* +/- Owner */ bServOwner?MENU_POPUPITEM:0; + gcmi->Item[9].uType = gcmi->Item[10].uType = /* +/- Admin */ bServAdmin?MENU_POPUPITEM:0; + gcmi->Item[7].bDisabled = gcmi->Item[8].bDisabled = gcmi->Item[9].bDisabled = gcmi->Item[10].bDisabled = /* +/- Owner/Admin */ + !(bForceEnable || bOwner); + gcmi->Item[11].bDisabled = gcmi->Item[12].bDisabled = gcmi->Item[13].bDisabled = gcmi->Item[14].bDisabled = /* +/- Op/hop */ + !(bForceEnable || bOp || bAdmin || bOwner); + } } } + + return 0; +} + +int __cdecl CIrcProto::OnPreShutdown(WPARAM, LPARAM) +{ + EnterCriticalSection(&cs); + + if ( m_perform && IsConnected()) + if ( DoPerform( "Event: Disconnect" )) + Sleep( 200 ); + + DisconnectAllDCCSessions( true ); + + if ( IsConnected()) + Disconnect(); + if ( m_listDlg ) + m_listDlg->Close(); + if ( m_nickDlg ) + m_nickDlg->Close(); + if ( m_joinDlg ) + m_joinDlg->Close(); + + LeaveCriticalSection(&cs); + return 0; +} + +int __cdecl CIrcProto::OnMenuPreBuild(WPARAM wParam, LPARAM) +{ + DBVARIANT dbv; + HANDLE hContact = ( HANDLE )wParam; + if ( !hContact ) + return 0; + + CLISTMENUITEM clmi = { 0 }; + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_FLAGS | CMIM_NAME | CMIM_ICON; + + char *szProto = ( char* ) CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) wParam, 0); + if ( szProto && !lstrcmpiA(szProto, m_szModuleName)) { + bool bIsOnline = getWord(hContact, "Status", ID_STATUS_OFFLINE)== ID_STATUS_OFFLINE ? false : true; + if ( getByte(hContact, "ChatRoom", 0) == GCW_CHATROOM) { + // context menu for chatrooms + clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); + } + else if ( !getTString( hContact, "Default", &dbv )) { + // context menu for contact + BYTE bDcc = getByte( hContact, "DCC", 0) ; + + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuChanSettings, ( LPARAM )&clmi ); + + clmi.flags = CMIM_FLAGS; + if ( bDcc ) { + // for DCC contact + clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuDisconnect, ( LPARAM )&clmi ); + } + else { + // for normal contact + clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + if ( !IsConnected()) + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuWhois, ( LPARAM )&clmi ); + + if (bIsOnline) { + DBVARIANT dbv3; + if ( !getString( hContact, "Host", &dbv3)) { + if (dbv3.pszVal[0] == 0) + clmi.flags = CMIM_FLAGS | CMIF_HIDDEN; + DBFreeVariant( &dbv3 ); + } + } + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hUMenuIgnore, ( LPARAM )&clmi ); + } + DBFreeVariant( &dbv ); + } } + + return 0; +} + +int __cdecl CIrcProto::OnDbSettingChanged(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = ( HANDLE ) wParam; + if ( hContact == NULL || !IsConnected()) + return 0; + + DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam; + if ( strcmp( cws->szModule, "CList" )) + return 0; + + if ( cws->value.type != DBVT_DELETED && !( cws->value.type==DBVT_BYTE && cws->value.bVal==0 )) + return 0; + + if ( !strcmp( cws->szSetting, "NotOnList" )) { + DBVARIANT dbv; + if ( !getTString( hContact, "Nick", &dbv )) { + if ( getByte( "MirVerAutoRequest", 1)) + PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), dbv.ptszVal ); + DBFreeVariant( &dbv ); + } } + return 0; +} +void __cdecl CIrcProto::ConnectServerThread( void* ) +{ + InterlockedIncrement((long *) &m_bConnectThreadRunning); + InterlockedIncrement((long *) &m_bConnectRequested); + while ( !Miranda_Terminated() && m_bConnectRequested > 0 ) { + while(m_bConnectRequested > 0) + InterlockedDecrement((long *) &m_bConnectRequested); + if (IsConnected()) { + Sleep(200); + Disconnect(); + } + + m_info.bNickFlag = false; + int Temp = m_iStatus; + m_iStatus = ID_STATUS_CONNECTING; + nickflag = true; + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp,ID_STATUS_CONNECTING); + Sleep(100); + EnterCriticalSection(&cs); + Connect(si); + LeaveCriticalSection(&cs); + if (IsConnected()) { + KillChatTimer( RetryTimer ); + + if ( m_mySpecifiedHost[0] ) + ircFork( &CIrcProto::ResolveIPThread, new IPRESOLVE( m_mySpecifiedHost, IP_MANUAL )); + + DoEvent(GC_EVENT_CHANGESESSIONAME, SERVERWINDOW, NULL, m_info.sNetwork.c_str(), NULL, NULL, NULL, FALSE, TRUE); + } + else { + Temp = m_iDesiredStatus; + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(m_szModuleName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK ); + ProtoBroadcastAck(m_szModuleName,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)Temp,ID_STATUS_OFFLINE); + Sleep(100); + } } + + InterlockedDecrement((long *) &m_bConnectThreadRunning); +} + +void __cdecl CIrcProto::DisconnectServerThread( void* ) +{ + EnterCriticalSection( &cs ); + KillChatTimer( RetryTimer ); + if ( IsConnected()) + Disconnect(); + LeaveCriticalSection( &cs ); + return; +} + +void CIrcProto::ConnectToServer(void) +{ + m_portCount = StrToIntA(m_portStart); + si.sServer = GetWord(m_serverName, 0); + si.iPort = m_portCount; + si.sNick = m_nick; + si.sUserID = m_userID; + si.sFullName = m_name; + si.sPassword = m_password; + si.bIdentServer = ((m_ident) ? (true) : (false)); + si.iIdentServerPort = StrToInt(m_identPort); + si.sIdentServerType = m_identSystem; + si.m_iSSL = m_iSSL; + { TCHAR* p = mir_a2t( m_network ); + si.sNetwork = p; + mir_free(p); + } + m_iRetryCount = 1; + KillChatTimer(RetryTimer); + if (m_retry) { + if (StrToInt(m_retryWait)<10) + lstrcpy(m_retryWait, _T("10")); + SetChatTimer(RetryTimer, StrToInt(m_retryWait)*1000, RetryTimerProc); + } + + bPerformDone = false; + bTempDisableCheck = false; + bTempForceCheck = false; + m_iTempCheckTime = 0; + sChannelPrefixes = _T("&#"); + sUserModes = "ov"; + sUserModePrefixes = _T("@+"); + sChannelModes = "btnimklps"; + + if (!m_bConnectThreadRunning) + ircFork( &CIrcProto::ConnectServerThread, 0 ); + else if (m_bConnectRequested < 1) + InterlockedIncrement((long *) &m_bConnectRequested); + + TCHAR szTemp[300]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0033%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u)"), + TranslateT("Connecting to"), si.sNetwork.c_str(), si.sServer.c_str(), si.iPort); + DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); +} + +void CIrcProto::DisconnectFromServer(void) +{ + GCEVENT gce = {0}; + GCDEST gcd = {0}; + + if ( m_perform && IsConnected()) + DoPerform( "Event: Disconnect" ); + + gcd.iType = GC_EVENT_CONTROL; + gcd.ptszID = NULL; // all windows + gcd.pszModule = m_szModuleName; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + + CallChatEvent( SESSION_TERMINATE, (LPARAM)&gce); + ircFork( &CIrcProto::DisconnectServerThread, 0 ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// GetMyAwayMsg - obtain the current away message + +INT_PTR __cdecl CIrcProto::GetMyAwayMsg(WPARAM wParam,LPARAM lParam) +{ + if (( int )wParam != m_iStatus ) + return 0; + + const TCHAR* p = m_statusMessage.c_str(); + + return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_t2u(p) : (INT_PTR)mir_t2a(p); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Service function creation + +VOID CALLBACK RetryTimerProc( HWND, UINT, UINT_PTR idEvent, DWORD ) +{ + CIrcProto* ppro = GetTimerOwner( idEvent ); + if ( !ppro ) + return; + + if ( ppro->m_iRetryCount <= StrToInt( ppro->m_retryCount) && ppro->m_retry ) { + ppro->m_portCount++; + if ( ppro->m_portCount > StrToIntA( ppro->m_portEnd ) || StrToIntA( ppro->m_portEnd ) == 0 ) + ppro->m_portCount = StrToIntA( ppro->m_portStart ); + ppro->si.iPort = ppro->m_portCount; + + TCHAR szTemp[300]; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("\0033%s \002%s\002 (") _T(TCHAR_STR_PARAM) _T(": %u, try %u)"), + TranslateT("Reconnecting to"), ppro->si.sNetwork.c_str(), ppro->si.sServer.c_str(), ppro->si.iPort, ppro->m_iRetryCount); + + ppro->DoEvent(GC_EVENT_INFORMATION, SERVERWINDOW, NULL, szTemp, NULL, NULL, NULL, true, false); + + if ( !ppro->m_bConnectThreadRunning ) + ppro->ircFork( &CIrcProto::ConnectServerThread, 0 ); + else + ppro->m_bConnectRequested = true; + + ppro->m_iRetryCount++; + } + else ppro->KillChatTimer( ppro->RetryTimer ); +} + +// logs text into NetLib (stolen from Jabber ;)) +void CIrcProto::DoNetlibLog( const char* fmt, ... ) +{ + va_list vararg; + va_start( vararg, fmt ); + char* str = ( char* )alloca( 32000 ); + mir_vsnprintf( str, 32000, fmt, vararg ); + va_end( vararg ); + + CallService( MS_NETLIB_LOG, ( WPARAM )hNetlib, ( LPARAM )str ); +} diff --git a/protocols/IRCG/src/tools.cpp b/protocols/IRCG/src/tools.cpp new file mode 100644 index 0000000000..83ac7ae60f --- /dev/null +++ b/protocols/IRCG/src/tools.cpp @@ -0,0 +1,905 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// Standard functions + +int CIrcProto::getByte( const char* name, BYTE defaultValue ) +{ return DBGetContactSettingByte( NULL, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getByte( HANDLE hContact, const char* name, BYTE defaultValue ) +{ return DBGetContactSettingByte(hContact, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getDword( const char* name, DWORD defaultValue ) +{ return DBGetContactSettingDword( NULL, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getDword( HANDLE hContact, const char* name, DWORD defaultValue ) +{ return DBGetContactSettingDword(hContact, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getString( const char* name, DBVARIANT* result ) +{ return DBGetContactSettingString( NULL, m_szModuleName, name, result ); +} + +int CIrcProto::getString( HANDLE hContact, const char* name, DBVARIANT* result ) +{ return DBGetContactSettingString( hContact, m_szModuleName, name, result ); +} + +int CIrcProto::getTString( const char* name, DBVARIANT* result ) +{ return DBGetContactSettingTString( NULL, m_szModuleName, name, result ); +} + +int CIrcProto::getTString( HANDLE hContact, const char* name, DBVARIANT* result ) +{ return DBGetContactSettingTString( hContact, m_szModuleName, name, result ); +} + +int CIrcProto::getWord( const char* name, WORD defaultValue ) +{ return DBGetContactSettingWord( NULL, m_szModuleName, name, defaultValue ); +} + +int CIrcProto::getWord( HANDLE hContact, const char* name, WORD defaultValue ) +{ return DBGetContactSettingWord(hContact, m_szModuleName, name, defaultValue ); +} + +void CIrcProto::setByte( const char* name, BYTE value ) +{ DBWriteContactSettingByte(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setByte( HANDLE hContact, const char* name, BYTE value ) +{ DBWriteContactSettingByte(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setDword( const char* name, DWORD value ) +{ DBWriteContactSettingDword(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setDword( HANDLE hContact, const char* name, DWORD value ) +{ DBWriteContactSettingDword(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setString( const char* name, const char* value ) +{ DBWriteContactSettingString(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setString( HANDLE hContact, const char* name, const char* value ) +{ DBWriteContactSettingString(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setTString( const char* name, const TCHAR* value ) +{ DBWriteContactSettingTString(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setTString( HANDLE hContact, const char* name, const TCHAR* value ) +{ DBWriteContactSettingTString(hContact, m_szModuleName, name, value ); +} + +void CIrcProto::setWord( const char* name, int value ) +{ DBWriteContactSettingWord(NULL, m_szModuleName, name, value ); +} + +void CIrcProto::setWord( HANDLE hContact, const char* name, int value ) +{ DBWriteContactSettingWord(hContact, m_szModuleName, name, value ); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIrcProto::AddToJTemp(TCHAR op, CMString& sCommand) +{ + CMString res; + + int pos = 0; + for ( ;; ) { + CMString tmp = sCommand.Tokenize( _T(","), pos ); + if ( pos == -1 ) + break; + + tmp = op + tmp; + if ( res.IsEmpty()) + res = tmp; + else + res += _T(" ") + tmp; + } + + DBVARIANT dbv; + if ( !getTString( "JTemp", &dbv )) { + res = CMString(dbv.ptszVal) + _T(" ") + res; + DBFreeVariant( &dbv ); + } + + setTString("JTemp", res.c_str()); +} + +void CIrcProto::ircFork( IrcThreadFunc pFunc, void* arg ) +{ + unsigned threadID; + CloseHandle(( HANDLE )::mir_forkthreadowner(( pThreadFuncOwner )( *( void** )&pFunc ), this, arg, &threadID )); +} + +HANDLE CIrcProto::ircForkEx( IrcThreadFunc pFunc, void* arg ) +{ + unsigned threadID; + return (HANDLE)::mir_forkthreadowner(( pThreadFuncOwner )( *( void** )&pFunc ), this, arg, &threadID ); +} + +void CIrcProto::IrcHookEvent( const char* szEvent, IrcEventFunc pFunc ) +{ + ::HookEventObj( szEvent, ( MIRANDAHOOKOBJ )*( void** )&pFunc, this ); +} + +CMString __stdcall GetWord(const TCHAR* text, int index) +{ + if ( text && *text ) { + TCHAR* p1 = (TCHAR*)text; + TCHAR* p2 = NULL; + + while (*p1 == ' ') + p1++; + + if (*p1 != '\0') { + for (int i =0; i < index; i++) { + p2 = _tcschr( p1, ' ' ); + if ( !p2 ) + p2 = _tcschr( p1, '\0' ); + else + while ( *p2 == ' ' ) + p2++; + + p1 = p2; + } + + p2 = _tcschr(p1, ' '); + if ( !p2 ) + p2 = _tcschr(p1, '\0'); + + if (p1 != p2) + return CMString( p1, p2-p1 ); + } } + + return CMString(); +} + +const TCHAR* __stdcall GetWordAddress(const TCHAR* text, int index) +{ + if ( !text || !lstrlen(text)) + return text; + + const TCHAR* temp = text; + + while (*temp == ' ') + temp++; + + if (index == 0) + return temp; + + for (int i = 0; i < index; i++) { + temp = _tcschr(temp, ' '); + if ( !temp ) + temp = ( TCHAR* )_tcschr(text, '\0'); + else + while (*temp == ' ') + temp++; + text = temp; + } + + return temp; +} + +void __stdcall RemoveLinebreaks( CMString& Message ) +{ + while ( Message.Find( _T("\r\n\r\n"), 0) != -1 ) + ReplaceString( Message, _T("\r\n\r\n"), _T("\r\n")); + + if (Message.Find( _T("\r\n"), 0) == 0) + Message.Delete(0,2); + + if ( (Message.GetLength() > 1) && (Message.Find(_T("\r\n"), Message.GetLength()-2) == 0)) + Message.Delete(Message.GetLength()-2, 2); +} + +String& __stdcall ReplaceString ( String& text, const char* replaceme, const char* newword ) +{ + if ( !text.IsEmpty() && replaceme != NULL) { + int i = 0; + while (( i = text.Find(replaceme, i)) != -1 ) { + text.Delete(i,lstrlenA(replaceme)); + text.Insert(i, newword); + i = i + lstrlenA(newword); + } } + + return text; +} + +CMString& __stdcall ReplaceString ( CMString& text, const TCHAR* replaceme, const TCHAR* newword) +{ + if ( !text.IsEmpty() && replaceme != NULL) { + int i = 0; + while (( i = text.Find(replaceme, i)) != -1 ) { + text.Delete(i,lstrlen(replaceme)); + text.Insert(i, newword); + i = i + lstrlen(newword); + } } + + return text; +} + +char* __stdcall IrcLoadFile( TCHAR* szPath) +{ + char * szContainer = NULL; + DWORD dwSiz = 0; + FILE *hFile = _tfopen(szPath, _T("rb")); + if ( hFile != NULL ) + { + fseek(hFile,0,SEEK_END); // seek to end + dwSiz = ftell(hFile); // size + fseek(hFile,0,SEEK_SET); // seek back to original pos + szContainer = new char [dwSiz+1]; + fread(szContainer, 1, dwSiz, hFile); + szContainer[dwSiz] = '\0'; + fclose(hFile); + return szContainer; + } + + return 0; +} + +int __stdcall WCCmp( const TCHAR* wild, const TCHAR* string ) +{ + if ( wild == NULL || !lstrlen(wild) || string == NULL || !lstrlen(string)) + return 1; + + const TCHAR *cp = NULL, *mp = NULL; + while ((*string) && (*wild != '*')) { + if ((*wild != *string) && (*wild != '?')) + return 0; + + wild++; + string++; + } + + while (*string) { + if (*wild == '*') { + if (!*++wild) + return 1; + + mp = wild; + cp = string+1; + } + else if ((*wild == *string) || (*wild == '?')) { + wild++; + string++; + } + else { + wild = mp; + string = cp++; + } } + + while (*wild == '*') + wild++; + + return !*wild; +} + +bool CIrcProto::IsChannel(const TCHAR* sName) +{ + return ( sChannelPrefixes.Find( sName[0] ) != -1 ); +} + +String __stdcall GetWord(const char* text, int index) +{ + if ( text && text[0] ) { + char* p1 = (char*)text; + char* p2 = NULL; + + while (*p1 == ' ') + p1++; + + if (*p1 != '\0') { + for (int i =0; i < index; i++) { + p2 = strchr( p1, ' ' ); + if ( !p2 ) + p2 = strchr( p1, '\0' ); + else + while ( *p2 == ' ' ) + p2++; + + p1 = p2; + } + + p2 = strchr(p1, ' '); + if (!p2) + p2 = strchr(p1, '\0'); + + if (p1 != p2) + return String( p1, p2-p1+1 ); + } } + + return String(); +} + +bool CIrcProto::IsChannel(const char* sName) +{ + return ( sChannelPrefixes.Find( sName[0] ) != -1 ); +} + +TCHAR* __stdcall my_strstri(const TCHAR* s1, const TCHAR* s2) +{ + int i,j,k; + for(i=0;s1[i];i++) + for(j=i,k=0; _totlower(s1[j]) == _totlower(s2[k]);j++,k++) + if (!s2[k+1]) + return ( TCHAR* )(s1+i); + + return NULL; +} + +TCHAR* __stdcall DoColorCodes (const TCHAR* text, bool bStrip, bool bReplacePercent) +{ + static TCHAR szTemp[4000]; szTemp[0] = '\0'; + TCHAR* p = szTemp; + bool bBold = false; + bool bUnderline = false; + bool bItalics = false; + + if ( !text ) + return szTemp; + + while ( *text != '\0' ) { + int iFG = -1; + int iBG = -1; + + switch( *text ) { + case '%': //escape + *p++ = '%'; + if ( bReplacePercent ) + *p++ = '%'; + text++; + break; + + case 2: //bold + if ( !bStrip ) { + *p++ = '%'; + *p++ = bBold ? 'B' : 'b'; + } + bBold = !bBold; + text++; + break; + + case 15: //reset + if ( !bStrip ) { + *p++ = '%'; + *p++ = 'r'; + } + bUnderline = false; + bBold = false; + text++; + break; + + case 22: //italics + if ( !bStrip ) { + *p++ = '%'; + *p++ = bItalics ? 'I' : 'i'; + } + bItalics = !bItalics; + text++; + break; + + case 31: //underlined + if ( !bStrip ) { + *p++ = '%'; + *p++ = bUnderline ? 'U' : 'u'; + } + bUnderline = !bUnderline; + text++; + break; + + case 3: //colors + text++; + + // do this if the colors should be reset to default + if ( *text <= 47 || *text >= 58 || *text == '\0' ) { + if ( !bStrip ) { + *p++ = '%'; + *p++ = 'C'; + *p++ = '%'; + *p++ = 'F'; + } + break; + } + else { // some colors should be set... need to find out who + TCHAR buf[3]; + + // fix foreground index + if ( text[1] > 47 && text[1] < 58 && text[1] != '\0') + lstrcpyn( buf, text, 3 ); + else + lstrcpyn( buf, text, 2 ); + text += lstrlen( buf ); + iFG = _ttoi( buf ); + + // fix background color + if ( *text == ',' && text[1] > 47 && text[1] < 58 && text[1] != '\0' ) { + text++; + + if ( text[1] > 47 && text[1] < 58 && text[1] != '\0' ) + lstrcpyn( buf, text, 3 ); + else + lstrcpyn( buf, text, 2 ); + text += lstrlen( buf ); + iBG = _ttoi( buf ); + } } + + if ( iFG >= 0 && iFG != 99 ) + while( iFG > 15 ) + iFG -= 16; + if ( iBG >= 0 && iBG != 99 ) + while( iBG > 15 ) + iBG -= 16; + + // create tag for chat.dll + if ( !bStrip ) { + TCHAR buf[10]; + if ( iFG >= 0 && iFG != 99 ) { + *p++ = '%'; + *p++ = 'c'; + + mir_sntprintf( buf, SIZEOF(buf), _T("%02u"), iFG ); + for (int i = 0; i<2; i++) + *p++ = buf[i]; + } + else if (iFG == 99) { + *p++ = '%'; + *p++ = 'C'; + } + + if ( iBG >= 0 && iBG != 99 ) { + *p++ = '%'; + *p++ = 'f'; + + mir_sntprintf( buf, SIZEOF(buf), _T("%02u"), iBG ); + for ( int i = 0; i<2; i++ ) + *p++ = buf[i]; + } + else if ( iBG == 99 ) { + *p++ = '%'; + *p++ = 'F'; + } } + break; + + default: + *p++ = *text++; + break; + } } + + *p = '\0'; + return szTemp; +} + +INT_PTR CIrcProto::CallChatEvent(WPARAM wParam, LPARAM lParam) +{ + GCEVENT * gce = (GCEVENT *)lParam; + INT_PTR iVal = 0; + + // first see if the scripting module should modify or stop this event + if ( m_bMbotInstalled && m_scriptingEnabled && gce + && gce->time != 0 && (gce->pDest->pszID == NULL + || lstrlen(gce->pDest->ptszID) != 0 && lstrcmpi(gce->pDest->ptszID , SERVERWINDOW))) + { + GCEVENT *gcevent= (GCEVENT*) lParam; + GCEVENT *gcetemp = NULL; + WPARAM wp = wParam; + gcetemp = (GCEVENT *)mir_alloc(sizeof(GCEVENT)); + gcetemp->pDest = (GCDEST *)mir_alloc(sizeof(GCDEST)); + gcetemp->pDest->iType = gcevent->pDest->iType; + gcetemp->dwFlags = gcevent->dwFlags; + gcetemp->bIsMe = gcevent->bIsMe; + gcetemp->cbSize = sizeof(GCEVENT); + gcetemp->dwItemData = gcevent->dwItemData; + gcetemp->time = gcevent->time; + gcetemp->pDest->ptszID = mir_tstrdup( gcevent->pDest->ptszID ); + gcetemp->pDest->pszModule = mir_strdup( gcevent->pDest->pszModule ); + gcetemp->ptszText = mir_tstrdup( gcevent->ptszText ); + gcetemp->ptszUID = mir_tstrdup( gcevent->ptszUID ); + gcetemp->ptszNick = mir_tstrdup( gcevent->ptszNick ); + gcetemp->ptszStatus = mir_tstrdup( gcevent->ptszStatus ); + gcetemp->ptszUserInfo = mir_tstrdup( gcevent->ptszUserInfo ); + + if ( Scripting_TriggerMSPGuiIn( &wp, gcetemp ) && gcetemp ) { + //MBOT CORRECTIONS + //if ( gcetemp && gcetemp->pDest && gcetemp->pDest->ptszID ) { + if ( gcetemp && gcetemp->pDest && gcetemp->pDest->ptszID && + !my_strstri(gcetemp->pDest->ptszID, (IsConnected()) ? m_info.sNetwork.c_str() : TranslateT("Offline"))) { + + CMString sTempId = MakeWndID( gcetemp->pDest->ptszID ); + mir_realloc( gcetemp->pDest->ptszID, sizeof(TCHAR)*(sTempId.GetLength() + 1)); + lstrcpyn(gcetemp->pDest->ptszID, sTempId.c_str(), sTempId.GetLength()+1); + } + iVal = CallServiceSync(MS_GC_EVENT, wp, (LPARAM) gcetemp); + } + + if ( gcetemp ) { + mir_free(( void* )gcetemp->pszNick); + mir_free(( void* )gcetemp->pszUID); + mir_free(( void* )gcetemp->pszStatus); + mir_free(( void* )gcetemp->pszUserInfo); + mir_free(( void* )gcetemp->pszText); + mir_free(( void* )gcetemp->pDest->pszID); + mir_free(( void* )gcetemp->pDest->pszModule); + mir_free(( void* )gcetemp->pDest); + mir_free(( void* )gcetemp); + } + + return iVal; + } + + return CallServiceSync( MS_GC_EVENT, wParam, ( LPARAM )gce ); +} + +INT_PTR CIrcProto::DoEvent(int iEvent, const TCHAR* pszWindow, const TCHAR* pszNick, + const TCHAR* pszText, const TCHAR* pszStatus, const TCHAR* pszUserInfo, + DWORD_PTR dwItemData, bool bAddToLog, bool bIsMe, time_t timestamp) +{ + GCDEST gcd = {0}; + GCEVENT gce = {0}; + CMString sID; + CMString sText = _T(""); + + if ( iEvent == GC_EVENT_INFORMATION && bIsMe && !bEcho ) + return false; + + if ( pszText ) { + if (iEvent != GC_EVENT_SENDMESSAGE) + sText = DoColorCodes(pszText, FALSE, TRUE); + else + sText = pszText; + } + + if ( pszWindow ) { + if ( lstrcmpi( pszWindow, SERVERWINDOW)) + sID = pszWindow + (CMString)_T(" - ") + m_info.sNetwork; + else + sID = pszWindow; + gcd.ptszID = (TCHAR*)sID.c_str(); + } + else gcd.ptszID = NULL; + + gcd.pszModule = m_szModuleName; + gcd.iType = iEvent; + + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.ptszStatus = pszStatus; + gce.dwFlags = GC_TCHAR + ((bAddToLog) ? GCEF_ADDTOLOG : 0); + gce.ptszNick = pszNick; + gce.ptszUID = pszNick; + if (iEvent == GC_EVENT_TOPIC) + gce.ptszUserInfo = pszUserInfo; + else + gce.ptszUserInfo = m_showAddresses ? pszUserInfo : NULL; + + if ( !sText.IsEmpty()) + gce.ptszText = sText.c_str(); + + gce.dwItemData = dwItemData; + if(timestamp == 1) + gce.time = time(NULL); + else + gce.time = timestamp; + gce.bIsMe = bIsMe; + return CallChatEvent((WPARAM)0, (LPARAM)&gce); +} + +CMString CIrcProto::ModeToStatus(int sMode) +{ + if ( sUserModes.Find( sMode ) != -1 ) { + switch( sMode ) { + case 'q': + return (CMString)_T("Owner"); + case 'o': + return (CMString)_T("Op"); + case 'v': + return (CMString)_T("Voice"); + case 'h': + return (CMString)_T("Halfop"); + case 'a': + return (CMString)_T("Admin"); + default: + return (CMString)_T("Unknown"); + } } + + return (CMString)_T("Normal"); +} + +CMString CIrcProto::PrefixToStatus(int cPrefix) +{ + const TCHAR* p = _tcschr( sUserModePrefixes.c_str(), cPrefix ); + if ( p ) { + int index = int( p - sUserModePrefixes.c_str()); + return ModeToStatus( sUserModes[index] ); + } + + return (CMString)_T("Normal"); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Timer functions + +struct TimerPair +{ + TimerPair( CIrcProto* _pro, UINT_PTR _id ) : + ppro( _pro ), + idEvent( _id ) + {} + + UINT_PTR idEvent; + CIrcProto* ppro; +}; + +static int CompareTimers( const TimerPair* p1, const TimerPair* p2 ) +{ + if ( p1->idEvent < p2->idEvent ) + return -1; + return ( p1->idEvent == p2->idEvent ) ? 0 : 1; +} + +static OBJLIST timers( 10, CompareTimers ); +static CRITICAL_SECTION timers_cs; + +void InitTimers( void ) +{ + InitializeCriticalSection( &timers_cs ); +} + +void UninitTimers( void ) +{ + EnterCriticalSection( &timers_cs ); + timers.destroy(); + LeaveCriticalSection( &timers_cs ); + DeleteCriticalSection( &timers_cs ); +} + +CIrcProto* GetTimerOwner( UINT_PTR nIDEvent ) +{ + CIrcProto* result; + + EnterCriticalSection( &timers_cs ); + TimerPair temp( NULL, nIDEvent ); + int idx = timers.getIndex( &temp ); + if ( idx == -1 ) + result = NULL; + else + result = timers[ idx ].ppro; + LeaveCriticalSection( &timers_cs ); + return result; +} + +void CIrcProto::SetChatTimer(UINT_PTR &nIDEvent,UINT uElapse, TIMERPROC lpTimerFunc) +{ + if (nIDEvent) + KillChatTimer(nIDEvent); + + nIDEvent = SetTimer( NULL, NULL, uElapse, lpTimerFunc); + + EnterCriticalSection( &timers_cs ); + timers.insert( new TimerPair( this, nIDEvent )); + LeaveCriticalSection( &timers_cs ); +} + +void CIrcProto::KillChatTimer(UINT_PTR &nIDEvent) +{ + if ( nIDEvent ) { + EnterCriticalSection( &timers_cs ); + TimerPair temp( this, nIDEvent ); + int idx = timers.getIndex( &temp ); + if ( idx != -1 ) + timers.remove( idx ); + + LeaveCriticalSection( &timers_cs ); + + KillTimer(NULL, nIDEvent); + nIDEvent = NULL; +} } + +///////////////////////////////////////////////////////////////////////////////////////// + +int CIrcProto::SetChannelSBText(CMString sWindow, CHANNELINFO * wi) +{ + CMString sTemp = _T(""); + if(wi->pszMode) + { + sTemp += _T("["); + sTemp += wi->pszMode; + sTemp += _T("] "); + } + if(wi->pszTopic) + sTemp += wi->pszTopic; + sTemp = DoColorCodes(sTemp.c_str(), TRUE, FALSE); + return DoEvent(GC_EVENT_SETSBTEXT, sWindow.c_str(), NULL, sTemp.c_str(), NULL, NULL, NULL, FALSE, FALSE, 0); +} + +CMString CIrcProto::MakeWndID(const TCHAR* sWindow) +{ + TCHAR buf[200]; + mir_sntprintf( buf, SIZEOF(buf), _T("%s - %s"), sWindow, (IsConnected()) ? m_info.sNetwork.c_str() : TranslateT("Offline")); + return CMString(buf); +} + +bool CIrcProto::FreeWindowItemData(CMString window, CHANNELINFO* wis) +{ + CHANNELINFO* wi; + if ( !wis ) + wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window.c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + else + wi = wis; + if ( wi ) { + delete[] wi->pszLimit; + delete[]wi->pszMode; + delete[]wi->pszPassword; + delete[]wi->pszTopic; + delete wi; + return true; + } + return false; +} + +bool CIrcProto::AddWindowItemData(CMString window, const TCHAR* pszLimit, const TCHAR* pszMode, const TCHAR* pszPassword, const TCHAR* pszTopic) +{ + CHANNELINFO* wi = (CHANNELINFO *)DoEvent(GC_EVENT_GETITEMDATA, window.c_str(), NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi ) { + if ( pszLimit ) { + wi->pszLimit = ( TCHAR* )realloc( wi->pszLimit, sizeof(TCHAR)*(lstrlen(pszLimit)+1)); + lstrcpy( wi->pszLimit, pszLimit ); + } + if ( pszMode ) { + wi->pszMode = ( TCHAR* )realloc( wi->pszMode, sizeof(TCHAR)*(lstrlen(pszMode)+1)); + lstrcpy( wi->pszMode, pszMode ); + } + if ( pszPassword ) { + wi->pszPassword = ( TCHAR* )realloc( wi->pszPassword, sizeof(TCHAR)*(lstrlen(pszPassword)+1)); + lstrcpy( wi->pszPassword, pszPassword ); + } + if ( pszTopic ) { + wi->pszTopic = ( TCHAR* )realloc( wi->pszTopic, sizeof(TCHAR)*(lstrlen(pszTopic)+1)); + lstrcpy( wi->pszTopic, pszTopic ); + } + + SetChannelSBText(window, wi); + return true; + } + return false; +} + +void CIrcProto::CreateProtoService( const char* serviceName, IrcServiceFunc pFunc ) +{ + char temp[MAXMODULELABELLENGTH]; + mir_snprintf( temp, sizeof(temp), "%s%s", m_szModuleName, serviceName ); + CreateServiceFunctionObj( temp, ( MIRANDASERVICEOBJ )*( void** )&pFunc, this ); +} + +void CIrcProto::FindLocalIP(HANDLE con) // inspiration from jabber +{ + // Determine local IP + int socket = CallService( MS_NETLIB_GETSOCKET, (WPARAM) con, 0); + if ( socket != INVALID_SOCKET ) { + struct sockaddr_in saddr; + int len = sizeof(saddr); + getsockname(socket, (struct sockaddr *) &saddr, &len); + lstrcpynA(m_myLocalHost, inet_ntoa(saddr.sin_addr), 49); + m_myLocalPort = ntohs(saddr.sin_port ); +} } + +void CIrcProto::DoUserhostWithReason(int type, CMString reason, bool bSendCommand, CMString userhostparams, ...) +{ + TCHAR temp[4096]; + CMString S = _T(""); + switch( type ) { + case 1: + S = _T("USERHOST"); + break; + case 2: + S = _T("WHO"); + break; + default: + S = _T("USERHOST"); + break; + } + + va_list ap; + va_start(ap, userhostparams); + mir_vsntprintf(temp, SIZEOF(temp), (S + _T(" ") + userhostparams).c_str(), ap); + va_end(ap); + + // Add reason + if ( type == 1 ) + vUserhostReasons.insert( new CMString( reason )); + else if ( type == 2 ) + vWhoInProgress.insert( new CMString( reason)); + + // Do command + if ( IsConnected() && bSendCommand ) + SendIrcMessage( temp, false ); +} + +CMString CIrcProto::GetNextUserhostReason(int type) +{ + CMString reason = _T(""); + switch( type ) { + case 1: + if ( !vUserhostReasons.getCount()) + return CMString(); + + // Get reason + reason = vUserhostReasons[0]; + vUserhostReasons.remove( 0 ); + break; + case 2: + if ( !vWhoInProgress.getCount()) + return CMString(); + + // Get reason + reason = vWhoInProgress[0]; + vWhoInProgress.remove( 0 ); + break; + } + + return reason; +} + +CMString CIrcProto::PeekAtReasons( int type ) +{ + switch ( type ) { + case 1: + if (!vUserhostReasons.getCount()) + return CMString(); + return vUserhostReasons[0]; + + case 2: + if (!vWhoInProgress.getCount()) + return CMString(); + return vWhoInProgress[0]; + + } + return CMString(); +} + +void CIrcProto::ClearUserhostReasons(int type) +{ + switch (type) { + case 1: + vUserhostReasons.destroy(); + break; + case 2: + vWhoInProgress.destroy(); + break; +} } + +//////////////////////////////////////////////////////////////////// + +SERVER_INFO::~SERVER_INFO() +{ + mir_free( m_name ); + mir_free( m_address ); + mir_free( m_group ); +} diff --git a/protocols/IRCG/src/ui_utils.cpp b/protocols/IRCG/src/ui_utils.cpp new file mode 100644 index 0000000000..d7c8e4b6b6 --- /dev/null +++ b/protocols/IRCG/src/ui_utils.cpp @@ -0,0 +1,1820 @@ +/* + +Object UI extensions +Copyright (C) 2008 Victor Pavlychko, George Hazan + +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. + +File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IRCG/ui_utils.cpp $ +Revision : $Revision: 13133 $ +Last change on : $Date: 2010-11-17 15:54:24 +0200 (Ср, 17 Ð½Ð¾Ñ 2010) $ +Last change by : $Author: george.hazan $ + +*/ + +#include "irc.h" +#include "ui_utils.h" + +extern HINSTANCE hInst; + +CDlgBase::CDlgBase(int idDialog, HWND hwndParent) : + m_controls(1, CCtrlBase::cmp) +{ + m_idDialog = idDialog; + m_hwndParent = hwndParent; + m_hwnd = NULL; + m_first = NULL; + m_isModal = false; + m_initialized = false; + m_autoClose = CLOSE_ON_OK|CLOSE_ON_CANCEL; + m_forceResizable = false; +} + +CDlgBase::~CDlgBase() +{ + // remove handlers + m_controls.destroy(); + + if (m_hwnd) + DestroyWindow(m_hwnd); +} + +void CDlgBase::Create() +{ + ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_HIDE); +} + +void CDlgBase::Show() +{ + ShowWindow(CreateDialogParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this), SW_SHOW); +} + +int CDlgBase::DoModal() +{ + m_isModal = true; + return DialogBoxParam(hInst, MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)(CDlgBase *)this); +} + +int CDlgBase::Resizer(UTILRESIZECONTROL*) +{ + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +INT_PTR CDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + m_initialized = false; + TranslateDialogDefault(m_hwnd); + + for ( CCtrlBase* p = m_first; p != NULL; p = p->m_next ) + AddControl( p ); + + NotifyControls(&CCtrlBase::OnInit); + OnInitDialog(); + + m_initialized = true; + return TRUE; + } + + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT *param = (MEASUREITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnMeasureItem(param); + return FALSE; + } + + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *param = (DRAWITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnDrawItem(param); + return FALSE; + } + + case WM_DELETEITEM: + { + DELETEITEMSTRUCT *param = (DELETEITEMSTRUCT *)lParam; + if (param && param->CtlID) + if (CCtrlBase *ctrl = FindControl(param->CtlID)) + return ctrl->OnDeleteItem(param); + return FALSE; + } + + case WM_COMMAND: + { + HWND hwndCtrl = (HWND)lParam; + WORD idCtrl = LOWORD(wParam); + WORD idCode = HIWORD(wParam); + if (CCtrlBase *ctrl = FindControl(idCtrl)) { + BOOL result = ctrl->OnCommand(hwndCtrl, idCtrl, idCode); + if ( result != FALSE ) + return result; + } + + if (idCode == BN_CLICKED && + ((idCtrl == IDOK) && (m_autoClose & CLOSE_ON_OK) || + (idCtrl == IDCANCEL) && (m_autoClose & CLOSE_ON_CANCEL))) + { + PostMessage( m_hwnd, WM_CLOSE, 0, 0 ); + } + return FALSE; + } + + case WM_NOTIFY: + { + int idCtrl = wParam; + NMHDR *pnmh = (NMHDR *)lParam; + + if (pnmh->idFrom == 0) + { + if (pnmh->code == PSN_APPLY) + { + NotifyControls(&CCtrlBase::OnApply); + OnApply(); + } + else if (pnmh->code == PSN_RESET) + { + NotifyControls(&CCtrlBase::OnReset); + OnReset(); + } + } + + if (CCtrlBase *ctrl = FindControl(pnmh->idFrom)) + return ctrl->OnNotify(idCtrl, pnmh); + return FALSE; + } + + case WM_SIZE: + { + if (m_forceResizable || (GetWindowLongPtr(m_hwnd, GWL_STYLE) & WS_SIZEBOX)) + { + UTILRESIZEDIALOG urd; + urd.cbSize = sizeof(urd); + urd.hwndDlg = m_hwnd; + urd.hInstance = hInst; + urd.lpTemplate = MAKEINTRESOURCEA(m_idDialog); + urd.lParam = 0; + urd.pfnResizer = GlobalDlgResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + } + return TRUE; + } + + case WM_CLOSE: + { + m_lresult = FALSE; + OnClose(); + if ( !m_lresult ) + { + if (m_isModal) + EndDialog(m_hwnd, 0); + else + DestroyWindow(m_hwnd); + } + return TRUE; + } + + case WM_DESTROY: + { + OnDestroy(); + NotifyControls(&CCtrlBase::OnDestroy); + + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + m_hwnd = NULL; + if (m_isModal) + { + m_isModal = false; + } else + { // modeless dialogs MUST be allocated with 'new' + delete this; + } + return TRUE; + } + } + + return FALSE; +} + +INT_PTR CALLBACK CDlgBase::GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CDlgBase *wnd = NULL; + if (msg == WM_INITDIALOG) + { + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + wnd = (CDlgBase *)lParam; + wnd->m_hwnd = hwnd; + } else + { + wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + } + + if (!wnd) return FALSE; + + wnd->m_msg.hwnd = hwnd; + wnd->m_msg.message = msg; + wnd->m_msg.wParam = wParam; + wnd->m_msg.lParam = lParam; + return wnd->DlgProc(msg, wParam, lParam); +} + +int CDlgBase::GlobalDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc) +{ + CDlgBase *wnd = (CDlgBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!wnd) return 0; + + return wnd->Resizer(urc); +} + +void CDlgBase::AddControl(CCtrlBase *ctrl) +{ + m_controls.insert(ctrl); +} + +void CDlgBase::NotifyControls(void (CCtrlBase::*fn)()) +{ + for (int i = 0; i < m_controls.getCount(); ++i) + (m_controls[i]->*fn)(); +} + +CCtrlBase* CDlgBase::FindControl(int idCtrl) +{ + CCtrlBase search(NULL, idCtrl); + return m_controls.find(&search); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo class + +CCtrlCombo::CCtrlCombo( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +int CCtrlCombo::AddString(const TCHAR *text, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if ( data ) + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +int CCtrlCombo::AddStringA(const char *text, LPARAM data) +{ + int iItem = SendMessageA(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if ( data ) + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlCombo::DeleteString(int index) +{ SendMessage(m_hwnd, CB_DELETESTRING, index, 0); +} + +int CCtrlCombo::FindString(const TCHAR *str, int index, bool exact ) +{ return SendMessage(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlCombo::FindStringA(const char *str, int index, bool exact ) +{ return SendMessageA(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlCombo::GetCount() +{ return SendMessage(m_hwnd, CB_GETCOUNT, 0, 0); +} + +int CCtrlCombo::GetCurSel() +{ return SendMessage(m_hwnd, CB_GETCURSEL, 0, 0); +} + +bool CCtrlCombo::GetDroppedState() +{ return SendMessage(m_hwnd, CB_GETDROPPEDSTATE, 0, 0) ? true : false; +} + +LPARAM CCtrlCombo::GetItemData(int index) +{ return SendMessage(m_hwnd, CB_GETITEMDATA, index, 0); +} + +TCHAR* CCtrlCombo::GetItemText(int index) +{ + TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); + return result; +} + +TCHAR* CCtrlCombo::GetItemText(int index, TCHAR *buf, int size) +{ + TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result); + lstrcpyn(buf, result, size); + return buf; +} + +int CCtrlCombo::InsertString(TCHAR *text, int pos, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlCombo::ResetContent() +{ SendMessage(m_hwnd, CB_RESETCONTENT, 0, 0); +} + +int CCtrlCombo::SelectString(TCHAR *str) +{ return SendMessage(m_hwnd, CB_SELECTSTRING, 0, (LPARAM)str); +} + +int CCtrlCombo::SetCurSel(int index) +{ return SendMessage(m_hwnd, CB_SETCURSEL, index, 0); +} + +void CCtrlCombo::SetItemData(int index, LPARAM data) +{ SendMessage(m_hwnd, CB_SETITEMDATA, index, data); +} + +void CCtrlCombo::ShowDropdown(bool show) +{ SendMessage(m_hwnd, CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox class + +CCtrlListBox::CCtrlListBox( CDlgBase* dlg, int ctrlId ) : + CCtrlBase( dlg, ctrlId ) +{ +} + +BOOL CCtrlListBox::OnCommand(HWND, WORD, WORD idCode) +{ + switch (idCode) + { + case LBN_DBLCLK: OnDblClick(this); break; + case LBN_SELCANCEL: OnSelCancel(this); break; + case LBN_SELCHANGE: OnSelChange(this); break; + } + return TRUE; +} + +int CCtrlListBox::AddString(TCHAR *text, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, LB_ADDSTRING, 0, (LPARAM)text); + SendMessage(m_hwnd, LB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlListBox::DeleteString(int index) +{ SendMessage(m_hwnd, LB_DELETESTRING, index, 0); +} + +int CCtrlListBox::FindString( TCHAR *str, int index, bool exact) +{ return SendMessage(m_hwnd, exact?LB_FINDSTRINGEXACT:LB_FINDSTRING, index, (LPARAM)str); +} + +int CCtrlListBox::GetCount() +{ return SendMessage(m_hwnd, LB_GETCOUNT, 0, 0); +} + +int CCtrlListBox::GetCurSel() +{ return SendMessage(m_hwnd, LB_GETCURSEL, 0, 0); +} + +LPARAM CCtrlListBox::GetItemData(int index) +{ return SendMessage(m_hwnd, LB_GETITEMDATA, index, 0); +} + +TCHAR* CCtrlListBox::GetItemText(int index) +{ + TCHAR *result = (TCHAR *)mir_alloc(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); + return result; +} + +TCHAR* CCtrlListBox::GetItemText(int index, TCHAR *buf, int size) +{ + TCHAR *result = (TCHAR *)_alloca(sizeof(TCHAR) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1)); + SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result); + lstrcpyn(buf, result, size); + return buf; +} + +bool CCtrlListBox::GetSel(int index) +{ return SendMessage(m_hwnd, LB_GETSEL, index, 0) ? true : false; +} + +int CCtrlListBox::GetSelCount() +{ return SendMessage(m_hwnd, LB_GETSELCOUNT, 0, 0); +} + +int* CCtrlListBox::GetSelItems(int *items, int count) +{ + SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)items); + return items; +} + +int* CCtrlListBox::GetSelItems() +{ + int count = GetSelCount() + 1; + int *result = (int *)mir_alloc(sizeof(int) * count); + SendMessage(m_hwnd, LB_GETSELITEMS, count, (LPARAM)result); + result[count-1] = -1; + return result; +} + +int CCtrlListBox::InsertString(TCHAR *text, int pos, LPARAM data) +{ + int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text); + SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data); + return iItem; +} + +void CCtrlListBox::ResetContent() +{ SendMessage(m_hwnd, LB_RESETCONTENT, 0, 0); +} + +int CCtrlListBox::SelectString(TCHAR *str) +{ return SendMessage(m_hwnd, LB_SELECTSTRING, 0, (LPARAM)str); +} + +int CCtrlListBox::SetCurSel(int index) +{ return SendMessage(m_hwnd, LB_SETCURSEL, index, 0); +} + +void CCtrlListBox::SetItemData(int index, LPARAM data) +{ SendMessage(m_hwnd, LB_SETITEMDATA, index, data); +} + +void CCtrlListBox::SetSel(int index, bool sel) +{ SendMessage(m_hwnd, LB_SETSEL, sel ? TRUE : FALSE, index); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck class + +CCtrlCheck::CCtrlCheck( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +int CCtrlCheck::GetState() +{ + return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); +} + +void CCtrlCheck::SetState(int state) +{ + SendMessage(m_hwnd, BM_SETCHECK, state, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit class + +CCtrlEdit::CCtrlEdit( CDlgBase* dlg, int ctrlId ) : + CCtrlData( dlg, ctrlId ) +{ +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData class + +CCtrlData::CCtrlData( CDlgBase *wnd, int idCtrl ) : + CCtrlBase( wnd, idCtrl ), + m_dbLink( NULL ) +{ +} + +void CCtrlData::OnInit() +{ + CCtrlBase::OnInit(); + m_changed = false; +} + +void CCtrlData::NotifyChange() +{ + if (!m_parentWnd || m_parentWnd->IsInitialized()) m_changed = true; + if ( m_parentWnd ) { + m_parentWnd->OnChange(this); + if ( m_parentWnd->IsInitialized()) + ::SendMessage( ::GetParent( m_parentWnd->GetHwnd()), PSM_CHANGED, 0, 0 ); + } + + OnChange(this); +} + +void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue ) +{ + m_dbLink = new CDbLink( szModuleName, szSetting, type, iValue); +} + +void CCtrlData::CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ) +{ + m_dbLink = new CDbLink( szModuleName, szSetting, DBVT_TCHAR, szValue ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +int CCtrlButton::GetState() +{ return SendMessage(m_hwnd, BM_GETCHECK, 0, 0); +} + +void CCtrlButton::SetState(int state) +{ SendMessage(m_hwnd, BM_SETCHECK, state, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlMButton + +CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ) : + CCtrlButton( dlg, ctrlId ), + m_hIcon( hIcon ), + m_toolTip( tooltip ) +{ +} + +CCtrlMButton::CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ) : + CCtrlButton( dlg, ctrlId ), + m_hIcon( LoadSkinnedIcon(iCoreIcon)), + m_toolTip( tooltip ) +{ +} + +CCtrlMButton::~CCtrlMButton() +{ + if ( m_hIcon ) CallService( MS_SKIN2_RELEASEICON, (WPARAM)m_hIcon, 0 ); +} + +void CCtrlMButton::OnInit() +{ + CCtrlButton::OnInit(); + + SendMessage( m_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon ); + SendMessage( m_hwnd, BUTTONADDTOOLTIP, (WPARAM)m_toolTip, 0); +} + +void CCtrlMButton::MakeFlat() +{ + SendMessage(m_hwnd, BUTTONSETASFLATBTN, TRUE, 0); +} + +void CCtrlMButton::MakePush() +{ + SendMessage(m_hwnd, BUTTONSETASPUSHBTN, TRUE, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +CCtrlButton::CCtrlButton( CDlgBase* wnd, int idCtrl ) : + CCtrlBase( wnd, idCtrl ) +{ +} + +BOOL CCtrlButton::OnCommand(HWND, WORD, WORD idCode) +{ + if ( idCode == BN_CLICKED || idCode == STN_CLICKED ) + OnClick(this); + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlHyperlink + +CCtrlHyperlink::CCtrlHyperlink( CDlgBase* wnd, int idCtrl, const char* url ) : + CCtrlBase( wnd, idCtrl ), + m_url(url) +{ +} + +BOOL CCtrlHyperlink::OnCommand(HWND, WORD, WORD) +{ + ShellExecuteA(m_hwnd, "open", m_url, "", "", SW_SHOW); + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc +CCtrlClc::CCtrlClc( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlClc::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, (NMCLISTCONTROL *)pnmh }; + switch (pnmh->code) + { + case CLN_EXPANDED: OnExpanded(&evt); break; + case CLN_LISTREBUILT: OnListRebuilt(&evt); break; + case CLN_ITEMCHECKED: OnItemChecked(&evt); break; + case CLN_DRAGGING: OnDragging(&evt); break; + case CLN_DROPPED: OnDropped(&evt); break; + case CLN_LISTSIZECHANGE: OnListSizeChange(&evt); break; + case CLN_OPTIONSCHANGED: OnOptionsChanged(&evt); break; + case CLN_DRAGSTOP: OnDragStop(&evt); break; + case CLN_NEWCONTACT: OnNewContact(&evt); break; + case CLN_CONTACTMOVED: OnContactMoved(&evt); break; + case CLN_CHECKCHANGED: OnCheckChanged(&evt); break; + case NM_CLICK: OnClick(&evt); break; + } + return FALSE; +} + +void CCtrlClc::AddContact(HANDLE hContact) +{ SendMessage(m_hwnd, CLM_ADDCONTACT, (WPARAM)hContact, 0); +} + +void CCtrlClc::AddGroup(HANDLE hGroup) +{ SendMessage(m_hwnd, CLM_ADDGROUP, (WPARAM)hGroup, 0); +} + +void CCtrlClc::AutoRebuild() +{ SendMessage(m_hwnd, CLM_AUTOREBUILD, 0, 0); +} + +void CCtrlClc::DeleteItem(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_DELETEITEM, (WPARAM)hItem, 0); +} + +void CCtrlClc::EditLabel(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_EDITLABEL, (WPARAM)hItem, 0); +} + +void CCtrlClc::EndEditLabel(bool save) +{ SendMessage(m_hwnd, CLM_ENDEDITLABELNOW, save ? 0 : 1, 0); +} + +void CCtrlClc::EnsureVisible(HANDLE hItem, bool partialOk) +{ SendMessage(m_hwnd, CLM_ENSUREVISIBLE, (WPARAM)hItem, partialOk ? TRUE : FALSE); +} + +void CCtrlClc::Expand(HANDLE hItem, DWORD flags) +{ SendMessage(m_hwnd, CLM_EXPAND, (WPARAM)hItem, flags); +} + +HANDLE CCtrlClc::FindContact(HANDLE hContact) +{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, (WPARAM)hContact, 0); +} + +HANDLE CCtrlClc::FindGroup(HANDLE hGroup) +{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, (WPARAM)hGroup, 0); +} + +COLORREF CCtrlClc::GetBkColor() +{ return (COLORREF)SendMessage(m_hwnd, CLM_GETBKCOLOR, 0, 0); +} + +bool CCtrlClc::GetCheck(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETCHECKMARK, (WPARAM)hItem, 0) ? true : false; +} + +int CCtrlClc::GetCount() +{ return SendMessage(m_hwnd, CLM_GETCOUNT, 0, 0); +} + +HWND CCtrlClc::GetEditControl() +{ return (HWND)SendMessage(m_hwnd, CLM_GETEDITCONTROL, 0, 0); +} + +DWORD CCtrlClc::GetExpand(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETEXPAND, (WPARAM)hItem, 0); +} + +int CCtrlClc::GetExtraColumns() +{ return SendMessage(m_hwnd, CLM_GETEXTRACOLUMNS, 0, 0); +} + +BYTE CCtrlClc::GetExtraImage(HANDLE hItem, int iColumn) +{ return (BYTE)(SendMessage(m_hwnd, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, 0)) & 0xFF); +} + +HIMAGELIST CCtrlClc::GetExtraImageList() +{ return (HIMAGELIST)SendMessage(m_hwnd, CLM_GETEXTRAIMAGELIST, 0, 0); +} + +HFONT CCtrlClc::GetFont(int iFontId) +{ return (HFONT)SendMessage(m_hwnd, CLM_GETFONT, (WPARAM)iFontId, 0); +} + +HANDLE CCtrlClc::GetSelection() +{ return (HANDLE)SendMessage(m_hwnd, CLM_GETSELECTION, 0, 0); +} + +HANDLE CCtrlClc::HitTest(int x, int y, DWORD *hitTest) +{ return (HANDLE)SendMessage(m_hwnd, CLM_HITTEST, (WPARAM)hitTest, MAKELPARAM(x,y)); +} + +void CCtrlClc::SelectItem(HANDLE hItem) +{ SendMessage(m_hwnd, CLM_SELECTITEM, (WPARAM)hItem, 0); +} + +void CCtrlClc::SetBkBitmap(DWORD mode, HBITMAP hBitmap) +{ SendMessage(m_hwnd, CLM_SETBKBITMAP, mode, (LPARAM)hBitmap); +} + +void CCtrlClc::SetBkColor(COLORREF clBack) +{ SendMessage(m_hwnd, CLM_SETBKCOLOR, (WPARAM)clBack, 0); +} + +void CCtrlClc::SetCheck(HANDLE hItem, bool check) +{ SendMessage(m_hwnd, CLM_SETCHECKMARK, (WPARAM)hItem, check ? 1 : 0); +} + +void CCtrlClc::SetExtraColumns(int iColumns) +{ SendMessage(m_hwnd, CLM_SETEXTRACOLUMNS, (WPARAM)iColumns, 0); +} + +void CCtrlClc::SetExtraImage(HANDLE hItem, int iColumn, int iImage) +{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); +} + +void CCtrlClc::SetExtraImageList(HIMAGELIST hImgList) +{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImgList); +} + +void CCtrlClc::SetFont(int iFontId, HANDLE hFont, bool bRedraw) +{ SendMessage(m_hwnd, CLM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw ? 1 : 0, iFontId)); +} + +void CCtrlClc::SetIndent(int iIndent) +{ SendMessage(m_hwnd, CLM_SETINDENT, (WPARAM)iIndent, 0); +} + +void CCtrlClc::SetItemText(HANDLE hItem, char *szText) +{ SendMessage(m_hwnd, CLM_SETITEMTEXT, (WPARAM)hItem, (LPARAM)szText); +} + +void CCtrlClc::SetHideEmptyGroups(bool state) +{ SendMessage(m_hwnd, CLM_SETHIDEEMPTYGROUPS, state ? 1 : 0, 0); +} + +void CCtrlClc::SetGreyoutFlags(DWORD flags) +{ SendMessage(m_hwnd, CLM_SETGREYOUTFLAGS, (WPARAM)flags, 0); +} + +bool CCtrlClc::GetHideOfflineRoot() +{ return SendMessage(m_hwnd, CLM_GETHIDEOFFLINEROOT, 0, 0) ? true : false; +} + +void CCtrlClc::SetHideOfflineRoot(bool state) +{ SendMessage(m_hwnd, CLM_SETHIDEOFFLINEROOT, state ? 1 : 0, 9); +} + +void CCtrlClc::SetUseGroups(bool state) +{ SendMessage(m_hwnd, CLM_SETUSEGROUPS, state ? 1 : 0, 0); +} + +void CCtrlClc::SetOfflineModes(DWORD modes) +{ SendMessage(m_hwnd, CLM_SETOFFLINEMODES, modes, 0); +} + +DWORD CCtrlClc::GetExStyle() +{ return SendMessage(m_hwnd, CLM_GETEXSTYLE, 0, 0); +} + +void CCtrlClc::SetExStyle(DWORD exStyle) +{ SendMessage(m_hwnd, CLM_SETEXSTYLE, (WPARAM)exStyle, 0); +} + +int CCtrlClc::GetLefrMargin() +{ return SendMessage(m_hwnd, CLM_GETLEFTMARGIN, 0, 0); +} + +void CCtrlClc::SetLeftMargin(int iMargin) +{ SendMessage(m_hwnd, CLM_SETLEFTMARGIN, (WPARAM)iMargin, 0); +} + +HANDLE CCtrlClc::AddInfoItem(CLCINFOITEM *cii) +{ return (HANDLE)SendMessage(m_hwnd, CLM_ADDINFOITEM, 0, (LPARAM)cii); +} + +int CCtrlClc::GetItemType(HANDLE hItem) +{ return SendMessage(m_hwnd, CLM_GETITEMTYPE, (WPARAM)hItem, 0); +} + +HANDLE CCtrlClc::GetNextItem(HANDLE hItem, DWORD flags) +{ return (HANDLE)SendMessage(m_hwnd, CLM_GETNEXTITEM, (WPARAM)flags, (LPARAM)hItem); +} + +COLORREF CCtrlClc::GetTextColot(int iFontId) +{ return (COLORREF)SendMessage(m_hwnd, CLM_GETTEXTCOLOR, (WPARAM)iFontId, 0); +} + +void CCtrlClc::SetTextColor(int iFontId, COLORREF clText) +{ SendMessage(m_hwnd, CLM_SETTEXTCOLOR, (WPARAM)iFontId, (LPARAM)clText); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +CCtrlListView::CCtrlListView( CDlgBase* dlg, int ctrlId ) : + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlListView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) { + case NM_DBLCLK: OnDoubleClick(&evt); return TRUE; + case LVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; + case LVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case LVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case LVN_BEGINSCROLL: OnBeginScroll(&evt); return TRUE; + case LVN_COLUMNCLICK: OnColumnClick(&evt); return TRUE; + case LVN_DELETEALLITEMS: OnDeleteAllItems(&evt); return TRUE; + case LVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case LVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case LVN_ENDSCROLL: OnEndScroll(&evt); return TRUE; + case LVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case LVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case LVN_HOTTRACK: OnHotTrack(&evt); return TRUE; + //case LVN_INCREMENTALSEARCH: OnIncrementalSearch(&evt); return TRUE; + case LVN_INSERTITEM: OnInsertItem(&evt); return TRUE; + case LVN_ITEMACTIVATE: OnItemActivate(&evt); return TRUE; + case LVN_ITEMCHANGED: OnItemChanged(&evt); return TRUE; + case LVN_ITEMCHANGING: OnItemChanging(&evt); return TRUE; + case LVN_KEYDOWN: OnKeyDown(&evt); return TRUE; + case LVN_MARQUEEBEGIN: OnMarqueeBegin(&evt); return TRUE; + case LVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + } + + return FALSE; +} +DWORD CCtrlListView::ApproximateViewRect(int cx, int cy, int iCount) +{ return ListView_ApproximateViewRect(m_hwnd, cx, cy, iCount); +} +void CCtrlListView::Arrange(UINT code) +{ ListView_Arrange(m_hwnd, code); +} +void CCtrlListView::CancelEditLabel() +{ ListView_CancelEditLabel(m_hwnd); +} +HIMAGELIST CCtrlListView::CreateDragImage(int iItem, LPPOINT lpptUpLeft) +{ return ListView_CreateDragImage(m_hwnd, iItem, lpptUpLeft); +} +void CCtrlListView::DeleteAllItems() +{ ListView_DeleteAllItems(m_hwnd); +} +void CCtrlListView::DeleteColumn(int iCol) +{ ListView_DeleteColumn(m_hwnd, iCol); +} +void CCtrlListView::DeleteItem(int iItem) +{ ListView_DeleteItem(m_hwnd, iItem); +} +HWND CCtrlListView::EditLabel(int iItem) +{ return ListView_EditLabel(m_hwnd, iItem); +} +int CCtrlListView::EnableGroupView(BOOL fEnable) +{ return ListView_EnableGroupView(m_hwnd, fEnable); +} +BOOL CCtrlListView::EnsureVisible(int i, BOOL fPartialOK) +{ return ListView_EnsureVisible(m_hwnd, i, fPartialOK); +} +int CCtrlListView::FindItem(int iStart, const LVFINDINFO *plvfi) +{ return ListView_FindItem(m_hwnd, iStart, plvfi); +} +COLORREF CCtrlListView::GetBkColor() +{ return ListView_GetBkColor(m_hwnd); +} +void CCtrlListView::GetBkImage(LPLVBKIMAGE plvbki) +{ ListView_GetBkImage(m_hwnd, plvbki); +} +UINT CCtrlListView::GetCallbackMask() +{ return ListView_GetCallbackMask(m_hwnd); +} +BOOL CCtrlListView::GetCheckState(UINT iIndex) +{ return ListView_GetCheckState(m_hwnd, iIndex); +} +void CCtrlListView::GetColumn(int iCol, LPLVCOLUMN pcol) +{ ListView_GetColumn(m_hwnd, iCol, pcol); +} +void CCtrlListView::GetColumnOrderArray(int iCount, int *lpiArray) +{ ListView_GetColumnOrderArray(m_hwnd, iCount, lpiArray); +} +int CCtrlListView::GetColumnWidth(int iCol) +{ return ListView_GetColumnWidth(m_hwnd, iCol); +} +int CCtrlListView::GetCountPerPage() +{ return ListView_GetCountPerPage(m_hwnd); +} +HWND CCtrlListView::GetEditControl() +{ return ListView_GetEditControl(m_hwnd); +} +//void CCtrlListView::GetEmptyText(PWSTR pszText, UINT cchText) +//{ ListView_GetEmptyText(m_hwnd, pszText, cchText); +//} +DWORD CCtrlListView::GetExtendedListViewStyle() +{ return ListView_GetExtendedListViewStyle(m_hwnd); +} +//INT CCtrlListView::GetFocusedGroup() +//{ return ListView_GetFocusedGroup(m_hwnd); +//} +//void CCtrlListView::GetFooterInfo(LPLVFOOTERINFO plvfi) +//{ ListView_GetFooterInfo(m_hwnd, plvfi); +//} +//void CCtrlListView::GetFooterItem(UINT iItem, LVFOOTERITEM *pfi) +//{ ListView_GetFooterItem(m_hwnd, iItem, pfi); +//} +//void CCtrlListView::GetFooterItemRect(UINT iItem, RECT *prc) +//{ ListView_GetFooterItemRect(m_hwnd, iItem, prc); +//} +//void CCtrlListView::GetFooterRect(RECT *prc) +//{ ListView_GetFooterRect(m_hwnd, prc); +//} +//int CCtrlListView::GetGroupCount() +//{ return ListView_GetGroupCount(m_hwnd); +//} +//HIMAGELIST CCtrlListView::GetGroupHeaderImageList() +//{ return ListView_GetGroupHeaderImageList(m_hwnd); +//} +//void CCtrlListView::GetGroupInfo(int iGroupId, PLVGROUP pgrp) +//{ ListView_GetGroupInfo(m_hwnd, iGroupId, pgrp); +//} +//void CCtrlListView::GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp) +//{ ListView_GetGroupInfoByIndex(m_hwnd, iIndex, pgrp); +//} +void CCtrlListView::GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) +{ ListView_GetGroupMetrics(m_hwnd, pGroupMetrics); +} +//BOOL CCtrlListView::GetGroupRect(int iGroupId, RECT *prc) +//{ return ListView_GetGroupRect(m_hwnd, iGroupId, prc); +//} +//UINT CCtrlListView::GetGroupState(UINT dwGroupId, UINT dwMask) +//{ return ListView_GetGroupState(m_hwnd, dwGroupId, dwMask); +//} +HWND CCtrlListView::GetHeader() +{ return ListView_GetHeader(m_hwnd); +} +HCURSOR CCtrlListView::GetHotCursor() +{ return ListView_GetHotCursor(m_hwnd); +} +INT CCtrlListView::GetHotItem() +{ return ListView_GetHotItem(m_hwnd); +} +DWORD CCtrlListView::GetHoverTime() +{ return ListView_GetHoverTime(m_hwnd); +} +HIMAGELIST CCtrlListView::GetImageList(int iImageList) +{ return ListView_GetImageList(m_hwnd, iImageList); +} +BOOL CCtrlListView::GetInsertMark(LVINSERTMARK *plvim) +{ return ListView_GetInsertMark(m_hwnd, plvim); +} +COLORREF CCtrlListView::GetInsertMarkColor() +{ return ListView_GetInsertMarkColor(m_hwnd); +} +int CCtrlListView::GetInsertMarkRect(LPRECT prc) +{ return ListView_GetInsertMarkRect(m_hwnd, prc); +} +BOOL CCtrlListView::GetISearchString(LPSTR lpsz) +{ return ListView_GetISearchString(m_hwnd, lpsz); +} +void CCtrlListView::GetItem(LPLVITEM pitem) +{ ListView_GetItem(m_hwnd, pitem); +} +int CCtrlListView::GetItemCount() +{ return ListView_GetItemCount(m_hwnd); +} +//void CCtrlListView::GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc) +//{ ListView_GetItemIndexRect(m_hwnd, plvii, iSubItem, code, prc); +//} +void CCtrlListView::GetItemPosition(int i, POINT *ppt) +{ ListView_GetItemPosition(m_hwnd, i, ppt); +} +void CCtrlListView::GetItemRect(int i, RECT *prc, int code) +{ ListView_GetItemRect(m_hwnd, i, prc, code); +} +DWORD CCtrlListView::GetItemSpacing(BOOL fSmall) +{ return ListView_GetItemSpacing(m_hwnd, fSmall); +} +UINT CCtrlListView::GetItemState(int i, UINT mask) +{ return ListView_GetItemState(m_hwnd, i, mask); +} +void CCtrlListView::GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) +{ ListView_GetItemText(m_hwnd, iItem, iSubItem, pszText, cchTextMax); +} +int CCtrlListView::GetNextItem(int iStart, UINT flags) +{ return ListView_GetNextItem(m_hwnd, iStart, flags); +} +//BOOL CCtrlListView::GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags) +//{ return ListView_GetNextItemIndex(m_hwnd, plvii, flags); +//} +BOOL CCtrlListView::GetNumberOfWorkAreas(LPUINT lpuWorkAreas) +{ return ListView_GetNumberOfWorkAreas(m_hwnd, lpuWorkAreas); +} +BOOL CCtrlListView::GetOrigin(LPPOINT lpptOrg) +{ return ListView_GetOrigin(m_hwnd, lpptOrg); +} +COLORREF CCtrlListView::GetOutlineColor() +{ return ListView_GetOutlineColor(m_hwnd); +} +UINT CCtrlListView::GetSelectedColumn() +{ return ListView_GetSelectedColumn(m_hwnd); +} +UINT CCtrlListView::GetSelectedCount() +{ return ListView_GetSelectedCount(m_hwnd); +} +INT CCtrlListView::GetSelectionMark() +{ return ListView_GetSelectionMark(m_hwnd); +} +int CCtrlListView::GetStringWidth(LPCSTR psz) +{ return ListView_GetStringWidth(m_hwnd, psz); +} +BOOL CCtrlListView::GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) +{ return ListView_GetSubItemRect(m_hwnd, iItem, iSubItem, code, lpRect); +} +COLORREF CCtrlListView::GetTextBkColor() +{ return ListView_GetTextBkColor(m_hwnd); +} +COLORREF CCtrlListView::GetTextColor() +{ return ListView_GetTextColor(m_hwnd); +} +void CCtrlListView::GetTileInfo(PLVTILEINFO plvtinfo) +{ ListView_GetTileInfo(m_hwnd, plvtinfo); +} +void CCtrlListView::GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) +{ ListView_GetTileViewInfo(m_hwnd, plvtvinfo); +} +HWND CCtrlListView::GetToolTips() +{ return ListView_GetToolTips(m_hwnd); +} +int CCtrlListView::GetTopIndex() +{ return ListView_GetTopIndex(m_hwnd); +} +BOOL CCtrlListView::GetUnicodeFormat() +{ return ListView_GetUnicodeFormat(m_hwnd); +} +DWORD CCtrlListView::GetView() +{ return ListView_GetView(m_hwnd); +} +BOOL CCtrlListView::GetViewRect(RECT *prc) +{ return ListView_GetViewRect(m_hwnd, prc); +} +void CCtrlListView::GetWorkAreas(INT nWorkAreas, LPRECT lprc) +{ ListView_GetWorkAreas(m_hwnd, nWorkAreas, lprc); +} +BOOL CCtrlListView::HasGroup(int dwGroupId) +{ return ListView_HasGroup(m_hwnd, dwGroupId); +} +int CCtrlListView::HitTest(LPLVHITTESTINFO pinfo) +{ return ListView_HitTest(m_hwnd, pinfo); +} +//int CCtrlListView::HitTestEx(LPLVHITTESTINFO pinfo) +//{ return ListView_HitTestEx(m_hwnd, pinfo); +//} +int CCtrlListView::InsertColumn(int iCol, const LPLVCOLUMN pcol) +{ return ListView_InsertColumn(m_hwnd, iCol, pcol); +} +int CCtrlListView::InsertGroup(int index, PLVGROUP pgrp) +{ return ListView_InsertGroup(m_hwnd, index, pgrp); +} +void CCtrlListView::InsertGroupSorted(PLVINSERTGROUPSORTED structInsert) +{ ListView_InsertGroupSorted(m_hwnd, structInsert); +} +int CCtrlListView::InsertItem(const LPLVITEM pitem) +{ return ListView_InsertItem(m_hwnd, pitem); +} +BOOL CCtrlListView::InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim) +{ return ListView_InsertMarkHitTest(m_hwnd, point, plvim); +} +BOOL CCtrlListView::IsGroupViewEnabled() +{ return ListView_IsGroupViewEnabled(m_hwnd); +} +//UINT CCtrlListView::IsItemVisible(UINT index) +//{ return ListView_IsItemVisible(m_hwnd, index); +//} +UINT CCtrlListView::MapIDToIndex(UINT id) +{ return ListView_MapIDToIndex(m_hwnd, id); +} +UINT CCtrlListView::MapIndexToID(UINT index) +{ return ListView_MapIndexToID(m_hwnd, index); +} +BOOL CCtrlListView::RedrawItems(int iFirst, int iLast) +{ return ListView_RedrawItems(m_hwnd, iFirst, iLast); +} +void CCtrlListView::RemoveAllGroups() +{ ListView_RemoveAllGroups(m_hwnd); +} +int CCtrlListView::RemoveGroup(int iGroupId) +{ return ListView_RemoveGroup(m_hwnd, iGroupId); +} +BOOL CCtrlListView::Scroll(int dx, int dy) +{ return ListView_Scroll(m_hwnd, dx, dy); +} +BOOL CCtrlListView::SetBkColor(COLORREF clrBk) +{ return ListView_SetBkColor(m_hwnd, clrBk); +} +BOOL CCtrlListView::SetBkImage(LPLVBKIMAGE plvbki) +{ return ListView_SetBkImage(m_hwnd, plvbki); +} +BOOL CCtrlListView::SetCallbackMask(UINT mask) +{ return ListView_SetCallbackMask(m_hwnd, mask); +} +void CCtrlListView::SetCheckState(UINT iIndex, BOOL fCheck) +{ ListView_SetCheckState(m_hwnd, iIndex, fCheck); +} +BOOL CCtrlListView::SetColumn(int iCol, LPLVCOLUMN pcol) +{ return ListView_SetColumn(m_hwnd, iCol, pcol); +} +BOOL CCtrlListView::SetColumnOrderArray(int iCount, int *lpiArray) +{ return ListView_SetColumnOrderArray(m_hwnd, iCount, lpiArray); +} +BOOL CCtrlListView::SetColumnWidth(int iCol, int cx) +{ return ListView_SetColumnWidth(m_hwnd, iCol, cx); +} +void CCtrlListView::SetExtendedListViewStyle(DWORD dwExStyle) +{ ListView_SetExtendedListViewStyle(m_hwnd, dwExStyle); +} +void CCtrlListView::SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle) +{ ListView_SetExtendedListViewStyleEx(m_hwnd, dwExMask, dwExStyle); +} +//HIMAGELIST CCtrlListView::SetGroupHeaderImageList(HIMAGELIST himl) +//{ return ListView_SetGroupHeaderImageList(m_hwnd, himl); +//} +int CCtrlListView::SetGroupInfo(int iGroupId, PLVGROUP pgrp) +{ return ListView_SetGroupInfo(m_hwnd, iGroupId, pgrp); +} +void CCtrlListView::SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) +{ ListView_SetGroupMetrics(m_hwnd, pGroupMetrics); +} +//void CCtrlListView::SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState) +//{ ListView_SetGroupState(m_hwnd, dwGroupId, dwMask, dwState); +//} +HCURSOR CCtrlListView::SetHotCursor(HCURSOR hCursor) +{ return ListView_SetHotCursor(m_hwnd, hCursor); +} +INT CCtrlListView::SetHotItem(INT iIndex) +{ return ListView_SetHotItem(m_hwnd, iIndex); +} +void CCtrlListView::SetHoverTime(DWORD dwHoverTime) +{ ListView_SetHoverTime(m_hwnd, dwHoverTime); +} +DWORD CCtrlListView::SetIconSpacing(int cx, int cy) +{ return ListView_SetIconSpacing(m_hwnd, cx, cy); +} +HIMAGELIST CCtrlListView::SetImageList(HIMAGELIST himl, int iImageList) +{ return ListView_SetImageList(m_hwnd, himl, iImageList); +} +BOOL CCtrlListView::SetInfoTip(PLVSETINFOTIP plvSetInfoTip) +{ return ListView_SetInfoTip(m_hwnd, plvSetInfoTip); +} +BOOL CCtrlListView::SetInsertMark(LVINSERTMARK *plvim) +{ return ListView_SetInsertMark(m_hwnd, plvim); +} +COLORREF CCtrlListView::SetInsertMarkColor(COLORREF color) +{ return ListView_SetInsertMarkColor(m_hwnd, color); +} +BOOL CCtrlListView::SetItem(const LPLVITEM pitem) +{ return ListView_SetItem(m_hwnd, pitem); +} +void CCtrlListView::SetItemCount(int cItems) +{ ListView_SetItemCount(m_hwnd, cItems); +} +void CCtrlListView::SetItemCountEx(int cItems, DWORD dwFlags) +{ ListView_SetItemCountEx(m_hwnd, cItems, dwFlags); +} +//HRESULT CCtrlListView::SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask) +//{ return ListView_SetItemIndexState(m_hwnd, plvii, data, mask); +//} +BOOL CCtrlListView::SetItemPosition(int i, int x, int y) +{ return ListView_SetItemPosition(m_hwnd, i, x, y); +} +void CCtrlListView::SetItemPosition32(int iItem, int x, int y) +{ ListView_SetItemPosition32(m_hwnd, iItem, x, y); +} +void CCtrlListView::SetItemState(int i, UINT state, UINT mask) +{ ListView_SetItemState(m_hwnd, i, state, mask); +} +void CCtrlListView::SetItemText(int i, int iSubItem, TCHAR *pszText) +{ ListView_SetItemText(m_hwnd, i, iSubItem, pszText); +} +COLORREF CCtrlListView::SetOutlineColor(COLORREF color) +{ return ListView_SetOutlineColor(m_hwnd, color); +} +void CCtrlListView::SetSelectedColumn(int iCol) +{ ListView_SetSelectedColumn(m_hwnd, iCol); +} +INT CCtrlListView::SetSelectionMark(INT iIndex) +{ return ListView_SetSelectionMark(m_hwnd, iIndex); +} +BOOL CCtrlListView::SetTextBkColor(COLORREF clrText) +{ return ListView_SetTextBkColor(m_hwnd, clrText); +} +BOOL CCtrlListView::SetTextColor(COLORREF clrText) +{ return ListView_SetTextColor(m_hwnd, clrText); +} +BOOL CCtrlListView::SetTileInfo(PLVTILEINFO plvtinfo) +{ return ListView_SetTileInfo(m_hwnd, plvtinfo); +} +BOOL CCtrlListView::SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) +{ return ListView_SetTileViewInfo(m_hwnd, plvtvinfo); +} +HWND CCtrlListView::SetToolTips(HWND ToolTip) +{ return ListView_SetToolTips(m_hwnd, ToolTip); +} +BOOL CCtrlListView::SetUnicodeFormat(BOOL fUnicode) +{ return ListView_SetUnicodeFormat(m_hwnd, fUnicode); +} +int CCtrlListView::SetView(DWORD iView) +{ return ListView_SetView(m_hwnd, iView); +} +void CCtrlListView::SetWorkAreas(INT nWorkAreas, LPRECT lprc) +{ ListView_SetWorkAreas(m_hwnd, nWorkAreas, lprc); +} +int CCtrlListView::SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv) +{ return ListView_SortGroups(m_hwnd, pfnGroupCompare, plv); +} +BOOL CCtrlListView::SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ return ListView_SortItems(m_hwnd, pfnCompare, lParamSort); +} +BOOL CCtrlListView::SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ return ListView_SortItemsEx(m_hwnd, pfnCompare, lParamSort); +} +INT CCtrlListView::SubItemHitTest(LPLVHITTESTINFO pInfo) +{ return ListView_SubItemHitTest(m_hwnd, pInfo); +} +//INT CCtrlListView::SubItemHitTestEx(LPLVHITTESTINFO plvhti) +//{ return ListView_SubItemHitTestEx(m_hwnd, plvhti); +//} +BOOL CCtrlListView::Update(int iItem) +{ return ListView_Update(m_hwnd, iItem); +} +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +CCtrlTreeView::CCtrlTreeView( CDlgBase* dlg, int ctrlId ): + CCtrlBase(dlg, ctrlId) +{ +} + +BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) + { + case TVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE; + case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; + case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; + case TVN_KEYDOWN: OnKeyDown(&evt); return TRUE; + case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; + case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; + case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; + } + + return FALSE; +} + +void CCtrlTreeView::TranslateItem(HTREEITEM hItem) +{ + TCHAR buf[128]; + TVITEMEX tvi; + + GetItem(hItem, &tvi, buf, SIZEOF(buf)); + tvi.pszText = TranslateTS(tvi.pszText); + tvi.cchTextMax = lstrlen(tvi.pszText); + SetItem(&tvi); +} + +void CCtrlTreeView::TranslateTree() +{ + HTREEITEM hItem = GetRoot(); + while (hItem) + { + TranslateItem(hItem); + + HTREEITEM hItemTmp = 0; + if (hItemTmp = GetChild(hItem)) + hItem = hItemTmp; + else if (hItemTmp = GetNextSibling(hItem)) + hItem = hItemTmp; + else + { + for (;;) + { + if (!(hItem = GetParent(hItem))) break; + if (hItemTmp = GetNextSibling(hItem)) + { + hItem = hItemTmp; + break; + } + } + } + } +} + +HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const TCHAR *name) +{ + TVITEMEX tvi = {0}; + TCHAR str[MAX_PATH]; + + if (hItem) + tvi.hItem = GetChild(hItem); + else + tvi.hItem = GetRoot(); + + if (!name) + return tvi.hItem; + + tvi.mask = TVIF_TEXT; + tvi.pszText = str; + tvi.cchTextMax = SIZEOF(str); + + while (tvi.hItem) + { + GetItem(&tvi); + + if (!lstrcmp(tvi.pszText, name)) + return tvi.hItem; + + tvi.hItem = GetNextSibling(tvi.hItem); + } + return NULL; +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) +{ + ZeroMemory(tvi, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE; + tvi->hItem = hItem; + GetItem(tvi); +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength) +{ + ZeroMemory(tvi, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_INTEGRAL|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT; + tvi->hItem = hItem; + tvi->pszText = szText; + tvi->cchTextMax = iTextLength; + GetItem(tvi); +} + +HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) +{ return TreeView_CreateDragImage(m_hwnd, hItem); +} + +void CCtrlTreeView::DeleteAllItems() +{ TreeView_DeleteAllItems(m_hwnd); +} + +void CCtrlTreeView::DeleteItem(HTREEITEM hItem) +{ TreeView_DeleteItem(m_hwnd, hItem); +} + +HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) +{ return TreeView_EditLabel(m_hwnd, hItem); +} + +void CCtrlTreeView::EndEditLabelNow(BOOL cancel) +{ TreeView_EndEditLabelNow(m_hwnd, cancel); +} + +void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) +{ TreeView_EnsureVisible(m_hwnd, hItem); +} + +void CCtrlTreeView::Expand(HTREEITEM hItem, DWORD flag) +{ TreeView_Expand(m_hwnd, hItem, flag); +} + +COLORREF CCtrlTreeView::GetBkColor() +{ return TreeView_GetBkColor(m_hwnd); +} + +DWORD CCtrlTreeView::GetCheckState(HTREEITEM hItem) +{ return TreeView_GetCheckState(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) +{ return TreeView_GetChild(m_hwnd, hItem); +} + +int CCtrlTreeView::GetCount() +{ return TreeView_GetCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetDropHilight() +{ return TreeView_GetDropHilight(m_hwnd); +} + +HWND CCtrlTreeView::GetEditControl() +{ return TreeView_GetEditControl(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetFirstVisible() +{ return TreeView_GetFirstVisible(m_hwnd); +} + +HIMAGELIST CCtrlTreeView::GetImageList(int iImage) +{ return TreeView_GetImageList(m_hwnd, iImage); +} + +int CCtrlTreeView::GetIndent() +{ return TreeView_GetIndent(m_hwnd); +} + +COLORREF CCtrlTreeView::GetInsertMarkColor() +{ return TreeView_GetInsertMarkColor(m_hwnd); +} + +void CCtrlTreeView::GetItem(TVITEMEX *tvi) +{ TreeView_GetItem(m_hwnd, tvi); +} + +int CCtrlTreeView::GetItemHeight() +{ return TreeView_GetItemHeight(m_hwnd); +} + +void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) +{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); +} + +DWORD CCtrlTreeView::GetItemState(HTREEITEM hItem, DWORD stateMask) +{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); +} + +HTREEITEM CCtrlTreeView::GetLastVisible() +{ return TreeView_GetLastVisible(m_hwnd); +} + +COLORREF CCtrlTreeView::GetLineColor() +{ return TreeView_GetLineColor(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, DWORD flag) +{ return TreeView_GetNextItem(m_hwnd, hItem, flag); +} + +HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) +{ return TreeView_GetNextSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) +{ return TreeView_GetNextVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) +{ return TreeView_GetParent(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) +{ return TreeView_GetPrevSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) +{ return TreeView_GetPrevVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetRoot() +{ return TreeView_GetRoot(m_hwnd); +} + +DWORD CCtrlTreeView::GetScrollTime() +{ return TreeView_GetScrollTime(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetSelection() +{ return TreeView_GetSelection(m_hwnd); +} + +COLORREF CCtrlTreeView::GetTextColor() +{ return TreeView_GetTextColor(m_hwnd); +} + +HWND CCtrlTreeView::GetToolTips() +{ return TreeView_GetToolTips(m_hwnd); +} + +BOOL CCtrlTreeView::GetUnicodeFormat() +{ return TreeView_GetUnicodeFormat(m_hwnd); +} + +unsigned CCtrlTreeView::GetVisibleCount() +{ return TreeView_GetVisibleCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) +{ return TreeView_HitTest(m_hwnd, hti); +} + +HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) +{ return TreeView_InsertItem(m_hwnd, tvis); +} + +/* +HTREEITEM CCtrlTreeView::MapAccIDToHTREEITEM(UINT id) +{ return TreeView_MapAccIDToHTREEITEM(m_hwnd, id); +} + +UINT CCtrlTreeView::MapHTREEITEMtoAccID(HTREEITEM hItem) +{ return TreeView_MapHTREEITEMtoAccID(m_hwnd, hItem); +} + +*/ +void CCtrlTreeView::Select(HTREEITEM hItem, DWORD flag) +{ TreeView_Select(m_hwnd, hItem, flag); +} + +void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) +{ TreeView_SelectDropTarget(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectItem(HTREEITEM hItem) +{ TreeView_SelectItem(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) +{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); +} + +COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) +{ return TreeView_SetBkColor(m_hwnd, clBack); +} + +void CCtrlTreeView::SetCheckState(HTREEITEM hItem, DWORD state) +{ TreeView_SetCheckState(m_hwnd, hItem, state); +} + +void CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) +{ TreeView_SetImageList(m_hwnd, hIml, iImage); +} + +void CCtrlTreeView::SetIndent(int iIndent) +{ TreeView_SetIndent(m_hwnd, iIndent); +} + +void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) +{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); +} + +COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) +{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); +} + +void CCtrlTreeView::SetItem(TVITEMEX *tvi) +{ TreeView_SetItem(m_hwnd, tvi); +} + +void CCtrlTreeView::SetItemHeight(short cyItem) +{ TreeView_SetItemHeight(m_hwnd, cyItem); +} + +void CCtrlTreeView::SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask) +{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); +} + +COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) +{ return TreeView_SetLineColor(m_hwnd, clLine); +} + +void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) +{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); +} + +COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) +{ return TreeView_SetTextColor(m_hwnd, clText); +} + +HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) +{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); +} + +BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) +{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); +} + +void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) +{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); +} + +void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) +{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +CCtrlBase::CCtrlBase(CDlgBase *wnd, int idCtrl) : + m_parentWnd( wnd ), + m_idCtrl( idCtrl ), + m_hwnd( NULL ), + m_wndproc( NULL ) +{ + if ( wnd ) { + m_next = wnd->m_first; + wnd->m_first = this; +} } + +void CCtrlBase::OnInit() +{ + m_hwnd = (m_idCtrl && m_parentWnd && m_parentWnd->GetHwnd()) ? GetDlgItem(m_parentWnd->GetHwnd(), m_idCtrl) : NULL; +} + +void CCtrlBase::OnDestroy() +{ + Unsubclass(); + m_hwnd = NULL; +} + +void CCtrlBase::Enable( int bIsEnable ) +{ + ::EnableWindow( m_hwnd, bIsEnable ); +} + +BOOL CCtrlBase::Enabled() const +{ + return ( m_hwnd ) ? IsWindowEnabled( m_hwnd ) : FALSE; +} + +LRESULT CCtrlBase::SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ) +{ + return ::SendMessage( m_hwnd, Msg, wParam, lParam ); +} + +void CCtrlBase::SetText(const TCHAR *text) +{ + ::SetWindowText( m_hwnd, text ); +} + +void CCtrlBase::SetTextA(const char *text) +{ + ::SetWindowTextA( m_hwnd, text ); +} + +void CCtrlBase::SetInt(int value) +{ + TCHAR buf[32] = {0}; + mir_sntprintf(buf, SIZEOF(buf), _T("%d"), value); + SetWindowText(m_hwnd, buf); +} + +TCHAR* CCtrlBase::GetText() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + TCHAR *result = (TCHAR *)mir_alloc(length * sizeof(TCHAR)); + GetWindowText(m_hwnd, result, length); + return result; +} + +char* CCtrlBase::GetTextA() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + char *result = (char *)mir_alloc(length * sizeof(char)); + GetWindowTextA(m_hwnd, result, length); + return result; +} + +TCHAR* CCtrlBase::GetText(TCHAR *buf, int size) +{ + GetWindowText(m_hwnd, buf, size); + buf[size-1] = 0; + return buf; +} + +char* CCtrlBase::GetTextA(char *buf, int size) +{ + GetWindowTextA(m_hwnd, buf, size); + buf[size-1] = 0; + return buf; +} + +int CCtrlBase::GetInt() +{ + int length = GetWindowTextLength(m_hwnd) + 1; + TCHAR *result = (TCHAR *)_alloca(length * sizeof(TCHAR)); + GetWindowText(m_hwnd, result, length); + return _ttoi(result); +} + +LRESULT CCtrlBase::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_DESTROY) Unsubclass(); + return CallWindowProc(m_wndproc, m_hwnd, msg, wParam, lParam); +} + +void CCtrlBase::Subclass() +{ + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + m_wndproc = (WNDPROC)SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)GlobalSubclassWndProc); +} + +void CCtrlBase::Unsubclass() +{ + if (m_wndproc) + { + SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + m_wndproc = 0; +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink class + +CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue) +{ + m_szModule = mir_strdup(szModule); + m_szSetting = mir_strdup(szSetting); + m_type = type; + m_iDefault = iValue; + m_szDefault = 0; + dbv.type = DBVT_DELETED; +} + +CDbLink::CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue) +{ + m_szModule = mir_strdup(szModule); + m_szSetting = mir_strdup(szSetting); + m_type = type; + m_szDefault = mir_tstrdup(szValue); + dbv.type = DBVT_DELETED; +} + +CDbLink::~CDbLink() +{ + mir_free(m_szModule); + mir_free(m_szSetting); + mir_free(m_szDefault); + if (dbv.type != DBVT_DELETED) + DBFreeVariant(&dbv); +} + +DWORD CDbLink::LoadInt() +{ + switch (m_type) { + case DBVT_BYTE: return DBGetContactSettingByte(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_WORD: return DBGetContactSettingWord(NULL, m_szModule, m_szSetting, m_iDefault); + case DBVT_DWORD: return DBGetContactSettingDword(NULL, m_szModule, m_szSetting, m_iDefault); + default: return m_iDefault; + } +} + +void CDbLink::SaveInt(DWORD value) +{ + switch (m_type) { + case DBVT_BYTE: DBWriteContactSettingByte(NULL, m_szModule, m_szSetting, (BYTE)value); break; + case DBVT_WORD: DBWriteContactSettingWord(NULL, m_szModule, m_szSetting, (WORD)value); break; + case DBVT_DWORD: DBWriteContactSettingDword(NULL, m_szModule, m_szSetting, value); break; + } +} + +TCHAR* CDbLink::LoadText() +{ + if (dbv.type != DBVT_DELETED) DBFreeVariant(&dbv); + if (!DBGetContactSettingTString(NULL, m_szModule, m_szSetting, &dbv)) + { + if (dbv.type == DBVT_TCHAR) + return dbv.ptszVal; + return m_szDefault; + } + + dbv.type = DBVT_DELETED; + return m_szDefault; +} + +void CDbLink::SaveText(TCHAR *value) +{ + DBWriteContactSettingTString(NULL, m_szModule, m_szSetting, value); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Misc utilities + +int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) +{ + if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton))) + PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton)); + return 0; +} + +void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow) +{ + for (; *idList; ++idList) + ShowWindow(GetDlgItem(hwndDlg, *idList), nCmdShow); +} diff --git a/protocols/IRCG/src/ui_utils.h b/protocols/IRCG/src/ui_utils.h new file mode 100644 index 0000000000..60566ce913 --- /dev/null +++ b/protocols/IRCG/src/ui_utils.h @@ -0,0 +1,1108 @@ +/* + +Jabber Protocol Plugin for Miranda IM +Copyright ( C ) 2002-04 Santithorn Bunchua +Copyright ( C ) 2005-08 George Hazan +Copyright ( C ) 2007-08 Maxim Mluhov +Copyright ( C ) 2007-08 Victor Pavlychko + +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. + +File name : $URL: http://miranda.googlecode.com/svn/trunk/miranda/protocols/IRCG/ui_utils.h $ +Revision : $Revision: 13133 $ +Last change on : $Date: 2010-11-17 15:54:24 +0200 (Ср, 17 Ð½Ð¾Ñ 2010) $ +Last change by : $Author: george.hazan $ + +*/ + +#ifndef __jabber_ui_utils_h__ +#define __jabber_ui_utils_h__ + +#include "m_clc.h" + +#ifndef LPLVCOLUMN +typedef struct tagNMLVSCROLL +{ + NMHDR hdr; + int dx; + int dy; +} NMLVSCROLL; +typedef struct tagLVG +{ + UINT cbSize; + UINT mask; + LPWSTR pszHeader; + int cchHeader; + LPWSTR pszFooter; + int cchFooter; + int iGroupId; + UINT stateMask; + UINT state; + UINT uAlign; +} LVGROUP, *PLVGROUP; +typedef struct tagLVGROUPMETRICS +{ + UINT cbSize; + UINT mask; + UINT Left; + UINT Top; + UINT Right; + UINT Bottom; + COLORREF crLeft; + COLORREF crTop; + COLORREF crRight; + COLORREF crBottom; + COLORREF crHeader; + COLORREF crFooter; +} LVGROUPMETRICS, *PLVGROUPMETRICS; +typedef struct tagLVTILEVIEWINFO +{ + UINT cbSize; + DWORD dwMask; + DWORD dwFlags; + SIZE sizeTile; + int cLines; + RECT rcLabelMargin; +} LVTILEVIEWINFO, *PLVTILEVIEWINFO; +typedef struct tagLVTILEINFO +{ + UINT cbSize; + int iItem; + UINT cColumns; + PUINT puColumns; +} LVTILEINFO, *PLVTILEINFO; +typedef struct +{ + UINT cbSize; + DWORD dwFlags; + int iItem; + DWORD dwReserved; +} LVINSERTMARK, * LPLVINSERTMARK; +typedef int (CALLBACK *PFNLVGROUPCOMPARE)(int, int, void *); +typedef struct tagLVINSERTGROUPSORTED +{ + PFNLVGROUPCOMPARE pfnGroupCompare; + void *pvData; + LVGROUP lvGroup; +} LVINSERTGROUPSORTED, *PLVINSERTGROUPSORTED; +typedef struct tagLVSETINFOTIP +{ + UINT cbSize; + DWORD dwFlags; + LPWSTR pszText; + int iItem; + int iSubItem; +} LVSETINFOTIP, *PLVSETINFOTIP; +#define LPLVCOLUMN LPLVCOLUMNA +#define LPLVITEM LPLVITEMA +#define LVN_BEGINSCROLL (LVN_FIRST-80) +#define LVN_ENDSCROLL (LVN_FIRST-81) +#define LVN_HOTTRACK (LVN_FIRST-21) +#define LVN_MARQUEEBEGIN (LVN_FIRST-56) +#define LVM_MAPINDEXTOID (LVM_FIRST + 180) +#define ListView_MapIndexToID(hwnd, index) \ + (UINT)SendMessage((hwnd), LVM_MAPINDEXTOID, (WPARAM)index, (LPARAM)0) +#define TreeView_GetLineColor(hwnd) \ + (COLORREF)SendMessage((hwnd), TVM_GETLINECOLOR, 0, 0) +#define TreeView_SetLineColor(hwnd, clr) \ + (COLORREF)SendMessage((hwnd), TVM_SETLINECOLOR, 0, (LPARAM)(clr)) +#endif + + +#pragma warning(disable:4355) + +///////////////////////////////////////////////////////////////////////////////////////// +// Callbacks + +struct CCallbackImp +{ + struct CDummy + { int foo; + }; + +public: + __inline CCallbackImp(): m_object(NULL), m_func(NULL) {} + + __inline CCallbackImp(const CCallbackImp &other): m_object(other.m_object), m_func(other.m_func) {} + __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } + + __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } + __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } + + __inline operator bool() const { return m_object && m_func; } + + __inline bool CheckObject(void *object) const { return (object == m_object) ? true : false; } + +protected: + template + __inline CCallbackImp(TClass *object, void ( TClass::*func)(TArgument *argument)): m_object(( CDummy* )object), m_func((TFnCallback)func) {} + + __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } + +private: + typedef void ( CDummy::*TFnCallback)( void *argument ); + + CDummy* m_object; + TFnCallback m_func; +}; + +template +struct CCallback: public CCallbackImp +{ +public: + __inline CCallback() {} + + template + __inline CCallback(TClass *object, void ( TClass::*func)(TArgument *argument)): CCallbackImp(object, func) {} + + __inline CCallback& operator=( const CCallbackImp& x ) { CCallbackImp::operator =( x ); return *this; } + + __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } +}; + +template +__inline CCallback Callback(TClass *object, void (TClass::*func)(TArgument *argument)) + { return CCallback(object, func); } + +///////////////////////////////////////////////////////////////////////////////////////// +// CDlgBase - base dialog class + +class CDlgBase +{ + friend class CCtrlBase; + friend class CCtrlData; + +public: + CDlgBase(int idDialog, HWND hwndParent); + virtual ~CDlgBase(); + + // general utilities + void Create(); + void Show(); + int DoModal(); + + __inline HWND GetHwnd() const { return m_hwnd; } + __inline bool IsInitialized() const { return m_initialized; } + __inline void Close() { SendMessage(m_hwnd, WM_CLOSE, 0, 0); } + __inline const MSG *ActiveMessage() const { return &m_msg; } + + // dynamic creation support (mainly to avoid leaks in options) + struct CreateParam + { + CDlgBase *(*create)(void *param); + void *param; + }; + static INT_PTR CALLBACK DynamicDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + if (msg == WM_INITDIALOG) + { + CreateParam *param = (CreateParam *)lParam; + CDlgBase *wnd = param->create(param->param); + SetWindowLongPtr(hwnd, DWLP_DLGPROC, (LONG_PTR)GlobalDlgProc); + return GlobalDlgProc(hwnd, msg, wParam, (LPARAM)wnd); + } + + return FALSE; + } + + LRESULT m_lresult; + +protected: + HWND m_hwnd; + HWND m_hwndParent; + int m_idDialog; + MSG m_msg; + bool m_isModal; + bool m_initialized; + bool m_forceResizable; + + enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; + BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL + + CCtrlBase* m_first; + + // override this handlers to provide custom functionality + // general messages + virtual void OnInitDialog() { } + virtual void OnClose() { } + virtual void OnDestroy() { } + + // miranda-related stuff + virtual int Resizer(UTILRESIZECONTROL *urc); + virtual void OnApply() {} + virtual void OnReset() {} + virtual void OnChange(CCtrlBase*) {} + + // main dialog procedure + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + // resister controls + void AddControl(CCtrlBase *ctrl); + +private: + LIST m_controls; + + void NotifyControls(void (CCtrlBase::*fn)()); + CCtrlBase *FindControl(int idCtrl); + + static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink + +class CDbLink +{ + char *m_szModule; + char *m_szSetting; + BYTE m_type; + + DWORD m_iDefault; + TCHAR *m_szDefault; + + DBVARIANT dbv; + +public: + CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue); + CDbLink(const char *szModule, const char *szSetting, BYTE type, TCHAR *szValue); + ~CDbLink(); + + __inline BYTE GetDataType() { return m_type; } + + DWORD LoadInt(); + void SaveInt(DWORD value); + + TCHAR *LoadText(); + void SaveText(TCHAR *value); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +class CCtrlBase +{ + friend class CDlgBase; + +public: + CCtrlBase(CDlgBase *wnd, int idCtrl ); + virtual ~CCtrlBase() { Unsubclass(); } + + __inline int GetCtrlId() const { return m_idCtrl; } + __inline HWND GetHwnd() const { return m_hwnd; } + __inline CDlgBase *GetParent() { return m_parentWnd; } + + void Enable( int bIsEnable = true ); + __inline void Disable() { Enable( false ); } + BOOL Enabled( void ) const; + + LRESULT SendMsg( UINT Msg, WPARAM wParam, LPARAM lParam ); + + void SetText(const TCHAR *text); + void SetTextA(const char *text); + void SetInt(int value); + + TCHAR *GetText(); + char *GetTextA(); + + TCHAR *GetText(TCHAR *buf, int size); + char *GetTextA(char *buf, int size); + + int GetInt(); + + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } + virtual BOOL OnNotify(int /*idCtrl*/, NMHDR* /*pnmh*/) { return FALSE; } + + virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDrawItem(DRAWITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDeleteItem(DELETEITEMSTRUCT*) { return FALSE; } + + virtual void OnInit(); + virtual void OnDestroy(); + + virtual void OnApply() {} + virtual void OnReset() {} + + static int cmp(const CCtrlBase *c1, const CCtrlBase *c2) + { + if (c1->m_idCtrl < c2->m_idCtrl) return -1; + if (c1->m_idCtrl > c2->m_idCtrl) return +1; + return 0; + } + +protected: + HWND m_hwnd; + int m_idCtrl; + CCtrlBase* m_next; + CDlgBase* m_parentWnd; + + virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + void Subclass(); + void Unsubclass(); + +private: + WNDPROC m_wndproc; + static LRESULT CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + if (CCtrlBase *ctrl = (CCtrlBase*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) + if (ctrl) + return ctrl->CustomWndProc(msg, wParam, lParam); + + return DefWindowProc(hwnd, msg, wParam, lParam); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +class CCtrlButton : public CCtrlBase +{ +public: + CCtrlButton( CDlgBase* dlg, int ctrlId ); + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); + + CCallback OnClick; + + int GetState(); + void SetState(int state); +}; + +class CCtrlMButton : public CCtrlButton +{ +public: + CCtrlMButton( CDlgBase* dlg, int ctrlId, HICON hIcon, const char* tooltip ); + CCtrlMButton( CDlgBase* dlg, int ctrlId, int iCoreIcon, const char* tooltip ); + ~CCtrlMButton(); + + void MakeFlat(); + void MakePush(); + + virtual void OnInit(); + +protected: + HICON m_hIcon; + const char* m_toolTip; +}; + +class CCtrlHyperlink : public CCtrlBase +{ +public: + CCtrlHyperlink( CDlgBase* dlg, int ctrlId, const char* url ); + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); + +protected: + const char* m_url; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc +class CCtrlClc: public CCtrlBase +{ +public: + CCtrlClc( CDlgBase* dlg, int ctrlId ); + + void AddContact(HANDLE hContact); + void AddGroup(HANDLE hGroup); + void AutoRebuild(); + void DeleteItem(HANDLE hItem); + void EditLabel(HANDLE hItem); + void EndEditLabel(bool save); + void EnsureVisible(HANDLE hItem, bool partialOk); + void Expand(HANDLE hItem, DWORD flags); + HANDLE FindContact(HANDLE hContact); + HANDLE FindGroup(HANDLE hGroup); + COLORREF GetBkColor(); + bool GetCheck(HANDLE hItem); + int GetCount(); + HWND GetEditControl(); + DWORD GetExpand(HANDLE hItem); + int GetExtraColumns(); + BYTE GetExtraImage(HANDLE hItem, int iColumn); + HIMAGELIST GetExtraImageList(); + HFONT GetFont(int iFontId); + HANDLE GetSelection(); + HANDLE HitTest(int x, int y, DWORD *hitTest); + void SelectItem(HANDLE hItem); + void SetBkBitmap(DWORD mode, HBITMAP hBitmap); + void SetBkColor(COLORREF clBack); + void SetCheck(HANDLE hItem, bool check); + void SetExtraColumns(int iColumns); + void SetExtraImage(HANDLE hItem, int iColumn, int iImage); + void SetExtraImageList(HIMAGELIST hImgList); + void SetFont(int iFontId, HANDLE hFont, bool bRedraw); + void SetIndent(int iIndent); + void SetItemText(HANDLE hItem, char *szText); + void SetHideEmptyGroups(bool state); + void SetGreyoutFlags(DWORD flags); + bool GetHideOfflineRoot(); + void SetHideOfflineRoot(bool state); + void SetUseGroups(bool state); + void SetOfflineModes(DWORD modes); + DWORD GetExStyle(); + void SetExStyle(DWORD exStyle); + int GetLefrMargin(); + void SetLeftMargin(int iMargin); + HANDLE AddInfoItem(CLCINFOITEM *cii); + int GetItemType(HANDLE hItem); + HANDLE GetNextItem(HANDLE hItem, DWORD flags); + COLORREF GetTextColot(int iFontId); + void SetTextColor(int iFontId, COLORREF clText); + + struct TEventInfo + { + CCtrlClc *ctrl; + NMCLISTCONTROL *info; + }; + + CCallback OnExpanded; + CCallback OnListRebuilt; + CCallback OnItemChecked; + CCallback OnDragging; + CCallback OnDropped; + CCallback OnListSizeChange; + CCallback OnOptionsChanged; + CCallback OnDragStop; + CCallback OnNewContact; + CCallback OnContactMoved; + CCallback OnCheckChanged; + CCallback OnClick; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData - data access controls base class + +class CCtrlData : public CCtrlBase +{ +public: + CCtrlData( CDlgBase* dlg, int ctrlId ); + + virtual ~CCtrlData() + { + if (m_dbLink) delete m_dbLink; + } + + __inline bool IsChanged() const { return m_changed; } + + void CreateDbLink( const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue ); + void CreateDbLink( const char* szModuleName, const char* szSetting, TCHAR* szValue ); + + virtual void OnInit(); + + // Events + CCallback OnChange; + +protected: + CDbLink *m_dbLink; + bool m_changed; + + void NotifyChange(); + + __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } + __inline DWORD LoadInt() { return m_dbLink ? m_dbLink->LoadInt() : 0; } + __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } + __inline const TCHAR *LoadText() { return m_dbLink ? m_dbLink->LoadText() : _T(""); } + __inline void SaveText(TCHAR *value) { if (m_dbLink) m_dbLink->SaveText(value); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck + +class CCtrlCheck : public CCtrlData +{ +public: + CCtrlCheck( CDlgBase* dlg, int ctrlId ); + virtual BOOL OnCommand(HWND, WORD, WORD) { NotifyChange(); return TRUE; } + virtual void OnInit() + { + CCtrlData::OnInit(); + OnReset(); + } + virtual void OnApply() + { + SaveInt(GetState()); + } + virtual void OnReset() + { + SetState(LoadInt()); + } + + int GetState(); + void SetState(int state); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit + +class CCtrlEdit : public CCtrlData +{ +public: + CCtrlEdit( CDlgBase* dlg, int ctrlId ); + virtual BOOL OnCommand(HWND, WORD, WORD idCode) + { + if (idCode == EN_CHANGE) + NotifyChange(); + return TRUE; + } + virtual void OnInit() + { + CCtrlData::OnInit(); + OnReset(); + } + virtual void OnApply() + { + if (GetDataType() == DBVT_TCHAR) + { + int len = GetWindowTextLength(m_hwnd) + 1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(m_hwnd, buf, len); + SaveText(buf); + } + else if (GetDataType() != DBVT_DELETED) + { + SaveInt(GetInt()); + } + } + virtual void OnReset() + { + if (GetDataType() == DBVT_TCHAR) + SetText(LoadText()); + else if (GetDataType() != DBVT_DELETED) + SetInt(LoadInt()); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox + +class CCtrlListBox : public CCtrlBase +{ +public: + CCtrlListBox( CDlgBase* dlg, int ctrlId ); + + int AddString(TCHAR *text, LPARAM data=0); + void DeleteString(int index); + int FindString(TCHAR *str, int index = -1, bool exact = false); + int GetCount(); + int GetCurSel(); + LPARAM GetItemData(int index); + TCHAR* GetItemText(int index); + TCHAR* GetItemText(int index, TCHAR *buf, int size); + bool GetSel(int index); + int GetSelCount(); + int* GetSelItems(int *items, int count); + int* GetSelItems(); + int InsertString(TCHAR *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(TCHAR *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void SetSel(int index, bool sel=true); + + // Events + CCallback OnDblClick; + CCallback OnSelCancel; + CCallback OnSelChange; + +protected: + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo + +class CCtrlCombo : public CCtrlData +{ +public: + CCtrlCombo( CDlgBase* dlg, int ctrlId ); + + virtual BOOL OnCommand(HWND, WORD, WORD idCode) + { + switch (idCode) + { + case CBN_CLOSEUP: OnCloseup(this); break; + case CBN_DROPDOWN: OnDropdown(this); break; + + case CBN_EDITCHANGE: + case CBN_EDITUPDATE: + case CBN_SELCHANGE: + case CBN_SELENDOK: + NotifyChange(); + break; + } + return TRUE; + } + + virtual void OnInit() + { + CCtrlData::OnInit(); + OnReset(); + } + virtual void OnApply() + { + if (GetDataType() == DBVT_TCHAR) + { + int len = GetWindowTextLength(m_hwnd) + 1; + TCHAR *buf = (TCHAR *)_alloca(sizeof(TCHAR) * len); + GetWindowText(m_hwnd, buf, len); + SaveText(buf); + } + else if (GetDataType() != DBVT_DELETED) + { + SaveInt(GetInt()); + } + } + virtual void OnReset() + { + if (GetDataType() == DBVT_TCHAR) + SetText(LoadText()); + else if (GetDataType() != DBVT_DELETED) + SetInt(LoadInt()); + } + + // Control interface + int AddString(const TCHAR *text, LPARAM data = 0 ); + int AddStringA(const char *text, LPARAM data = 0 ); + void DeleteString(int index); + int FindString(const TCHAR *str, int index = -1, bool exact = false); + int FindStringA(const char *str, int index = -1, bool exact = false); + int GetCount(); + int GetCurSel(); + bool GetDroppedState(); + LPARAM GetItemData(int index); + TCHAR* GetItemText(int index); + TCHAR* GetItemText(int index, TCHAR *buf, int size); + int InsertString(TCHAR *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(TCHAR *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void ShowDropdown(bool show = true); + + // Events + CCallback OnCloseup; + CCallback OnDropdown; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +class CCtrlListView : public CCtrlBase +{ +public: + CCtrlListView( CDlgBase* dlg, int ctrlId ); + + // Classic LV interface + DWORD ApproximateViewRect(int cx, int cy, int iCount); + void Arrange(UINT code); + void CancelEditLabel(); + HIMAGELIST CreateDragImage(int iItem, LPPOINT lpptUpLeft); + void DeleteAllItems(); + void DeleteColumn(int iCol); + void DeleteItem(int iItem); + HWND EditLabel(int iItem); + int EnableGroupView(BOOL fEnable); + BOOL EnsureVisible(int i, BOOL fPartialOK); + int FindItem(int iStart, const LVFINDINFO *plvfi); + COLORREF GetBkColor(); + void GetBkImage(LPLVBKIMAGE plvbki); + UINT GetCallbackMask(); + BOOL GetCheckState(UINT iIndex); + void GetColumn(int iCol, LPLVCOLUMN pcol); + void GetColumnOrderArray(int iCount, int *lpiArray); + int GetColumnWidth(int iCol); + int GetCountPerPage(); + HWND GetEditControl(); + //void GetEmptyText(PWSTR pszText, UINT cchText); + DWORD GetExtendedListViewStyle(); + INT GetFocusedGroup(); + //void GetFooterInfo(LVFOOTERINFO *plvfi); + //void GetFooterItem(UINT iItem, LVFOOTERITEM *pfi); + //void GetFooterItemRect(UINT iItem, RECT *prc); + //void GetFooterRect(RECT *prc); + int GetGroupCount(); + //HIMAGELIST GetGroupHeaderImageList(); + void GetGroupInfo(int iGroupId, PLVGROUP pgrp); + void GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp); + void GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics); + //BOOL GetGroupRect(int iGroupId, RECT *prc); + UINT GetGroupState(UINT dwGroupId, UINT dwMask); + HWND GetHeader(); + HCURSOR GetHotCursor(); + INT GetHotItem(); + DWORD GetHoverTime(); + HIMAGELIST GetImageList(int iImageList); + BOOL GetInsertMark(LVINSERTMARK *plvim); + COLORREF GetInsertMarkColor(); + int GetInsertMarkRect(LPRECT prc); + BOOL GetISearchString(LPSTR lpsz); + void GetItem(LPLVITEM pitem); + int GetItemCount(); + //void GetItemIndexRect(LVITEMINDEX *plvii, LONG iSubItem, LONG code, LPRECT prc); + void GetItemPosition(int i, POINT *ppt); + void GetItemRect(int i, RECT *prc, int code); + DWORD GetItemSpacing(BOOL fSmall); + UINT GetItemState(int i, UINT mask); + void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax); + int GetNextItem(int iStart, UINT flags); + //BOOL GetNextItemIndex(LVITEMINDEX *plvii, LPARAM flags); + BOOL GetNumberOfWorkAreas(LPUINT lpuWorkAreas); + BOOL GetOrigin(LPPOINT lpptOrg); + COLORREF GetOutlineColor(); + UINT GetSelectedColumn(); + UINT GetSelectedCount(); + INT GetSelectionMark(); + int GetStringWidth(LPCSTR psz); + BOOL GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect); + COLORREF GetTextBkColor(); + COLORREF GetTextColor(); + void GetTileInfo(PLVTILEINFO plvtinfo); + void GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); + HWND GetToolTips(); + int GetTopIndex(); + BOOL GetUnicodeFormat(); + DWORD GetView(); + BOOL GetViewRect(RECT *prc); + void GetWorkAreas(INT nWorkAreas, LPRECT lprc); + BOOL HasGroup(int dwGroupId); + int HitTest(LPLVHITTESTINFO pinfo); + int HitTestEx(LPLVHITTESTINFO pinfo); + int InsertColumn(int iCol, const LPLVCOLUMN pcol); + int InsertGroup(int index, PLVGROUP pgrp); + void InsertGroupSorted(PLVINSERTGROUPSORTED structInsert); + int InsertItem(const LPLVITEM pitem); + BOOL InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim); + BOOL IsGroupViewEnabled(); + UINT IsItemVisible(UINT index); + UINT MapIDToIndex(UINT id); + UINT MapIndexToID(UINT index); + BOOL RedrawItems(int iFirst, int iLast); + void RemoveAllGroups(); + int RemoveGroup(int iGroupId); + BOOL Scroll(int dx, int dy); + BOOL SetBkColor(COLORREF clrBk); + BOOL SetBkImage(LPLVBKIMAGE plvbki); + BOOL SetCallbackMask(UINT mask); + void SetCheckState(UINT iIndex, BOOL fCheck); + BOOL SetColumn(int iCol, LPLVCOLUMN pcol); + BOOL SetColumnOrderArray(int iCount, int *lpiArray); + BOOL SetColumnWidth(int iCol, int cx); + void SetExtendedListViewStyle(DWORD dwExStyle); + void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); + //HIMAGELIST SetGroupHeaderImageList(HIMAGELIST himl); + int SetGroupInfo(int iGroupId, PLVGROUP pgrp); + void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics); + void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); + HCURSOR SetHotCursor(HCURSOR hCursor); + INT SetHotItem(INT iIndex); + void SetHoverTime(DWORD dwHoverTime); + DWORD SetIconSpacing(int cx, int cy); + HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); + BOOL SetInfoTip(PLVSETINFOTIP plvSetInfoTip); + BOOL SetInsertMark(LVINSERTMARK *plvim); + COLORREF SetInsertMarkColor(COLORREF color); + BOOL SetItem(const LPLVITEM pitem); + void SetItemCount(int cItems); + void SetItemCountEx(int cItems, DWORD dwFlags); + //HRESULT SetItemIndexState(LVITEMINDEX *plvii, UINT data, UINT mask); + BOOL SetItemPosition(int i, int x, int y); + void SetItemPosition32(int iItem, int x, int y); + void SetItemState(int i, UINT state, UINT mask); + void SetItemText(int i, int iSubItem, TCHAR *pszText); + COLORREF SetOutlineColor(COLORREF color); + void SetSelectedColumn(int iCol); + INT SetSelectionMark(INT iIndex); + BOOL SetTextBkColor(COLORREF clrText); + BOOL SetTextColor(COLORREF clrText); + BOOL SetTileInfo(PLVTILEINFO plvtinfo); + BOOL SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); + HWND SetToolTips(HWND ToolTip); + BOOL SetUnicodeFormat(BOOL fUnicode); + int SetView(DWORD iView); + void SetWorkAreas(INT nWorkAreas, LPRECT lprc); + int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); + BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + INT SubItemHitTest(LPLVHITTESTINFO pInfo); + INT SubItemHitTestEx(LPLVHITTESTINFO plvhti); + BOOL Update(int iItem); + + // Events + struct TEventInfo { + CCtrlListView *treeviewctrl; + union { + NMHDR *nmhdr; + NMLISTVIEW *nmlv; + NMLVDISPINFO *nmlvdi; + NMLVSCROLL *nmlvscr; + NMLVGETINFOTIP *nmlvit; + NMLVFINDITEM *nmlvfi; + NMITEMACTIVATE *nmlvia; + NMLVKEYDOWN *nmlvkey; + }; + }; + + CCallback OnBeginDrag; + CCallback OnBeginLabelEdit; + CCallback OnBeginRDrag; + CCallback OnBeginScroll; + CCallback OnColumnClick; + //CCallback OnColumnDropdown; + //CCallback OnColumnOverflowClick; + CCallback OnDeleteAllItems; + CCallback OnDeleteItem; + CCallback OnDoubleClick; + CCallback OnEndLabelEdit; + CCallback OnEndScroll; + CCallback OnGetDispInfo; + //CCallback OnGetEmptyMarkup; + CCallback OnGetInfoTip; + CCallback OnHotTrack; + CCallback OnIncrementalSearch; + CCallback OnInsertItem; + CCallback OnItemActivate; + CCallback OnItemChanged; + CCallback OnItemChanging; + CCallback OnKeyDown; + //CCallback OnLinkClick; + CCallback OnMarqueeBegin; + CCallback OnSetDispInfo; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +class CCtrlTreeView : public CCtrlBase +{ +public: + CCtrlTreeView( CDlgBase* dlg, int ctrlId ); + + // Classic TV interface + HIMAGELIST CreateDragImage(HTREEITEM hItem); + void DeleteAllItems(); + void DeleteItem(HTREEITEM hItem); + HWND EditLabel(HTREEITEM hItem); + void EndEditLabelNow(BOOL cancel); + void EnsureVisible(HTREEITEM hItem); + void Expand(HTREEITEM hItem, DWORD flag); + COLORREF GetBkColor(); + DWORD GetCheckState(HTREEITEM hItem); + HTREEITEM GetChild(HTREEITEM hItem); + int GetCount(); + HTREEITEM GetDropHilight(); + HWND GetEditControl(); + HTREEITEM GetFirstVisible(); + HIMAGELIST GetImageList(int iImage); + int GetIndent(); + COLORREF GetInsertMarkColor(); + void GetItem(TVITEMEX *tvi); + int GetItemHeight(); + void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect); + DWORD GetItemState(HTREEITEM hItem, DWORD stateMask); + HTREEITEM GetLastVisible(); + COLORREF GetLineColor(); + HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag); + HTREEITEM GetNextSibling(HTREEITEM hItem); + HTREEITEM GetNextVisible(HTREEITEM hItem); + HTREEITEM GetParent(HTREEITEM hItem); + HTREEITEM GetPrevSibling(HTREEITEM hItem); + HTREEITEM GetPrevVisible(HTREEITEM hItem); + HTREEITEM GetRoot(); + DWORD GetScrollTime(); + HTREEITEM GetSelection(); + COLORREF GetTextColor(); + HWND GetToolTips(); + BOOL GetUnicodeFormat(); + unsigned GetVisibleCount(); + HTREEITEM HitTest(TVHITTESTINFO *hti); + HTREEITEM InsertItem(TVINSERTSTRUCT *tvis); + //HTREEITEM MapAccIDToHTREEITEM(UINT id); + //UINT MapHTREEITEMtoAccID(HTREEITEM hItem); + void Select(HTREEITEM hItem, DWORD flag); + void SelectDropTarget(HTREEITEM hItem); + void SelectItem(HTREEITEM hItem); + void SelectSetFirstVisible(HTREEITEM hItem); + COLORREF SetBkColor(COLORREF clBack); + void SetCheckState(HTREEITEM hItem, DWORD state); + void SetImageList(HIMAGELIST hIml, int iImage); + void SetIndent(int iIndent); + void SetInsertMark(HTREEITEM hItem, BOOL fAfter); + COLORREF SetInsertMarkColor(COLORREF clMark); + void SetItem(TVITEMEX *tvi); + void SetItemHeight(short cyItem); + void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); + COLORREF SetLineColor(COLORREF clLine); + void SetScrollTime(UINT uMaxScrollTime); + COLORREF SetTextColor(COLORREF clText); + HWND SetToolTips(HWND hwndToolTips); + BOOL SetUnicodeFormat(BOOL fUnicode); + void SortChildren(HTREEITEM hItem, BOOL fRecurse); + void SortChildrenCB(TVSORTCB *cb, BOOL fRecurse); + + // Additional stuff + void TranslateItem(HTREEITEM hItem); + void TranslateTree(); + HTREEITEM FindNamedItem(HTREEITEM hItem, const TCHAR *name); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi, TCHAR *szText, int iTextLength); + + // Events + struct TEventInfo { + CCtrlTreeView *treeviewctrl; + union { + NMHDR *nmhdr; + NMTREEVIEW *nmtv; + NMTVDISPINFO *nmtvdi; + NMTVGETINFOTIP *nmtvit; + NMTVKEYDOWN *nmtvkey; + }; + }; + + CCallback OnBeginDrag; + CCallback OnBeginLabelEdit; + CCallback OnBeginRDrag; + CCallback OnDeleteItem; + CCallback OnEndLabelEdit; + CCallback OnGetDispInfo; + CCallback OnGetInfoTip; + CCallback OnItemExpanded; + CCallback OnItemExpanding; + CCallback OnKeyDown; + CCallback OnSelChanged; + CCallback OnSelChanging; + CCallback OnSetDispInfo; + CCallback OnSingleExpand; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCustom + +template +class CCtrlCustom : public CCtrlBase +{ +private: + void (TDlg::*m_pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode); + void (TDlg::*m_pfnOnNotify)(int idCtrl, NMHDR *pnmh); + void (TDlg::*m_pfnOnMeasureItem)(MEASUREITEMSTRUCT *param); + void (TDlg::*m_pfnOnDrawItem)(DRAWITEMSTRUCT *param); + void (TDlg::*m_pfnOnDeleteItem)(DELETEITEMSTRUCT *param); + +public: + CCtrlCustom(TDlg *wnd, int idCtrl, + void (TDlg::*pfnOnCommand)(HWND hwndCtrl, WORD idCtrl, WORD idCode), + void (TDlg::*pfnOnNotify)(int idCtrl, NMHDR *pnmh), + void (TDlg::*pfnOnMeasureItem)(MEASUREITEMSTRUCT *param) = NULL, + void (TDlg::*pfnOnDrawItem)(DRAWITEMSTRUCT *param) = NULL, + void (TDlg::*pfnOnDeleteItem)(DELETEITEMSTRUCT *param) = NULL): CCtrlBase(wnd, idCtrl) + { + m_pfnOnCommand = pfnOnCommand; + m_pfnOnNotify = pfnOnNotify; + m_pfnOnMeasureItem = pfnOnMeasureItem; + m_pfnOnDrawItem = pfnOnDrawItem; + m_pfnOnDeleteItem = pfnOnDeleteItem; + } + + virtual BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) + { + if (m_parentWnd && m_pfnOnCommand) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnCommand)(hwndCtrl, idCtrl, idCode); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnNotify(int idCtrl, NMHDR *pnmh) + { + if (m_parentWnd && m_pfnOnNotify) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnNotify)(idCtrl, pnmh); + return m_parentWnd->m_lresult; + } + return FALSE; + } + + virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnMeasureItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnMeasureItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnDrawItem(DRAWITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnDrawItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnDrawItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } + virtual BOOL OnDeleteItem(DELETEITEMSTRUCT *param) + { + if (m_parentWnd && m_pfnOnDeleteItem) { + m_parentWnd->m_lresult = 0; + (((TDlg *)m_parentWnd)->*m_pfnOnDeleteItem)(param); + return m_parentWnd->m_lresult; + } + return FALSE; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CProtoDlgBase + +template +class CProtoDlgBase : public CDlgBase +{ +public: + __inline CProtoDlgBase(TProto *proto, int idDialog, HWND parent ) : + CDlgBase( idDialog, parent ), + m_proto( proto ) + { + } + + __inline void CreateLink( CCtrlData& ctrl, char *szSetting, BYTE type, DWORD iValue) + { + ctrl.CreateDbLink((( PROTO_INTERFACE* )m_proto)->m_szModuleName, szSetting, type, iValue ); + } + __inline void CreateLink( CCtrlData& ctrl, const char *szSetting, TCHAR *szValue) + { + ctrl.CreateDbLink((( PROTO_INTERFACE* )m_proto)->m_szModuleName, szSetting, szValue ); + } + + __inline TProto *GetProto() { return m_proto; } + +protected: + TProto* m_proto; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton); +void UIShowControls(HWND hwndDlg, int *idList, int nCmdShow); + +#endif // __jabber_ui_utils_h__ diff --git a/protocols/IRCG/src/userinfo.cpp b/protocols/IRCG/src/userinfo.cpp new file mode 100644 index 0000000000..8f6378a3ce --- /dev/null +++ b/protocols/IRCG/src/userinfo.cpp @@ -0,0 +1,224 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// 'User details' dialog + +struct UserDetailsDlgProcParam +{ + UserDetailsDlgProcParam( CIrcProto* _pro, HANDLE _info ) : + ppro( _pro ), + hContact( _info ) + {} + + CIrcProto* ppro; + HANDLE hContact; +}; + +#define STR_BASIC "Faster! Searches the network for an exact match of the nickname only. The hostmask is optional and provides further security if used. Wildcards (? and *) are allowed." +#define STR_ADVANCED "Slower! Searches the network for nicknames matching a wildcard string. The hostmask is mandatory and a minimum of 4 characters is necessary in the \"Nick\" field. Wildcards (? and *) are allowed." +#define STR_ERROR "Settings could not be saved!\n\nThe \"Nick\" field must contain at least four characters including wildcards,\n and it must also match the default nickname for this contact." +#define STR_ERROR2 "Settings could not be saved!\n\nA full hostmask must be set for this online detection mode to work." + +INT_PTR CALLBACK UserDetailsDlgProc(HWND m_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + UserDetailsDlgProcParam* p = ( UserDetailsDlgProcParam* )GetWindowLongPtr( m_hwnd, GWLP_USERDATA ); + switch (msg) { + case WM_INITDIALOG: + p = new UserDetailsDlgProcParam( NULL, ( HANDLE )lParam ); + SetWindowLongPtr( m_hwnd, GWLP_USERDATA, ( LPARAM )p ); + break; + + case WM_NOTIFY: + if ((( LPNMHDR )lParam )->idFrom == 0 && (( LPNMHDR )lParam )->code == PSN_PARAMCHANGED ) { + p->ppro = ( CIrcProto* )(( PSHNOTIFY* )lParam )->lParam; + + DBVARIANT dbv; + BYTE bAdvanced = p->ppro->getByte( p->hContact, "AdvancedMode", 0); + + TranslateDialogDefault( m_hwnd); + + CheckDlgButton( m_hwnd, IDC_RADIO1, bAdvanced?BST_UNCHECKED:BST_CHECKED); + CheckDlgButton( m_hwnd, IDC_RADIO2, bAdvanced?BST_CHECKED:BST_UNCHECKED); + EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), bAdvanced); + + if ( !bAdvanced ) { + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_BASIC)); + if ( !p->ppro->getTString( p->hContact, "Default", &dbv)) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + else { + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_ADVANCED)); + if ( !p->ppro->getTString( p->hContact, "UWildcard", &dbv)) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal); + DBFreeVariant(&dbv); + } } + + if ( !p->ppro->getTString( p->hContact, "UUser", &dbv)) { + SetDlgItemText( m_hwnd, IDC_USER, dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if ( !p->ppro->getTString( p->hContact, "UHost", &dbv)) { + SetDlgItemText( m_hwnd, IDC_HOST, dbv.ptszVal); + DBFreeVariant(&dbv); + } + ProtoBroadcastAck(p->ppro->m_szModuleName, p->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0); + } + break; + + case WM_COMMAND: + if (( LOWORD(wParam) == IDC_WILDCARD || LOWORD(wParam) == IDC_USER || LOWORD(wParam) == IDC_HOST ) && + ( HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) + return true; + + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), true); + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON2), true); + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BUTTON ) { + TCHAR temp[500]; + GetDlgItemText( m_hwnd, IDC_WILDCARD, temp, SIZEOF(temp)); + DBVARIANT dbv; + + BYTE bAdvanced = IsDlgButtonChecked( m_hwnd, IDC_RADIO1)?0:1; + if ( bAdvanced ) { + if ( GetWindowTextLength(GetDlgItem( m_hwnd, IDC_WILDCARD)) == 0 || + GetWindowTextLength(GetDlgItem( m_hwnd, IDC_USER)) == 0 || + GetWindowTextLength(GetDlgItem( m_hwnd, IDC_HOST)) == 0) + { + MessageBox( NULL, TranslateT(STR_ERROR2), TranslateT("IRC error"), MB_OK|MB_ICONERROR); + return FALSE; + } + + if ( !p->ppro->getTString( p->hContact, "Default", &dbv )) { + CMString S = _T(STR_ERROR); + S += _T(" ("); + S += dbv.ptszVal; + S += _T(")"); + if (( lstrlen(temp) < 4 && lstrlen(temp)) || !WCCmp(CharLower(temp), CharLower(dbv.ptszVal))) { + MessageBox( NULL, TranslateTS( S.c_str()), TranslateT( "IRC error" ), MB_OK | MB_ICONERROR ); + DBFreeVariant( &dbv ); + return FALSE; + } + DBFreeVariant( &dbv ); + } + + GetDlgItemText( m_hwnd, IDC_WILDCARD, temp, SIZEOF(temp)); + if ( lstrlen( GetWord(temp, 0).c_str())) + p->ppro->setTString( p->hContact, "UWildcard", GetWord(temp, 0).c_str()); + else + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UWildcard"); + } + + p->ppro->setByte( p->hContact, "AdvancedMode", bAdvanced); + + GetDlgItemText( m_hwnd, IDC_USER, temp, SIZEOF(temp)); + if (lstrlen(GetWord(temp, 0).c_str())) + p->ppro->setTString( p->hContact, "UUser", GetWord(temp, 0).c_str()); + else + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UUser"); + + GetDlgItemText( m_hwnd, IDC_HOST, temp, SIZEOF(temp)); + if (lstrlen(GetWord(temp, 0).c_str())) + p->ppro->setTString( p->hContact, "UHost", GetWord(temp, 0).c_str()); + else + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UHost"); + + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), FALSE); + } + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_BUTTON2 ) { + if ( IsDlgButtonChecked( m_hwnd, IDC_RADIO2 )) + SetDlgItemTextA( m_hwnd, IDC_WILDCARD, ""); + SetDlgItemTextA( m_hwnd, IDC_HOST, "" ); + SetDlgItemTextA( m_hwnd, IDC_USER, "" ); + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UWildcard"); + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UUser"); + DBDeleteContactSetting( p->hContact, p->ppro->m_szModuleName, "UHost"); + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON), FALSE ); + EnableWindow(GetDlgItem( m_hwnd, IDC_BUTTON2), FALSE ); + } + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RADIO1 ) { + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_BASIC)); + + DBVARIANT dbv; + if ( !p->ppro->getTString( p->hContact, "Default", &dbv )) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), FALSE ); + } + + if ( HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RADIO2 ) { + DBVARIANT dbv; + SetDlgItemText( m_hwnd, IDC_DEFAULT, TranslateT(STR_ADVANCED)); + if ( !p->ppro->getTString( p->hContact, "UWildcard", &dbv )) { + SetDlgItemText( m_hwnd, IDC_WILDCARD, dbv.ptszVal ); + DBFreeVariant( &dbv ); + } + EnableWindow(GetDlgItem( m_hwnd, IDC_WILDCARD), true); + } + break; + } + return FALSE; +} + +int __cdecl CIrcProto::OnInitUserInfo(WPARAM wParam, LPARAM lParam) +{ + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, lParam, 0); + HANDLE hContact = (HANDLE) lParam; + if ( !hContact || !szProto || lstrcmpiA( szProto, m_szModuleName )) + return 0; + + if ( getByte( hContact, "ChatRoom", 0 ) != 0 ) + return 0; + + if ( getByte( hContact, "DCC", 0 ) != 0 ) + return 0; + + DBVARIANT dbv; + if ( !getTString( hContact, "Default", &dbv )) { + if ( IsChannel( dbv.ptszVal )) { + DBFreeVariant( &dbv ); + return 0; + } + DBFreeVariant(&dbv); + } + + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.flags = ODPF_DONTTRANSLATE; + odp.pszTitle = m_szModuleName; + odp.hIcon = NULL; + odp.dwInitParam = ( LPARAM )this; + odp.hInstance = hInst; + odp.position = -1900000000; + odp.pfnDlgProc = UserDetailsDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_USERINFO); + odp.pszTitle = m_szModuleName; + UserInfo_AddPage(wParam, &odp); + return 0; +} diff --git a/protocols/IRCG/src/version.h b/protocols/IRCG/src/version.h new file mode 100644 index 0000000000..4def5ec467 --- /dev/null +++ b/protocols/IRCG/src/version.h @@ -0,0 +1,12 @@ +#define __FILEVERSION_STRING 0,11,0,1 +#define __VERSION_STRING "0.11.0.1" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 11, 0, 1) + +#define __DESC "IRC protocol for Miranda NG." +#define __AUTHOR "Miranda team" +#define __AUTHOREMAIL "ghazan@miranda-im.org" +#define __COPYRIGHT "c 2003-2011 Jurgen Persson, George Hazan" +#define __AUTHORWEB "http://miranda-ng.org/" + +#define __PLUGIN_NAME "IRC protocol" +#define __FILENAME "IRC.dll" diff --git a/protocols/IRCG/src/windows.cpp b/protocols/IRCG/src/windows.cpp new file mode 100644 index 0000000000..313e99353c --- /dev/null +++ b/protocols/IRCG/src/windows.cpp @@ -0,0 +1,1406 @@ +/* +IRC plugin for Miranda IM + +Copyright (C) 2003-05 Jurgen Persson +Copyright (C) 2007-09 George Hazan + +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 "irc.h" + +static WNDPROC OldMgrEditProc; + +///////////////////////////////////////////////////////////////////////////////////////// +// Message Box + +CMessageBoxDlg::CMessageBoxDlg( CIrcProto* _pro, DCCINFO* _dci ) : + CProtoDlgBase( _pro, IDD_MESSAGEBOX, NULL ), + pdci( _dci ), + m_Ok( this, IDOK ) +{ + m_Ok.OnClick = Callback( this, &CMessageBoxDlg::OnOk ); +} + +void CMessageBoxDlg::OnInitDialog() +{ +} + +void CMessageBoxDlg::OnOk( CCtrlButton* ) +{ + CDccSession* dcc = new CDccSession(m_proto, pdci); + + CDccSession* olddcc = m_proto->FindDCCSession(pdci->hContact); + if (olddcc) + olddcc->Disconnect(); + m_proto->AddDCCSession(pdci->hContact, dcc); + + dcc->Connect(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Whois dialog + +CWhoisDlg::CWhoisDlg( CIrcProto* _pro ) : + CCoolIrcDlg( _pro, IDD_INFO ), + m_InfoNick( this, IDC_INFO_NICK ), + m_Reply( this, IDC_REPLY ), + m_Caption( this, IDC_CAPTION ), + m_AwayTime( this, IDC_AWAYTIME ), + m_InfoName( this, IDC_INFO_NAME ), + m_InfoId( this, IDC_INFO_ID ), + m_InfoAddress( this, IDC_INFO_ADDRESS ), + m_InfoChannels( this, IDC_INFO_CHANNELS ), + m_InfoAuth( this, IDC_INFO_AUTH ), + m_InfoServer( this, IDC_INFO_SERVER ), + m_InfoAway2( this, IDC_INFO_AWAY2 ), + m_InfoOther( this, IDC_INFO_OTHER ), + m_Ping( this, IDC_PING ), + m_Version( this, IDC_VERSION ), + m_Time( this, IDC_TIME ), + m_userInfo( this, IDC_USERINFO ), + m_Refresh( this, ID_INFO_GO ), + m_Query( this, ID_INFO_QUERY ) +{ + m_Ping.OnClick = Callback( this, &CWhoisDlg::OnPing ); + m_Version.OnClick = Callback( this, &CWhoisDlg::OnVersion ); + m_Time.OnClick = Callback( this, &CWhoisDlg::OnTime ); + m_userInfo.OnClick = Callback( this, &CWhoisDlg::OnUserInfo ); + m_Refresh.OnClick = Callback( this, &CWhoisDlg::OnGo ); + m_Query.OnClick = Callback( this, &CWhoisDlg::OnQuery ); +} + +void CWhoisDlg::OnInitDialog() +{ + LOGFONT lf; + HFONT hFont = ( HFONT )m_AwayTime.SendMsg( WM_GETFONT, 0, 0 ); + GetObject( hFont, sizeof( lf ), &lf ); + lf.lfWeight = FW_BOLD; + hFont = CreateFontIndirect( &lf ); + m_AwayTime.SendMsg( WM_SETFONT, ( WPARAM )hFont, 0 ); + + CCoolIrcDlg::OnInitDialog(); + + WindowSetIcon( m_hwnd, IDI_WHOIS ); +} + +void CWhoisDlg::OnClose() +{ + ShowWindow( m_hwnd, SW_HIDE); + SendMessage( m_hwnd, WM_SETREDRAW, FALSE, 0); +} + +void CWhoisDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + + HFONT hFont2=(HFONT)SendDlgItemMessage( m_hwnd,IDC_AWAYTIME,WM_GETFONT,0,0); + SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,SendDlgItemMessage( m_hwnd,IDOK,WM_GETFONT,0,0),0); + DeleteObject(hFont2); + + m_proto->m_whoisDlg = NULL; +} + +void CWhoisDlg::OnGo( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_proto->PostIrcMessage( _T("/WHOIS %s %s"), szTemp, szTemp ); +} + +void CWhoisDlg::OnQuery( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_proto->PostIrcMessage( _T("/QUERY %s"), szTemp ); +} + +void CWhoisDlg::OnPing( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001PING %u\001"), szTemp, time(0)); +} + +void CWhoisDlg::OnUserInfo( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001USERINFO\001"), szTemp); +} + +void CWhoisDlg::OnTime( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001TIME\001"), szTemp); +} + +void CWhoisDlg::OnVersion( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_InfoNick.GetText( szTemp, SIZEOF(szTemp)); + m_Reply.SetText( TranslateT("Please wait...")); + m_proto->PostIrcMessage( _T("/PRIVMSG %s \001VERSION\001"), szTemp); +} + +void CWhoisDlg::ShowMessage( const CIrcMessage* pmsg ) +{ + if ( m_InfoNick.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM) pmsg->parameters[1].c_str()) == CB_ERR) + m_InfoNick.SendMsg( CB_ADDSTRING, 0, (LPARAM) pmsg->parameters[1].c_str()); + int i = m_InfoNick.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM) pmsg->parameters[1].c_str()); + m_InfoNick.SendMsg( CB_SETCURSEL, i, 0); + m_Caption.SetText( pmsg->parameters[1].c_str()); + m_InfoName.SetText( pmsg->parameters[5].c_str()); + m_InfoAddress.SetText( pmsg->parameters[3].c_str()); + m_InfoId.SetText( pmsg->parameters[2].c_str()); + m_InfoChannels.SetText( _T("")); + m_InfoServer.SetText( _T("")); + m_InfoAway2.SetText( _T("")); + m_InfoAuth.SetText( _T("")); + m_InfoOther.SetText( _T("")); + m_Reply.SetText( _T("")); + SetWindowText( m_hwnd, TranslateT("User information")); + EnableWindow( GetDlgItem( m_hwnd, ID_INFO_QUERY), true ); + ShowWindow( m_hwnd, SW_SHOW); + if ( IsIconic( m_hwnd )) + ShowWindow( m_hwnd, SW_SHOWNORMAL ); + SendMessage( m_hwnd, WM_SETREDRAW, TRUE, 0); + InvalidateRect( m_hwnd, NULL, TRUE); +} + +void CWhoisDlg::ShowMessageNoUser( const CIrcMessage* pmsg ) +{ + m_InfoNick.SetText( pmsg->parameters[2].c_str()); + m_InfoNick.SendMsg( CB_SETEDITSEL, 0,MAKELPARAM(0,-1)); + m_Caption.SetText( pmsg->parameters[2].c_str()); + m_InfoName.SetText( _T("")); + m_InfoAddress.SetText( _T("")); + m_InfoId.SetText( _T("")); + m_InfoChannels.SetText( _T("")); + m_InfoServer.SetText( _T("")); + m_InfoAway2.SetText( _T("")); + m_InfoAuth.SetText( _T("")); + m_Reply.SetText( _T("")); + EnableWindow(GetDlgItem(m_hwnd, ID_INFO_QUERY), false); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Change nickname' dialog + +CNickDlg::CNickDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_NICK ), + m_Ok( this, IDOK ), + m_Enick( this, IDC_ENICK ) +{ + m_Ok.OnClick = Callback( this, &CNickDlg::OnOk ); +} + +void CNickDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + WindowSetIcon( m_hwnd, IDI_RENAME ); + + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentNicks", &dbv)) { + for (int i = 0; i<10; i++) + if ( !GetWord( dbv.ptszVal, i).IsEmpty()) + SendDlgItemMessage( m_hwnd, IDC_ENICK, CB_ADDSTRING, 0, (LPARAM)GetWord(dbv.ptszVal, i).c_str()); + + DBFreeVariant(&dbv); +} } + +void CNickDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + m_proto->m_nickDlg = NULL; +} + +void CNickDlg::OnOk( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_Enick.GetText( szTemp, SIZEOF(szTemp)); + m_proto->PostIrcMessage( _T("/NICK %s"), szTemp); + + CMString S = szTemp; + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentNicks", &dbv )) { + for ( int i = 0; i<10; i++ ) { + CMString s = GetWord(dbv.ptszVal, i); + if ( !s.IsEmpty() && s != szTemp) + S += _T(" ") + s; + } + DBFreeVariant(&dbv); + } + m_proto->setTString( "RecentNicks", S.c_str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Change nickname' dialog + +#define LIST_TIMER 10 + +CListDlg::CListDlg(CIrcProto *_pro) : + CProtoDlgBase( _pro, IDD_LIST, NULL ), + m_Join( this, IDC_JOIN ), + m_list( this, IDC_INFO_LISTVIEW ), + m_list2( this, IDC_INFO_LISTVIEW2 ), + m_status( this, IDC_TEXT ), + m_filter( this, IDC_FILTER_STRING ) +{ + m_list2.OnDoubleClick = m_list.OnDoubleClick = m_Join.OnClick = Callback( this, &CListDlg::OnJoin ); + m_list.OnColumnClick = Callback( this, &CListDlg::List_OnColumnClick ); +} + +void CListDlg::OnInitDialog() +{ + RECT screen; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0); + LVCOLUMN lvC; + int COLUMNS_SIZES[4] ={200, 50,50,2000}; + TCHAR szBuffer[32]; + + lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvC.fmt = LVCFMT_LEFT; + for ( int index = 0; index < 4; index++ ) { + lvC.iSubItem = index; + lvC.cx = COLUMNS_SIZES[index]; + + switch( index ) { + case 0: lstrcpy( szBuffer, TranslateT("Channel")); break; + case 1: lstrcpy( szBuffer, _T("#")); break; + case 2: lstrcpy( szBuffer, TranslateT("Mode")); break; + case 3: lstrcpy( szBuffer, TranslateT("Topic")); break; + } + lvC.pszText = szBuffer; + m_list.InsertColumn( index, &lvC ); + m_list2.InsertColumn( index, &lvC ); + } + + Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "channelList_"); + + m_list.SetExtendedListViewStyle( LVS_EX_FULLROWSELECT ); + m_list2.SetExtendedListViewStyle( LVS_EX_FULLROWSELECT ); + WindowSetIcon( m_hwnd, IDI_LIST ); + m_status.SetText( TranslateT( "Please wait..." )); +} + +INT_PTR CListDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if ( msg == WM_TIMER ) { + ::KillTimer( m_hwnd, m_timer ); m_timer = 0; + + // Retrieve the input text + TCHAR strFilterText[255]; + m_filter.GetText( strFilterText, SIZEOF(strFilterText)); + + if ( strFilterText[0] ) { + int itemCount = 0; + int j = m_list.GetItemCount(); + if ( j <= 0 ) + return FALSE; + + // Empty the filtered list + m_list2.DeleteAllItems(); + + LVITEM lvm; + TCHAR text[255]; + lvm.pszText = text; // Set buffer for texts + lvm.cchTextMax = 128; + lvm.mask = LVIF_TEXT; + for ( int i = 0; i < j; i++ ) { + lvm.iSubItem = 0; // First column + lvm.iItem = i; + m_list.GetItem( &lvm ); + + // Match the text? + TCHAR* t = _tcsstr( lvm.pszText, strFilterText); + if ( t == NULL ) // If no, then Check if in the topics + { + LVITEM lvm2; // To avoid to overwrite the external lvm + TCHAR text[300]; + lvm2.pszText = text; // Set buffer for texts + lvm2.cchTextMax = SIZEOF(text); + lvm2.mask = LVIF_TEXT; + lvm2.iSubItem = 3; // Topic column + lvm2.iItem = i; + m_list.GetItem( &lvm ); + + // Match the text? + t = _tcsstr( lvm.pszText, strFilterText); + } + if ( t ) { + ++itemCount; + + // Column 0 + LVITEM lvItem; + lvItem.iItem = m_list2.GetItemCount(); + lvItem.mask = LVIF_TEXT | LVIF_PARAM; + + lvItem.iSubItem = 0; + lvItem.pszText = lvm.pszText; + lvItem.lParam = lvItem.iItem; + lvItem.iItem = m_list2.InsertItem( &lvItem ); + + // Column 2 + lvm.mask = LVIF_TEXT; + lvm.iSubItem = 1; + lvm.iItem = i; + m_list.GetItem( &lvm ); + + lvItem.mask = LVIF_TEXT; + lvItem.iSubItem = 1; + lvItem.pszText = lvm.pszText; + m_list2.SetItem( &lvItem ); + + // Column 4 + lvm.mask= LVIF_TEXT; + lvm.iSubItem = 3; + lvm.iItem = i; + m_list.GetItem( &lvm ); + + lvItem.mask = LVIF_TEXT; + lvItem.pszText = lvm.pszText; + lvItem.iSubItem = 3; + m_list2.SetItem( &lvItem ); + } } + + // Show the list + SetWindowPos( m_list2.GetHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); + ShowWindow( m_list.GetHwnd(), SW_HIDE ); + + // New dialog title + TCHAR newTitle[255]; + wsprintf( newTitle, TranslateT("%s - Filtered - %d items"), m_title, itemCount ); + SetWindowText( m_hwnd, newTitle ); + } + else { + ShowWindow( m_list.GetHwnd(), SW_SHOW ); + ShowWindow( m_list2.GetHwnd(), SW_HIDE); + SetWindowText( m_hwnd, m_title ); + } } + + return CProtoDlgBase::DlgProc( msg, wParam, lParam ); +} + +void CListDlg::OnChange( CCtrlBase* ctrl ) +{ + if ( ctrl->GetCtrlId() == IDC_FILTER_STRING ) + m_timer = ::SetTimer( m_hwnd, LIST_TIMER, 200, NULL ); +} + +void CListDlg::OnDestroy() +{ + if ( m_timer ) + ::KillTimer( m_hwnd, m_timer ); + Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "channelList_"); + m_proto->m_listDlg = NULL; +} + +struct ListViewSortParam +{ + CCtrlListView* pList; + int iSubItem; +}; + +static int CALLBACK ListViewSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + ListViewSortParam* param = ( ListViewSortParam* )lParamSort; + if ( !param->pList->GetHwnd()) + return 0; + + TCHAR temp1[512]; + TCHAR temp2[512]; + LVITEM lvm; + lvm.mask = LVIF_TEXT; + lvm.iItem = lParam1; + lvm.iSubItem = param->iSubItem; + lvm.pszText = temp1; + lvm.cchTextMax = 511; + param->pList->GetItem( &lvm ); + lvm.iItem = lParam2; + lvm.pszText = temp2; + param->pList->GetItem( &lvm ); + if (param->iSubItem != 1){ + if (lstrlen(temp1) != 0 && lstrlen(temp2) !=0) + return lstrcmpi(temp1, temp2); + + return ( *temp1 == 0 ) ? 1 : -1; + } + + return ( StrToInt(temp1) < StrToInt(temp2)) ? 1 : -1; +} + +int CListDlg::Resizer( UTILRESIZECONTROL *urc) +{ + switch( urc->wId ) { + case IDC_INFO_LISTVIEW: + case IDC_INFO_LISTVIEW2: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORY_HEIGHT | RD_ANCHORX_WIDTH; + case IDC_FILTER_STRING: + case IDC_FILTER_BTN: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + case IDC_TEXT: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM | RD_ANCHORX_WIDTH; + } + + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; +} + +void CListDlg::List_OnColumnClick( CCtrlListView::TEventInfo* ev ) +{ + ListViewSortParam param = { &m_list, ev->nmlv->iSubItem }; + m_list.SortItems( ListViewSort, (LPARAM)¶m ); + UpdateList(); +} + +void CListDlg::OnJoin( CCtrlButton* ) +{ + TCHAR szTemp[255]; + m_filter.GetText( szTemp, SIZEOF(szTemp)); + + if ( szTemp[0] ) + m_list2.GetItemText( m_list2.GetSelectionMark(), 0, szTemp, 255 ); + else + m_list.GetItemText( m_list.GetSelectionMark(), 0, szTemp, 255 ); + m_proto->PostIrcMessage( _T("/JOIN %s"), szTemp ); +} + +void CListDlg::UpdateList() +{ + GetWindowText( m_hwnd, m_title, 128); + + int j = m_list.GetItemCount(); + if ( j > 0 ) { + LVITEM lvm; + lvm.mask= LVIF_PARAM; + lvm.iSubItem = 0; + for ( int i = 0; i < j; i++ ) { + lvm.iItem = i; + lvm.lParam = i; + m_list.SetItem( &lvm ); +} } } + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Join' dialog + +CJoinDlg::CJoinDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_NICK, NULL ), + m_Ok( this, IDOK ) +{ + m_Ok.OnClick = Callback( this, &CJoinDlg::OnOk ); +} + +void CJoinDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentChannels", &dbv)) { + for ( int i = 0; i < 20; i++ ) { + if ( !GetWord( dbv.ptszVal, i).IsEmpty()) { + CMString S = GetWord(dbv.ptszVal, i); + ReplaceString( S, _T("%newl"), _T(" ")); + SendDlgItemMessage( m_hwnd, IDC_ENICK, CB_ADDSTRING, 0, (LPARAM)S.c_str()); + } } + DBFreeVariant(&dbv); +} } + +void CJoinDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + m_proto->m_joinDlg = NULL; +} + +void CJoinDlg::OnOk( CCtrlButton* ) +{ + TCHAR szTemp[255]; + GetDlgItemText( m_hwnd, IDC_ENICK, szTemp, SIZEOF(szTemp)); + if ( m_proto->IsChannel( szTemp )) + m_proto->PostIrcMessage( _T("/JOIN %s"), szTemp ); + else + m_proto->PostIrcMessage( _T("/JOIN #%s"), szTemp ); + + CMString S = szTemp; + ReplaceString( S, _T(" "), _T("%newl")); + CMString SL = S; + + DBVARIANT dbv; + if ( !m_proto->getTString( "RecentChannels", &dbv)) { + for (int i = 0; i < 20; i++ ) { + CMString W = GetWord(dbv.ptszVal, i); + if ( !W.IsEmpty() && W != SL) + S += _T(" ") + W; + } + DBFreeVariant(&dbv); + } + m_proto->setTString("RecentChannels", S.c_str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Quick' dialog + +CQuickDlg::CQuickDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_QUICKCONN ), + m_Ok( this, IDOK ), + m_serverCombo( this, IDC_SERVERCOMBO ) +{ + m_Ok.OnClick = Callback( this, &CQuickDlg::OnOk ); + m_serverCombo.OnChange = Callback( this, &CQuickDlg::OnServerCombo ); +} + +void CQuickDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + if ( g_servers.getCount() > 0 ) { + for ( int i=0; i < g_servers.getCount(); i++ ) { + const SERVER_INFO& si = g_servers[i]; + m_serverCombo.AddStringA( si.m_name, ( LPARAM )&si ); + } + } + else EnableWindow(GetDlgItem( m_hwnd, IDOK), false); + + m_si = new SERVER_INFO; + m_si->m_group = mir_strdup( "" ); + m_si->m_name = mir_strdup( Translate("---- Not listed server ----")); + + DBVARIANT dbv; + if ( !m_proto->getString( "ServerName", &dbv )) { + m_si->m_address = mir_strdup( dbv.pszVal ); + DBFreeVariant(&dbv); + } + else m_si->m_address = mir_strdup( Translate("Type new server address here")); + + if ( !m_proto->getString( "PortStart", &dbv )) { + m_si->m_portStart = atoi( dbv.pszVal ); + DBFreeVariant(&dbv); + } + else m_si->m_portStart = 6667; + + if ( !m_proto->getString( "PortEnd", &dbv )) { + m_si->m_portEnd = atoi( dbv.pszVal ); + DBFreeVariant(&dbv); + } + else m_si->m_portEnd = 6667; + + m_si->m_iSSL = m_proto->getByte( "UseSSL", 0 ); + + m_serverCombo.AddStringA( m_si->m_name, ( LPARAM )m_si ); + + if ( m_proto->m_quickComboSelection != -1 ) { + m_serverCombo.SetCurSel( m_proto->m_quickComboSelection ); + OnServerCombo( NULL ); + } + else EnableWindow(GetDlgItem( m_hwnd, IDOK), false); +} + +void CQuickDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + + delete m_si; + m_proto->m_quickDlg = NULL; +} + +void CQuickDlg::OnOk( CCtrlButton* ) +{ + GetDlgItemTextA( m_hwnd, IDC_SERVER, m_proto->m_serverName, SIZEOF(m_proto->m_serverName)); + GetDlgItemTextA( m_hwnd, IDC_PORT, m_proto->m_portStart, SIZEOF(m_proto->m_portStart)); + GetDlgItemTextA( m_hwnd, IDC_PORT2, m_proto->m_portEnd, SIZEOF(m_proto->m_portEnd)); + GetDlgItemTextA( m_hwnd, IDC_PASS, m_proto->m_password, SIZEOF(m_proto->m_password)); + + int i = m_serverCombo.GetCurSel(); + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + if ( pData && (INT_PTR)pData != CB_ERR ) { + lstrcpyA( m_proto->m_network, pData->m_group ); + pData->m_iSSL = 0; + if ( IsDlgButtonChecked( m_hwnd, IDC_SSL_ON )) + pData->m_iSSL = 2; + if ( IsDlgButtonChecked( m_hwnd, IDC_SSL_AUTO )) + pData->m_iSSL = 1; + m_proto->m_iSSL = pData->m_iSSL; + } + + TCHAR windowname[20]; + GetWindowText( m_hwnd, windowname, 20); + if ( lstrcmpi(windowname, _T("Miranda IRC")) == 0 ) { + m_proto->m_serverComboSelection = m_serverCombo.GetCurSel() - 1; + m_proto->setDword("ServerComboSelection",m_proto->m_serverComboSelection); + m_proto->setString("ServerName",m_proto->m_serverName); + m_proto->setString("PortStart",m_proto->m_portStart); + m_proto->setString("PortEnd",m_proto->m_portEnd); + CallService( MS_DB_CRYPT_ENCODESTRING, 499, (LPARAM)m_proto->m_password); + m_proto->setString("Password",m_proto->m_password); + CallService( MS_DB_CRYPT_DECODESTRING, 499, (LPARAM)m_proto->m_password); + m_proto->setString("Network",m_proto->m_network); + m_proto->setByte("UseSSL",m_proto->m_iSSL); + } + m_proto->m_quickComboSelection = m_serverCombo.GetCurSel(); + m_proto->setDword("QuickComboSelection",m_proto->m_quickComboSelection); + m_proto->DisconnectFromServer(); + m_proto->ConnectToServer(); +} + +void CQuickDlg::OnServerCombo( CCtrlData* ) +{ + int i = m_serverCombo.GetCurSel(); + if ( i == CB_ERR ) + return; + + SERVER_INFO* pData = ( SERVER_INFO* )m_serverCombo.GetItemData( i ); + SetDlgItemTextA( m_hwnd, IDC_SERVER, pData->m_address ); + SetDlgItemTextA( m_hwnd, IDC_PASS, "" ); + SetDlgItemInt( m_hwnd, IDC_PORT, pData->m_portStart, FALSE ); + SetDlgItemInt( m_hwnd, IDC_PORT2, pData->m_portEnd, FALSE ); + + if ( pData->m_iSSL == 0 ) { + CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_CHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_UNCHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_UNCHECKED ); + } + if ( pData->m_iSSL == 1 ) { + CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_CHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_UNCHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_UNCHECKED ); + } + if ( pData->m_iSSL == 2 ) { + CheckDlgButton( m_hwnd, IDC_SSL_ON, BST_CHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_OFF, BST_UNCHECKED ); + CheckDlgButton( m_hwnd, IDC_SSL_AUTO, BST_UNCHECKED ); + } + + if ( !strcmp( pData->m_name, Translate("---- Not listed server ----" ))) { + SendDlgItemMessage( m_hwnd, IDC_SERVER, EM_SETREADONLY, false, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT, EM_SETREADONLY, false, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT2, EM_SETREADONLY, false, 0); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_OFF), TRUE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_AUTO),TRUE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_ON), TRUE); + } + else { + SendDlgItemMessage( m_hwnd, IDC_SERVER, EM_SETREADONLY, true, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT, EM_SETREADONLY, true, 0); + SendDlgItemMessage( m_hwnd, IDC_PORT2, EM_SETREADONLY, true, 0); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_OFF), FALSE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_AUTO),FALSE); + EnableWindow(GetDlgItem( m_hwnd, IDC_SSL_ON), FALSE); + } + + EnableWindow(GetDlgItem( m_hwnd, IDOK), true); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Question' dialog + +CQuestionDlg::CQuestionDlg(CIrcProto *_pro, CManagerDlg* owner ) : + CCoolIrcDlg( _pro, IDD_QUESTION, ( owner == NULL ) ? NULL : owner->GetHwnd()), + m_Ok( this, IDOK ), + m_owner( owner ) +{ + m_Ok.OnClick = Callback( this, &CQuestionDlg::OnOk ); +} + +void CQuestionDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + WindowSetIcon( m_hwnd, IDI_IRCQUESTION ); +} + +void CQuestionDlg::OnClose() +{ + if ( m_owner ) + m_owner->CloseQuestion(); +} + +void CQuestionDlg::OnOk( CCtrlButton* ) +{ + int i = GetWindowTextLength( GetDlgItem( m_hwnd, IDC_EDIT )); + if ( i > 0 ) { + TCHAR* l = new TCHAR[ i+2 ]; + GetDlgItemText( m_hwnd, IDC_EDIT, l, i+1 ); + + int j = GetWindowTextLength(GetDlgItem( m_hwnd, IDC_HIDDENEDIT)); + TCHAR* m = new TCHAR[ j+2 ]; + GetDlgItemText( m_hwnd, IDC_HIDDENEDIT, m, j+1 ); + + TCHAR* text = _tcsstr( m, _T("%question")); + TCHAR* p1 = text; + TCHAR* p2 = NULL; + if ( p1 ) { + p1 += 9; + if ( *p1 == '=' && p1[1] == '\"' ) { + p1 += 2; + for ( int k =0; k < 3; k++ ) { + p2 = _tcschr( p1, '\"' ); + if ( p2 ) { + p2++; + if ( k == 2 || (*p2 != ',' || (*p2 == ',' && p2[1] != '\"'))) + *p2 = '\0'; + else + p2 += 2; + p1 = p2; + } } + } + else *p1 = '\0'; + } + + TCHAR* n = ( TCHAR* )alloca( sizeof( TCHAR )*( j+2 )); + GetDlgItemText( m_hwnd, IDC_HIDDENEDIT, n, j+1 ); + CMString S( n ); + ReplaceString( S, text, l ); + m_proto->PostIrcMessageWnd( NULL, NULL, (TCHAR*)S.c_str()); + + delete []m; + delete []l; + + if ( m_owner ) + m_owner->ApplyQuestion(); +} } + +void CQuestionDlg::Activate() +{ + ShowWindow( m_hwnd, SW_SHOW ); + SetActiveWindow( m_hwnd ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 'Channel Manager' dialog + +CManagerDlg::CManagerDlg(CIrcProto *_pro) : + CCoolIrcDlg( _pro, IDD_CHANMANAGER ), + m_list( this, IDC_LIST ), + + m_check1( this, IDC_CHECK1 ), + m_check2( this, IDC_CHECK2 ), + m_check3( this, IDC_CHECK3 ), + m_check4( this, IDC_CHECK4 ), + m_check5( this, IDC_CHECK5 ), + m_check6( this, IDC_CHECK6 ), + m_check7( this, IDC_CHECK7 ), + m_check8( this, IDC_CHECK8 ), + m_check9( this, IDC_CHECK9 ), + + m_key( this, IDC_KEY ), + m_limit( this, IDC_LIMIT ), + m_topic( this, IDC_TOPIC ), + + m_add( this, IDC_ADD, LoadIconEx(IDI_ADD), LPGEN("Add ban/invite/exception")), + m_edit( this, IDC_EDIT, LoadIconEx(IDI_EDIT), LPGEN("Edit selected ban/invite/exception")), + m_remove( this, IDC_REMOVE, LoadIconEx(IDI_DELETE), LPGEN("Delete selected ban/invite/exception")), + m_applyModes( this, IDC_APPLYMODES, LoadIconEx( IDI_APPLY ), LPGEN("Set these modes for the channel")), + m_applyTopic( this, IDC_APPLYTOPIC, LoadIconEx( IDI_APPLY ), LPGEN("Set this topic for the channel")), + + m_radio1( this, IDC_RADIO1 ), + m_radio2( this, IDC_RADIO2 ), + m_radio3( this, IDC_RADIO3 ) +{ + m_add.OnClick = Callback( this, &CManagerDlg::OnAdd ); + m_edit.OnClick = Callback( this, &CManagerDlg::OnEdit ); + m_remove.OnClick = Callback( this, &CManagerDlg::OnRemove ); + + m_applyModes.OnClick = Callback( this, &CManagerDlg::OnApplyModes ); + m_applyTopic.OnClick = Callback( this, &CManagerDlg::OnApplyTopic ); + + m_check1.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check2.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check3.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check4.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check5.OnChange = Callback( this, &CManagerDlg::OnCheck5 ); + m_check6.OnChange = Callback( this, &CManagerDlg::OnCheck6 ); + m_check7.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check8.OnChange = Callback( this, &CManagerDlg::OnCheck ); + m_check9.OnChange = Callback( this, &CManagerDlg::OnCheck ); + + m_key.OnChange = Callback( this, &CManagerDlg::OnChangeModes ); + m_limit.OnChange = Callback( this, &CManagerDlg::OnChangeModes ); + m_topic.OnChange = Callback( this, &CManagerDlg::OnChangeTopic ); + + m_radio1.OnChange = Callback( this, &CManagerDlg::OnRadio ); + m_radio2.OnChange = Callback( this, &CManagerDlg::OnRadio ); + m_radio3.OnChange = Callback( this, &CManagerDlg::OnRadio ); + + m_list.OnDblClick = Callback( this, &CManagerDlg::OnListDblClick ); + m_list.OnSelChange = Callback( this, &CManagerDlg::OnChangeList ); +} + +LRESULT CALLBACK MgrEditSubclassProc(HWND m_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch( msg ) { + case WM_CHAR : + if ( wParam == 21 || wParam == 11 || wParam == 2 ) { + char w[2]; + if ( wParam == 11 ) { + w[0] = 3; + w[1] = '\0'; + } + if ( wParam == 2 ) { + w[0] = 2; + w[1] = '\0'; + } + if ( wParam == 21 ) { + w[0] = 31; + w[1] = '\0'; + } + SendMessage( m_hwnd, EM_REPLACESEL, false, (LPARAM) w); + SendMessage( m_hwnd, EM_SCROLLCARET, 0, 0 ); + return 0; + } + break; + } + + return CallWindowProc(OldMgrEditProc, m_hwnd, msg, wParam, lParam); +} + +void CManagerDlg::OnInitDialog() +{ + CCoolIrcDlg::OnInitDialog(); + + POINT pt; + pt.x = 3; + pt.y = 3; + HWND hwndEdit = ChildWindowFromPoint( m_topic.GetHwnd(), pt); + OldMgrEditProc = (WNDPROC)SetWindowLongPtr(hwndEdit, GWLP_WNDPROC,(LONG_PTR)MgrEditSubclassProc); + + WindowSetIcon( m_hwnd, IDI_MANAGER ); + + m_list.SendMsg( LB_SETHORIZONTALEXTENT, 750, NULL ); + m_radio1.SetState( true ); + + const char* modes = m_proto->sChannelModes.c_str(); + if ( !strchr( modes, 't')) m_check1.Disable(); + if ( !strchr( modes, 'n')) m_check2.Disable(); + if ( !strchr( modes, 'i')) m_check3.Disable(); + if ( !strchr( modes, 'm')) m_check4.Disable(); + if ( !strchr( modes, 'k')) m_check5.Disable(); + if ( !strchr( modes, 'l')) m_check6.Disable(); + if ( !strchr( modes, 'p')) m_check7.Disable(); + if ( !strchr( modes, 's')) m_check8.Disable(); + if ( !strchr( modes, 'c')) m_check9.Disable(); +} + +void CManagerDlg::OnClose() +{ + if ( m_applyModes.Enabled() || m_applyTopic.Enabled()) { + int i = MessageBox( NULL, TranslateT("You have not applied all changes!\n\nApply before exiting?"), TranslateT("IRC warning"), MB_YESNOCANCEL|MB_ICONWARNING|MB_DEFBUTTON3); + if ( i == IDCANCEL ) { + m_lresult = TRUE; + return; + } + + if ( i == IDYES ) { + if ( m_applyModes.Enabled()) + OnApplyModes( NULL ); + if ( m_applyTopic.Enabled()) + OnApplyTopic( NULL ); + } } + + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, 255 ); + CMString S = _T(""); + TCHAR temp[1000]; + for ( int i = 0; i < 5; i++ ) { + if ( m_topic.SendMsg( CB_GETLBTEXT, i, (LPARAM)temp) != LB_ERR) { + CMString S1 = temp; +/* FIXME: What the hell does it mean!? GCC won't compile this on UNICODE */ +#if !defined(__GNUC__) || !defined(UNICODE) + ReplaceString( S1, _T(" "), _T("%¤")); +#endif + S += _T(" ") + S1; + } } + + if ( !S.IsEmpty() && m_proto->IsConnected()) { + mir_sntprintf( temp, SIZEOF(temp), _T("Topic%s%s"), window, m_proto->m_info.sNetwork.c_str()); + char* p = mir_t2a(temp); + m_proto->setTString(p, S.c_str()); + mir_free(p); + } + DestroyWindow( m_hwnd); +} + +void CManagerDlg::OnDestroy() +{ + CCoolIrcDlg::OnDestroy(); + m_proto->m_managerDlg = NULL; +} + +void CManagerDlg::OnAdd( CCtrlButton* ) +{ + TCHAR temp[100]; + TCHAR mode[3]; + if ( m_radio1.GetState()) { + lstrcpy( mode, _T("+b")); + lstrcpyn( temp, TranslateT("Add ban"), 100 ); + } + if ( m_radio2.GetState()) { + lstrcpy( mode, _T("+I")); + lstrcpyn( temp, TranslateT("Add invite"), 100 ); + } + if ( m_radio3.GetState()) { + lstrcpy( mode, _T("+e")); + lstrcpyn( temp, TranslateT("Add exception"), 100); + } + + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + + CQuestionDlg* dlg = new CQuestionDlg( m_proto, this ); + dlg->Show(); + HWND addban_hWnd = dlg->GetHwnd(); + SetDlgItemText(addban_hWnd, IDC_CAPTION, temp); + SetWindowText(GetDlgItem(addban_hWnd, IDC_TEXT), TranslateT("Please enter the hostmask (nick!user@host)")); + + TCHAR temp2[450]; + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + mir_sntprintf(temp2, 450, _T("/MODE %s %s %s"), window, mode, _T("%question")); + SetDlgItemText(addban_hWnd, IDC_HIDDENEDIT, temp2); + dlg->Activate(); +} + +void CManagerDlg::OnEdit( CCtrlButton* ) +{ + if ( !IsDlgButtonChecked( m_hwnd, IDC_NOTOP )) { + int i = m_list.GetCurSel(); + if ( i != LB_ERR ) { + TCHAR* m = m_list.GetItemText( i ); + CMString user = GetWord(m, 0); + mir_free( m ); + + TCHAR temp[100]; + TCHAR mode[3]; + if ( m_radio1.GetState()) { + lstrcpy( mode, _T("b")); + lstrcpyn( temp, TranslateT("Edit ban"), 100 ); + } + if ( m_radio2.GetState()) { + lstrcpy( mode, _T("I")); + lstrcpyn( temp, TranslateT("Edit invite?"), 100 ); + } + if ( m_radio3.GetState()) { + lstrcpy( mode, _T("e")); + lstrcpyn( temp, TranslateT("Edit exception?"), 100 ); + } + + CQuestionDlg* dlg = new CQuestionDlg( m_proto, this ); + dlg->Show(); + HWND addban_hWnd = dlg->GetHwnd(); + SetDlgItemText(addban_hWnd, IDC_CAPTION, temp); + SetWindowText(GetDlgItem(addban_hWnd, IDC_TEXT), TranslateT("Please enter the hostmask (nick!user@host)")); + SetWindowText(GetDlgItem(addban_hWnd, IDC_EDIT), user.c_str()); + + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + + TCHAR temp2[450]; + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + mir_sntprintf(temp2, 450, _T("/MODE %s -%s %s%s/MODE %s +%s %s"), window, mode, user.c_str(), _T("%newl"), window, mode, _T("%question")); + SetDlgItemText(addban_hWnd, IDC_HIDDENEDIT, temp2); + dlg->Activate(); +} } } + +void CManagerDlg::OnRemove( CCtrlButton* ) +{ + int i = m_list.GetCurSel(); + if ( i != LB_ERR ) { + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + + TCHAR temp[100], mode[3]; + TCHAR* m = m_list.GetItemText( i, temp, SIZEOF( temp )); + CMString user = GetWord(m, 0); + + if ( m_radio1.GetState()) { + lstrcpy(mode, _T("-b")); + lstrcpyn(temp, TranslateT( "Remove ban?" ), 100 ); + } + if ( m_radio2.GetState()) { + lstrcpy(mode, _T("-I")); + lstrcpyn(temp, TranslateT( "Remove invite?" ), 100 ); + } + if ( m_radio3.GetState()) { + lstrcpy(mode, _T("-e")); + lstrcpyn(temp, TranslateT( "Remove exception?" ), 100 ); + } + + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + if ( MessageBox( m_hwnd, user.c_str(), temp, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 ) == IDYES ) { + m_proto->PostIrcMessage( _T("/MODE %s %s %s"), window, mode, user.c_str()); + ApplyQuestion(); + } + CloseQuestion(); +} } + +void CManagerDlg::OnListDblClick( CCtrlListBox* ) +{ + OnEdit( NULL ); +} + +void CManagerDlg::OnChangeList( CCtrlListBox* ) +{ + if ( !IsDlgButtonChecked( m_hwnd, IDC_NOTOP )) { + m_edit.Enable(); + m_remove.Enable(); +} } + +void CManagerDlg::OnChangeModes( CCtrlData* ) +{ + m_applyModes.Enable(); +} + +void CManagerDlg::OnChangeTopic( CCtrlData* ) +{ + m_applyTopic.Enable(); +} + +void CManagerDlg::OnApplyModes( CCtrlButton* ) +{ + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + CHANNELINFO* wi = (CHANNELINFO *)m_proto->DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi ) { + TCHAR toadd[10]; *toadd = '\0'; + TCHAR toremove[10]; *toremove = '\0'; + CMString appendixadd = _T(""); + CMString appendixremove = _T(""); + if ( wi->pszMode && _tcschr( wi->pszMode, 't' )) { + if ( !m_check1.GetState()) + lstrcat( toremove, _T("t")); + } + else if ( m_check1.GetState()) + lstrcat( toadd, _T("t")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'n' )) { + if ( !m_check2.GetState()) + lstrcat( toremove, _T("n")); + } + else if ( m_check2.GetState()) + lstrcat( toadd, _T("n")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'i' )) { + if ( !m_check3.GetState()) + lstrcat( toremove, _T("i")); + } + else if ( m_check3.GetState()) + lstrcat( toadd, _T("i")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'm' )) { + if ( !m_check4.GetState()) + lstrcat( toremove, _T("m")); + } + else if ( m_check4.GetState()) + lstrcat( toadd, _T("m")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'p' )) { + if ( !m_check7.GetState()) + lstrcat( toremove, _T("p")); + } + else if ( m_check7.GetState()) + lstrcat( toadd, _T("p")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 's' )) { + if ( !m_check8.GetState()) + lstrcat( toremove, _T("s")); + } + else if ( m_check8.GetState()) + lstrcat( toadd, _T("s")); + + if ( wi->pszMode && _tcschr( wi->pszMode, 'c' )) { + if ( !m_check9.GetState()) + lstrcat( toremove, _T("c")); + } + else if ( m_check9.GetState()) + lstrcat( toadd, _T("c")); + + CMString Key = _T(""); + CMString Limit = _T(""); + if ( wi->pszMode && wi->pszPassword && _tcschr( wi->pszMode, 'k' )) { + if ( !m_check5.GetState()) { + lstrcat( toremove, _T("k")); + appendixremove += _T(" ") + CMString(wi->pszPassword); + } + else if ( GetWindowTextLength( m_key.GetHwnd())) { + TCHAR temp[400]; + m_key.GetText( temp, 14); + + if ( Key != temp ) { + lstrcat( toremove, _T("k")); + lstrcat( toadd, _T("k")); + appendixadd += _T(" ") + CMString(temp); + appendixremove += _T(" ") + CMString(wi->pszPassword); + } } + } + else if ( m_check5.GetState() && GetWindowTextLength( m_key.GetHwnd())) { + lstrcat( toadd, _T("k")); + appendixadd += _T(" "); + + TCHAR temp[400]; + m_key.GetText( temp, SIZEOF(temp)); + appendixadd += temp; + } + + if ( _tcschr( wi->pszMode, 'l' )) { + if ( !m_check6.GetState()) + lstrcat( toremove, _T("l")); + else if ( GetWindowTextLength( GetDlgItem( m_hwnd, IDC_LIMIT ))) { + TCHAR temp[15]; + GetDlgItemText( m_hwnd, IDC_LIMIT, temp, SIZEOF(temp)); + if ( wi->pszLimit && lstrcmpi( wi->pszLimit, temp )) { + lstrcat( toadd, _T("l")); + appendixadd += _T(" ") + CMString(temp); + } } + } + else if ( m_check6.GetState() && GetWindowTextLength( m_limit.GetHwnd())) { + lstrcat( toadd, _T("l")); + appendixadd += _T(" "); + + TCHAR temp[15]; + m_limit.GetText( temp, SIZEOF(temp)); + appendixadd += temp; + } + + if ( lstrlen(toadd) || lstrlen( toremove )) { + TCHAR temp[500]; + lstrcpy(temp, _T("/mode ")); + lstrcat(temp, window); + lstrcat(temp, _T(" ")); + if ( lstrlen( toremove )) + mir_sntprintf( temp, 499, _T("%s-%s"), temp, toremove ); + if ( lstrlen( toadd )) + mir_sntprintf( temp, 499, _T("%s+%s"), temp, toadd ); + if (!appendixremove.IsEmpty()) + lstrcat(temp, appendixremove.c_str()); + if (!appendixadd.IsEmpty()) + lstrcat(temp, appendixadd.c_str()); + m_proto->PostIrcMessage( temp); + } } + + m_applyModes.Disable(); +} + +void CManagerDlg::OnApplyTopic( CCtrlButton* ) +{ + TCHAR temp[470]; + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, SIZEOF(window)); + m_topic.GetText( temp, SIZEOF(temp)); + m_proto->PostIrcMessage( _T("/TOPIC %s %s"), window, temp); + int i = m_topic.SendMsg( CB_FINDSTRINGEXACT, -1, (LPARAM)temp); + if ( i != LB_ERR ) + m_topic.SendMsg( CB_DELETESTRING, i, 0); + m_topic.SendMsg( CB_INSERTSTRING, 0, (LPARAM)temp); + m_topic.SetText( temp ); + m_applyTopic.Disable(); +} + +void CManagerDlg::OnCheck( CCtrlData* ) +{ + m_applyModes.Enable(); +} + +void CManagerDlg::OnCheck5( CCtrlData* ) +{ + m_key.Enable( m_check5.GetState()); + m_applyModes.Enable(); +} + +void CManagerDlg::OnCheck6( CCtrlData* ) +{ + m_limit.Enable( m_check6.GetState()); + m_applyModes.Enable(); +} + +void CManagerDlg::OnRadio( CCtrlData* ) +{ + ApplyQuestion(); +} + +void CManagerDlg::ApplyQuestion() +{ + TCHAR window[256]; + GetDlgItemText( m_hwnd, IDC_CAPTION, window, 255); + + TCHAR mode[3]; + lstrcpy( mode, _T("+b")); + if ( m_radio2.GetState()) + lstrcpy( mode, _T("+I")); + if ( m_radio3.GetState()) + lstrcpy( mode, _T("+e")); + m_list.ResetContent(); + m_radio1.Disable(); + m_radio2.Disable(); + m_radio3.Disable(); + m_add.Disable(); + m_edit.Disable(); + m_remove.Disable(); + m_proto->PostIrcMessage( _T("%s %s %s"), _T("/MODE"), window, mode); //wrong overloaded operator if three args +} + +void CManagerDlg::CloseQuestion() +{ + m_add.Enable(); + if ( m_list.GetCurSel() != LB_ERR) { + m_edit.Enable(); + m_remove.Enable(); +} } + +void CManagerDlg::InitManager( int mode, const TCHAR* window ) +{ + SetWindowText( GetDlgItem( m_hwnd, IDC_CAPTION ), window ); + + CHANNELINFO* wi = (CHANNELINFO *)m_proto->DoEvent(GC_EVENT_GETITEMDATA, window, NULL, NULL, NULL, NULL, NULL, FALSE, FALSE, 0); + if ( wi ) { + if ( m_proto->IsConnected()) { + TCHAR temp[1000]; + mir_sntprintf(temp, SIZEOF(temp), _T("Topic%s%s"), window, m_proto->m_info.sNetwork.c_str()); + + char* p = mir_t2a(temp); + + DBVARIANT dbv; + if ( !m_proto->getTString( p, &dbv )) { + for ( int i = 0; i<5; i++ ) { + CMString S = GetWord(dbv.ptszVal, i); + if ( !S.IsEmpty()) { +/* FIXME: What the hell does it mean!? GCC won't compile this on UNICODE */ +#if !defined(__GNUC__) || !defined(UNICODE) + ReplaceString( S, _T("%¤"), _T(" ")); +#endif + m_topic.SendMsg( CB_ADDSTRING, 0, (LPARAM)S.c_str()); + } } + DBFreeVariant(&dbv); + } + mir_free(p); + } + + if ( wi->pszTopic ) + m_topic.SetText( wi->pszTopic ); + + if ( !IsDlgButtonChecked( m_proto->m_managerDlg->GetHwnd(), IDC_NOTOP )) + m_add.Enable(); + + bool add = false; + TCHAR* p1= wi->pszMode; + if ( p1 ) { + while ( *p1 != '\0' && *p1 != ' ' ) { + if (*p1 == '+') + add = true; + if (*p1 == '-') + add = false; + if (*p1 == 't') + m_check1.SetState( add ); + if (*p1 == 'n') + m_check2.SetState( add ); + if (*p1 == 'i') + m_check3.SetState( add ); + if (*p1 == 'm') + m_check4.SetState( add ); + if (*p1 == 'p') + m_check7.SetState( add ); + if (*p1 == 's') + m_check8.SetState( add ); + if (*p1 == 'c') + m_check9.SetState( add ); + if (*p1 == 'k' && add) { + m_check5.SetState( add ); + m_key.Enable( add ); + if ( wi->pszPassword ) + m_key.SetText( wi->pszPassword ); + } + if (*p1 == 'l' && add) { + m_check6.SetState( add ); + m_limit.Enable( add ); + if ( wi->pszLimit ) + m_limit.SetText( wi->pszLimit ); + } + p1++; + if ( mode == 0 ) { + m_limit.Disable(); + m_key.Disable(); + m_check1.Disable(); + m_check2.Disable(); + m_check3.Disable(); + m_check4.Disable(); + m_check5.Disable(); + m_check6.Disable(); + m_check7.Disable(); + m_check8.Disable(); + m_check9.Disable(); + m_add.Disable(); + if ( m_check1.GetState()) + m_topic.Disable(); + CheckDlgButton( m_hwnd, IDC_NOTOP, BST_CHECKED); + } + ShowWindow( m_hwnd, SW_SHOW ); + } } } + + if ( strchr( m_proto->sChannelModes.c_str(), 'b' )) { + m_radio1.SetState( true ); + m_proto->PostIrcMessage( _T("/MODE %s +b"), window); +} } + +///////////////////////////////////////////////////////////////////////////////////////// +// 'cool' dialog + +CCoolIrcDlg::CCoolIrcDlg( CIrcProto* _pro, int dlgId, HWND parent ) : + CProtoDlgBase( _pro, dlgId, parent ) +{ +} + +void CCoolIrcDlg::OnInitDialog() +{ + HFONT hFont; + LOGFONT lf; + hFont=(HFONT)SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_GETFONT,0,0); + GetObject(hFont,sizeof(lf),&lf); + lf.lfHeight=(int)(lf.lfHeight*1.2); + lf.lfWeight=FW_BOLD; + hFont=CreateFontIndirect(&lf); + SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,(WPARAM)hFont,0); + + SendDlgItemMessage( m_hwnd, IDC_LOGO, STM_SETICON,(LPARAM)(HICON)LoadIconEx(IDI_LOGO), 0); +} + +void CCoolIrcDlg::OnDestroy() +{ + HFONT hFont = (HFONT)SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_GETFONT,0,0); + SendDlgItemMessage( m_hwnd,IDC_CAPTION,WM_SETFONT,SendDlgItemMessage( m_hwnd,IDOK,WM_GETFONT,0,0),0); + DeleteObject(hFont); + + ReleaseIconEx((HICON)SendDlgItemMessage(m_hwnd, IDC_LOGO, STM_SETICON, 0, 0)); + WindowFreeIcon(m_hwnd); +} + +INT_PTR CCoolIrcDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if ( msg == WM_CTLCOLOREDIT || msg == WM_CTLCOLORSTATIC ) { + switch( GetDlgCtrlID(( HWND )lParam )) { + case IDC_WHITERECT: case IDC_TEXT: case IDC_CAPTION: case IDC_AWAYTIME: case IDC_LOGO: + SetTextColor((HDC)wParam,RGB(0,0,0)); + SetBkColor((HDC)wParam,RGB(255,255,255)); + return (INT_PTR)GetStockObject(WHITE_BRUSH); + } } + + return CDlgBase::DlgProc(msg, wParam, lParam); +} -- cgit v1.2.3