diff options
Diffstat (limited to 'miranda-wine/src')
144 files changed, 35297 insertions, 0 deletions
diff --git a/miranda-wine/src/core/commonheaders.c b/miranda-wine/src/core/commonheaders.c new file mode 100644 index 0000000..95b2201 --- /dev/null +++ b/miranda-wine/src/core/commonheaders.c @@ -0,0 +1,2 @@ +#include "commonheaders.h"
+
diff --git a/miranda-wine/src/core/commonheaders.h b/miranda-wine/src/core/commonheaders.h new file mode 100644 index 0000000..a08783f --- /dev/null +++ b/miranda-wine/src/core/commonheaders.h @@ -0,0 +1,84 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#if defined( UNICODE ) && !defined( _UNICODE )
+# define _UNICODE
+#endif
+
+#include <tchar.h>
+#include <malloc.h>
+
+#define _ALPHA_BASE_ 1 // defined for CVS builds
+#define _ALPHA_FUSE_ 1 // defined for fuse powered core
+
+#ifdef _DEBUG
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+#endif
+
+#define _WIN32_WINNT 0x0501
+#define _WIN32_IE 0x0500
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+#include "../resource.h"
+#include <win2k.h>
+#include "modules.h"
+#include "miranda.h"
+#include "forkthread.h"
+#include <m_system.h>
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_langpack.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_netlib.h>
+#include <m_button.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_protocols.h>
+#include <m_plugins.h>
+#include <m_options.h>
+#include <m_utils.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_message.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_addcontact.h>
+#include <m_findadd.h>
+#include <m_file.h>
+#include <m_email.h>
+#include <m_awaymsg.h>
+#include <m_idle.h>
+#include <m_ignore.h>
+#include <m_utils.h>
diff --git a/miranda-wine/src/core/forkthread.h b/miranda-wine/src/core/forkthread.h new file mode 100644 index 0000000..154584f --- /dev/null +++ b/miranda-wine/src/core/forkthread.h @@ -0,0 +1,64 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+/*
+
+Purpose:
+
+ A safe version of _beginthread()
+
+Description:
+
+ A new thread is created and the source thread is paused until
+ internal code to call MS_SYSTEM_THREAD_PUSH is made in the context
+ if the new thread.
+
+ The source thread is then released and then the user supplied
+ code is called, when that function returns -- MS_SYSTEM_THREAD_POP
+ is called and then the thread returns.
+
+ This insures that Miranda will not exit whilst new threads
+ are trying to be born; and the unwind wait stack will unsure
+ that Miranda will wait for all created threads to return as well.
+
+Cavets:
+
+ The function must be reimplemented across MT plugins, since thread
+ creation depends on CRT which can not be shared.
+
+*/
+unsigned long forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+);
+
+unsigned long forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void *arg,
+ unsigned cf,
+ unsigned *thraddr
+);
+
diff --git a/miranda-wine/src/core/memory.c b/miranda-wine/src/core/memory.c new file mode 100644 index 0000000..7c55939 --- /dev/null +++ b/miranda-wine/src/core/memory.c @@ -0,0 +1,167 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#define BLOCK_ALLOCED 0xABBABABA
+#define BLOCK_FREED 0xDEADBEEF
+
+static int CheckBlock( void* blk )
+{
+ int result = FALSE;
+ char* p = ( char* )blk - sizeof(DWORD)*2;
+ DWORD size, *b, *e;
+
+ __try
+ {
+ size = *( DWORD* )p;
+ b = ( DWORD* )&p[ sizeof( DWORD ) ];
+ e = ( DWORD* )&p[ sizeof( DWORD )*2 + size ];
+
+ if ( *b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED )
+ {
+ if ( *b == BLOCK_FREED && *e == BLOCK_FREED )
+ OutputDebugStringA( "memory block is already deleted\n" );
+ else
+ OutputDebugStringA( "memory block is corrupted\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+ else result = TRUE;
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OutputDebugStringA( "access violation during checking memory block\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+void* mir_alloc( size_t size )
+{
+ if ( size == 0 )
+ return NULL;
+ {
+ char* p = (char*)malloc( size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+} }
+
+/******************************************************************************/
+
+void* mir_calloc( size_t size )
+{
+ void* p = mir_alloc( size );
+ if ( p != NULL )
+ memset( p, 0, size );
+ return p;
+}
+
+/******************************************************************************/
+
+void* mir_realloc( void* ptr, size_t size )
+{
+ char* p;
+
+ if ( ptr != NULL ) {
+ if ( !CheckBlock( ptr ))
+ return NULL;
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ }
+ else p = NULL;
+
+ p = ( char* )realloc( p, size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+}
+
+/******************************************************************************/
+
+void mir_free( void* ptr )
+{
+ char* p;
+ DWORD size;
+
+ if ( ptr == NULL )
+ return;
+ if ( !CheckBlock( ptr ))
+ return;
+
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ size = *( DWORD* )p;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_FREED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
+ free( p );
+}
+
+/******************************************************************************/
+
+char* mir_strdup( const char* str )
+{
+ if ( str != NULL ) {
+ char* p = mir_alloc( strlen( str )+1 );
+ if ( p )
+ strcpy( p, str );
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+WCHAR* mir_wstrdup( const WCHAR* str )
+{
+ if ( str != NULL ) {
+ WCHAR* p = mir_alloc( sizeof( WCHAR )*( wcslen( str )+1 ));
+ if ( p )
+ wcscpy( p, str );
+ return p;
+ }
+ return NULL;
+}
diff --git a/miranda-wine/src/core/miranda.c b/miranda-wine/src/core/miranda.c new file mode 100644 index 0000000..f003ecf --- /dev/null +++ b/miranda-wine/src/core/miranda.c @@ -0,0 +1,565 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "../modules/database/dblists.h"
+
+int InitialiseModularEngine(void);
+void DestroyingModularEngine(void);
+void DestroyModularEngine(void);
+int UnloadNewPluginsModule(void);
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+DWORD (WINAPI *MyMsgWaitForMultipleObjectsEx)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD);
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags);
+
+static HANDLE hOkToExitEvent,hModulesLoadedEvent;
+HANDLE hShutdownEvent,hPreShutdownEvent;
+static HANDLE hWaitObjects[MAXIMUM_WAIT_OBJECTS-1];
+static char *pszWaitServices[MAXIMUM_WAIT_OBJECTS-1];
+static int waitObjectCount=0;
+HANDLE hStackMutex,hMirandaShutdown,hThreadQueueEmpty;
+
+struct THREAD_WAIT_ENTRY {
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+};
+
+struct THREAD_WAIT_ENTRY *WaitingThreads=NULL;
+int WaitingThreadsCount=0;
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ void (__cdecl *threadcode)(void*);
+ unsigned (__stdcall *threadcodeex)(void*);
+ void *arg;
+};
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ CallService(MS_SYSTEM_THREAD_PUSH,0,0);
+ SetEvent(fa->hEvent);
+ __try {
+ callercode(cookie);
+ } __finally {
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+ }
+ return;
+}
+
+unsigned long forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+)
+{
+ unsigned long rc;
+ struct FORK_ARG fa;
+ fa.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ fa.threadcode=threadcode;
+ fa.arg=arg;
+ rc=_beginthread(forkthread_r,stacksize,&fa);
+ if ((unsigned long)-1L != rc) {
+ WaitForSingleObject(fa.hEvent,INFINITE);
+ } //if
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa=(struct FORK_ARG *)arg;
+ unsigned (__stdcall * threadcode) (void *)=fa->threadcodeex;
+ void *cookie=fa->arg;
+ unsigned long rc;
+
+ CallService(MS_SYSTEM_THREAD_PUSH,0,0);
+ SetEvent(fa->hEvent);
+ __try {
+ rc=threadcode(cookie);
+ } __finally {
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+ }
+ return rc;
+}
+
+unsigned long forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void *arg,
+ unsigned cf,
+ unsigned *thraddr
+)
+{
+ unsigned long rc;
+ struct FORK_ARG fa;
+ fa.threadcodeex=threadcode;
+ fa.arg=arg;
+ fa.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ rc=_beginthreadex(sec,stacksize,forkthreadex_r,(void *)&fa,0,thraddr);
+ if (rc) {
+ WaitForSingleObject(fa.hEvent,INFINITE);
+ }
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+static void __stdcall DummyAPCFunc(DWORD dwArg)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc=MsgWaitForMultipleObjectsExWorkaround(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc == WAIT_OBJECT_0 + 1 ) {
+ MSG msg;
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( IsDialogMessage(msg.hwnd, &msg) ) continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else if ( rc==WAIT_OBJECT_0 ) {
+ // got object
+ return 1;
+ } else if ( rc==WAIT_ABANDONED_0 || rc == WAIT_FAILED ) return 0;
+ }
+}
+
+VOID CALLBACK KillAllThreads(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ if ( MirandaWaitForMutex( hStackMutex )) {
+ int j;
+ for ( j=0; j < WaitingThreadsCount; j++ ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( WaitingThreads[j].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "Thread %08x was abnormally terminated because module '%s' didn't released it",
+ WaitingThreads[j].hThread, szModuleName );
+ TerminateThread( WaitingThreads[j].hThread, 9999 );
+ }
+
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty);
+} }
+
+static void UnwindThreadWait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex) ) {
+ int j;
+ for (j=0;j<WaitingThreadsCount;j++)
+ QueueUserAPC(DummyAPCFunc,WaitingThreads[j].hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer( NULL, 0, 5000, KillAllThreads );
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+void* GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
+ if(NtQueryInformationThread == NULL) return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+int UnwindThreadPush(WPARAM wParam,LPARAM lParam)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ HANDLE hThread=0;
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hThread,THREAD_SET_CONTEXT,FALSE,0);
+ WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*(WaitingThreadsCount+1));
+ WaitingThreads[WaitingThreadsCount].hThread=hThread;
+ WaitingThreads[WaitingThreadsCount].dwThreadId=GetCurrentThreadId();
+ WaitingThreads[WaitingThreadsCount].hOwner=GetInstByAddress( GetCurrentThreadEntryPoint() );
+ WaitingThreadsCount++;
+#ifdef _DEBUG
+ {
+ char szBuf[64];
+ mir_snprintf(szBuf,SIZEOF(szBuf),"*** pushing thread (%x)\n",GetCurrentThreadId());
+ OutputDebugStringA(szBuf);
+ }
+#endif
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 0;
+}
+
+int UnwindThreadPop(WPARAM wParam,LPARAM lParam)
+{
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ DWORD dwThreadId=GetCurrentThreadId();
+ int j;
+ for (j=0;j<WaitingThreadsCount;j++) {
+ if (WaitingThreads[j].dwThreadId == dwThreadId) {
+ CloseHandle(WaitingThreads[j].hThread);
+ WaitingThreadsCount--;
+ if (j<WaitingThreadsCount) memmove(&WaitingThreads[j],&WaitingThreads[j+1],(WaitingThreadsCount-j) * sizeof(struct THREAD_WAIT_ENTRY));
+ if (!WaitingThreadsCount)
+ {
+ mir_free(WaitingThreads);
+ WaitingThreads=NULL;
+ WaitingThreadsCount=0;
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ } else {
+ WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*WaitingThreadsCount);
+ } //if
+ ReleaseMutex(hStackMutex);
+ return 0;
+ } //if
+ } //for
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 1;
+}
+
+int MirandaIsTerminated(WPARAM wParam,LPARAM lParam)
+{
+ return WaitForSingleObject(hMirandaShutdown,0)==WAIT_OBJECT_0;
+}
+
+static void __cdecl compactHeapsThread(void *dummy)
+{
+ while (!Miranda_Terminated())
+ {
+ HANDLE hHeaps[256];
+ DWORD hc;
+ SleepEx((1000*60)*5,TRUE); // every 5 minutes
+ hc=GetProcessHeaps(255,(PHANDLE)&hHeaps);
+ if (hc != 0 && hc < 256) {
+ DWORD j;
+ for (j=0;j<hc;j++) HeapCompact(hHeaps[j],0);
+ }
+ } //while
+}
+
+static void InsertRegistryKey(void)
+{
+ if(DBGetContactSettingByte(NULL,"_Sys","CreateRegKey",1)) {
+ HKEY hKey;
+ DWORD dw;
+ if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,"SOFTWARE\\Miranda",0,NULL,0,KEY_CREATE_SUB_KEY|KEY_SET_VALUE,NULL,&hKey,&dw)==ERROR_SUCCESS) {
+ char str[MAX_PATH],*str2;
+ GetModuleFileNameA(NULL,str,SIZEOF(str));
+ str2=strrchr(str,'\\');
+ if(str2!=NULL) *str2=0;
+ RegSetValueExA(hKey,"Install_Dir",0,REG_SZ,(PBYTE)str,lstrlenA(str)+1);
+ RegCloseKey(hKey);
+ }
+ }
+}
+
+DWORD CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg==WM_NULL) SleepEx(0,TRUE);
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+HWND hAPCWindow=NULL;
+void (*SetIdleCallback) (void)=NULL;
+
+static int SystemSetIdleCallback(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam && SetIdleCallback==NULL) {
+ SetIdleCallback=(void (*)(void))lParam;
+ return 1;
+ }
+ return 0;
+}
+
+static DWORD dwEventTime=0;
+void checkIdle(MSG * msg)
+{
+ switch(msg->message) {
+ case WM_MOUSEACTIVATE:
+ case WM_MOUSEMOVE:
+ case WM_CHAR:
+ {
+ dwEventTime = GetTickCount();
+ }
+ }
+}
+
+static int SystemGetIdle(WPARAM wParam, LPARAM lParam)
+{
+ if ( lParam ) *(DWORD*)lParam = dwEventTime;
+ return 0;
+}
+
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags)
+{
+ DWORD rc;
+ if ( MyMsgWaitForMultipleObjectsEx != NULL )
+ return MyMsgWaitForMultipleObjectsEx(nCount, pHandles, dwMsecs, dwWakeMask, dwFlags);
+ rc=MsgWaitForMultipleObjects(nCount, pHandles, FALSE, 50, QS_ALLINPUT);
+ if ( rc == WAIT_TIMEOUT ) rc=WaitForMultipleObjectsEx(nCount, pHandles, FALSE, 20, TRUE);
+ return rc;
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ DWORD myPid=0;
+ int messageloop=1;
+
+#ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ if (InitialiseModularEngine())
+ {
+ NotifyEventHooks(hShutdownEvent,0,0);
+ UnloadNewPluginsModule();
+ DestroyModularEngine();
+ return 1;
+ }
+ InsertRegistryKey();
+ NotifyEventHooks(hModulesLoadedEvent,0,0);
+ MyMsgWaitForMultipleObjectsEx=(DWORD (WINAPI *)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD))GetProcAddress(GetModuleHandleA("user32"),"MsgWaitForMultipleObjectsEx");
+ forkthread(compactHeapsThread,0,NULL);
+ CreateServiceFunction(MS_SYSTEM_SETIDLECALLBACK,SystemSetIdleCallback);
+ CreateServiceFunction(MS_SYSTEM_GETIDLE, SystemGetIdle);
+ dwEventTime=GetTickCount();
+ myPid=GetCurrentProcessId();
+ for(;messageloop;) {
+ MSG msg;
+ DWORD rc;
+ BOOL dying=FALSE;
+ rc=MsgWaitForMultipleObjectsExWorkaround(waitObjectCount, hWaitObjects, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + waitObjectCount) {
+ rc -= WAIT_OBJECT_0;
+ CallService(pszWaitServices[rc], (WPARAM) hWaitObjects[rc], 0);
+ }
+ //
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( msg.message != WM_QUIT ) {
+ HWND h=GetForegroundWindow();
+ DWORD pid = 0;
+ checkIdle(&msg);
+ if ( h != NULL && GetWindowThreadProcessId(h,&pid) && pid==myPid
+ && GetClassLong(h, GCW_ATOM)==32770 ) {
+ if ( IsDialogMessage(h, &msg) ) continue;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if ( SetIdleCallback != NULL )
+ SetIdleCallback();
+ } else if ( !dying ) {
+ dying++;
+ SetEvent(hMirandaShutdown);
+ NotifyEventHooks(hPreShutdownEvent, 0, 0);
+ DestroyingModularEngine();
+ // this spins and processes the msg loop, objects and APC.
+ UnwindThreadWait();
+ NotifyEventHooks(hShutdownEvent, 0, 0);
+ // if the hooks generated any messages, it'll get processed before the second WM_QUIT
+ PostQuitMessage(0);
+ } else if ( dying ) {
+ messageloop=0;
+ }
+ } // while
+ }
+ UnloadNewPluginsModule();
+ DestroyModularEngine();
+ CloseHandle(hStackMutex);
+ CloseHandle(hMirandaShutdown);
+ CloseHandle(hThreadQueueEmpty);
+ DestroyWindow(hAPCWindow);
+ return 0;
+}
+
+static int SystemShutdownProc(WPARAM wParam,LPARAM lParam)
+{
+ return 0;
+}
+
+static int OkToExit(WPARAM wParam,LPARAM lParam)
+{
+ return NotifyEventHooks(hOkToExitEvent,0,0)==0;
+}
+
+static int GetMirandaVersion(WPARAM wParam,LPARAM lParam)
+{
+ char filename[MAX_PATH];
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+ VS_FIXEDFILEINFO *vsffi;
+ DWORD ver;
+
+ GetModuleFileNameA(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSizeA(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo);
+ VerQueryValueA(pVerInfo,"\\",(PVOID*)&vsffi,&blockSize);
+ ver=(((vsffi->dwProductVersionMS>>16)&0xFF)<<24)|
+ ((vsffi->dwProductVersionMS&0xFF)<<16)|
+ (((vsffi->dwProductVersionLS>>16)&0xFF)<<8)|
+ (vsffi->dwProductVersionLS&0xFF);
+ mir_free(pVerInfo);
+ return (int)ver;
+}
+
+static int GetMirandaVersionText(WPARAM wParam,LPARAM lParam)
+{
+ char filename[MAX_PATH],*productVersion;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSizeA(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo);
+ VerQueryValueA(pVerInfo,"\\StringFileInfo\\000004b0\\ProductVersion",(void*)&productVersion,&blockSize);
+ #if defined( _UNICODE )
+ mir_snprintf(( char* )lParam, wParam, "%s Unicode", productVersion );
+ #else
+ lstrcpynA((char*)lParam,productVersion,wParam);
+ #endif
+ mir_free(pVerInfo);
+ return 0;
+}
+
+int WaitOnHandle(WPARAM wParam,LPARAM lParam)
+{
+ if(waitObjectCount>=MAXIMUM_WAIT_OBJECTS-1) return 1;
+ hWaitObjects[waitObjectCount]=(HANDLE)wParam;
+ pszWaitServices[waitObjectCount]=(char*)lParam;
+ waitObjectCount++;
+ return 0;
+}
+
+static int RemoveWait(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ for(i=0;i<waitObjectCount;i++)
+ if(hWaitObjects[i]==(HANDLE)wParam) break;
+ if(i==waitObjectCount) return 1;
+ waitObjectCount--;
+ MoveMemory(&hWaitObjects[i],&hWaitObjects[i+1],sizeof(HANDLE)*(waitObjectCount-i));
+ MoveMemory(&pszWaitServices[i],&pszWaitServices[i+1],sizeof(char*)*(waitObjectCount-i));
+ return 0;
+}
+
+int GetMemoryManagerInterface(WPARAM wParam, LPARAM lParam)
+{
+ struct MM_INTERFACE *mmi = (struct MM_INTERFACE*) lParam;
+ if (mmi || mmi->cbSize == sizeof(struct MM_INTERFACE))
+ {
+ mmi->mmi_malloc = mir_alloc;
+ mmi->mmi_realloc = mir_realloc;
+ mmi->mmi_free = mir_free;
+ return 0;
+ }
+ return 1;
+}
+
+int GetListInterface(WPARAM wParam, LPARAM lParam)
+{
+ struct LIST_INTERFACE *li = (struct LIST_INTERFACE*) lParam;
+ if (li || li->cbSize == sizeof(struct LIST_INTERFACE))
+ {
+ li->List_Create = List_Create;
+ li->List_Destroy = List_Destroy;
+ li->List_Find = List_Find;
+ li->List_GetIndex = List_GetIndex;
+ li->List_Insert = List_Insert;
+ li->List_Remove = List_Remove;
+ li->List_IndexOf = List_IndexOf;
+ return 0;
+ }
+ return 1;
+}
+
+int LoadSystemModule(void)
+{
+ InitCommonControls();
+
+ hAPCWindow=CreateWindowEx(0,_T("STATIC"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL); // lame
+ SetWindowLong(hAPCWindow,GWL_WNDPROC,(LONG)APCWndProc);
+ hStackMutex=CreateMutex(NULL,FALSE,NULL);
+ hMirandaShutdown=CreateEvent(NULL,TRUE,FALSE,NULL);
+ hThreadQueueEmpty=CreateEvent(NULL,TRUE,TRUE,NULL);
+
+ hShutdownEvent=CreateHookableEvent(ME_SYSTEM_SHUTDOWN);
+ hPreShutdownEvent=CreateHookableEvent(ME_SYSTEM_PRESHUTDOWN);
+ hModulesLoadedEvent=CreateHookableEvent(ME_SYSTEM_MODULESLOADED);
+ hOkToExitEvent=CreateHookableEvent(ME_SYSTEM_OKTOEXIT);
+
+ HookEvent(ME_SYSTEM_SHUTDOWN,SystemShutdownProc);
+
+ CreateServiceFunction(MS_SYSTEM_THREAD_PUSH,UnwindThreadPush);
+ CreateServiceFunction(MS_SYSTEM_THREAD_POP,UnwindThreadPop);
+ CreateServiceFunction(MS_SYSTEM_TERMINATED,MirandaIsTerminated);
+ CreateServiceFunction(MS_SYSTEM_OKTOEXIT,OkToExit);
+ CreateServiceFunction(MS_SYSTEM_GETVERSION,GetMirandaVersion);
+ CreateServiceFunction(MS_SYSTEM_GETVERSIONTEXT,GetMirandaVersionText);
+ CreateServiceFunction(MS_SYSTEM_WAITONHANDLE,WaitOnHandle);
+ CreateServiceFunction(MS_SYSTEM_REMOVEWAIT,RemoveWait);
+ CreateServiceFunction(MS_SYSTEM_GET_LI,GetListInterface);
+ CreateServiceFunction(MS_SYSTEM_GET_MMI,GetMemoryManagerInterface);
+ return 0;
+}
diff --git a/miranda-wine/src/core/miranda.h b/miranda-wine/src/core/miranda.h new file mode 100644 index 0000000..af80535 --- /dev/null +++ b/miranda-wine/src/core/miranda.h @@ -0,0 +1,48 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+/**** memory.c *************************************************************************/
+
+void* mir_alloc( size_t );
+void* mir_calloc( size_t );
+void* mir_realloc( void* ptr, size_t );
+void mir_free( void* ptr );
+char* mir_strdup( const char* str );
+WCHAR* mir_wstrdup( const WCHAR* str );
+
+#if defined( _UNICODE )
+ #define mir_tstrdup mir_wstrdup
+#else
+ #define mir_tstrdup mir_strdup
+#endif
+
+/**** utf.c ****************************************************************************/
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+
+/**** langpack.c ***********************************************************************/
+
+int LangPackGetDefaultCodePage();
+int LangPackGetDefaultLocale();
+TCHAR* LangPackPcharToTchar( const char* pszStr );
+char* LangPackTranslateString(const char *szEnglish, const int W);
diff --git a/miranda-wine/src/core/modules.c b/miranda-wine/src/core/modules.c new file mode 100644 index 0000000..dd180fe --- /dev/null +++ b/miranda-wine/src/core/modules.c @@ -0,0 +1,656 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <m_plugins.h>
+
+typedef struct {
+ MIRANDAHOOK pfnHook;
+ HINSTANCE hOwner;
+ HWND hwnd;
+ UINT message;
+} THookSubscriber;
+
+typedef struct {
+ char name[MAXMODULELABELLENGTH];
+ DWORD hookHash;
+ int subscriberCount;
+ THookSubscriber *subscriber;
+ MIRANDAHOOK pfnHook;
+} THookList;
+
+typedef struct {
+ char name[MAXMODULELABELLENGTH];
+ DWORD nameHash;
+ HINSTANCE hOwner;
+ MIRANDASERVICE pfnService;
+} TServiceList;
+
+typedef struct {
+ int hookId;
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+} THookToMainThreadItem;
+
+typedef struct {
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+ const char *name;
+} TServiceToMainThreadItem;
+
+static THookList *hook;
+static TServiceList *service;
+static int hookCount,serviceCount;
+static CRITICAL_SECTION csHooks,csServices;
+static DWORD mainThreadId;
+static HANDLE hMainThread;
+static HANDLE hMissingService;
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+int LoadSystemModule(void); // core: m_system.h services
+int LoadNewPluginsModuleInfos(void); // core: preloading plugins
+int LoadNewPluginsModule(void); // core: N.O. plugins
+int LoadNetlibModule(void); // core: network
+int LoadLangPackModule(void); // core: translation
+int LoadProtocolsModule(void); // core: protocol manager
+int LoadIgnoreModule(void); // protocol filter: ignore
+
+int LoadSendRecvUrlModule(void); //send/recv
+int LoadSendRecvEMailModule(void); //send/recv
+int LoadSendRecvAuthModule(void); //send/recv
+int LoadSendRecvFileModule(void); //send/recv
+
+int LoadContactListModule(void);// ui: clist
+int LoadOptionsModule(void); // ui: options dialog
+int LoadFindAddModule(void); // ui: search/add users
+int LoadSkinModule(void); // ui: skin
+int LoadHelpModule(void); // ui: help stuff
+int LoadUserInfoModule(void); // ui: user info
+int LoadHistoryModule(void); // ui: history viewer
+int LoadAwayMsgModule(void); // ui: setting away messages
+int LoadVisibilityModule(void); // ui: visibility control
+int LoadCLUIModule(void); // ui: CList UI
+int LoadPluginOptionsModule(void); // ui: plugin viewer
+int LoadAddContactModule(void); // ui: authcontrol contacts
+int LoadIdleModule(void); // rnd: report idle information
+int LoadAutoAwayModule(void); // ui: away
+int LoadUserOnlineModule(void); // ui: online alert
+int LoadUtilsModule(void); // ui: utils (has a few window classes, like HyperLink)
+int LoadCLCModule(void); // window class: CLC control
+int LoadButtonModule(void); // window class: button class
+int LoadContactsModule(void); // random: contact
+
+static int LoadDefaultModules(void)
+{
+ int *disableDefaultModule = 0;
+
+ //load order is very important for these
+ if(LoadSystemModule()) return 1;
+ if(LoadLangPackModule()) return 1; // langpack will be a system module in the new order so this is moved 'ere
+ if(LoadUtilsModule()) return 1; //order not important for this, but no dependencies and no point in pluginising
+ if(LoadNewPluginsModuleInfos()) return 1;
+ if(LoadProtocolsModule()) return 1;
+ if(LoadSkinModule()) return 1;
+ if(LoadButtonModule()) return 1;
+ if(LoadOptionsModule()) return 1;
+ if(LoadContactsModule()) return 1;
+ if(LoadContactListModule()) return 1;
+ if(LoadAddContactModule()) return 1;
+ if(LoadNewPluginsModule()) return 1; // will call Load() on everything, clist will load first
+
+ //this info will be available at LoadNewPluginsModule()
+ disableDefaultModule=(int*)CallService(MS_PLUGINS_GETDISABLEDEFAULTARRAY,0,0);
+ if(!disableDefaultModule[DEFMOD_PROTOCOLNETLIB]) if(LoadNetlibModule()) return 1;
+ //order becomes less important below here
+ if(!disableDefaultModule[DEFMOD_UIFINDADD]) if(LoadFindAddModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIUSERINFO]) if(LoadUserInfoModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRURL]) if(LoadSendRecvUrlModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SREMAIL]) if(LoadSendRecvEMailModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRAUTH]) if(LoadSendRecvAuthModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRFILE]) if(LoadSendRecvFileModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIHELP]) if(LoadHelpModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIHISTORY]) if(LoadHistoryModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDIDLE]) if(LoadIdleModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDAUTOAWAY]) if(LoadAutoAwayModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDUSERONLINE]) if(LoadUserOnlineModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_SRAWAY]) if(LoadAwayMsgModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_RNDIGNORE]) if(LoadIgnoreModule()) return 1;
+ if(!disableDefaultModule[DEFMOD_UIVISIBILITY]) if(LoadVisibilityModule()) return 1;
+ //if(!disableDefaultModule[DEFMOD_UIPLUGINOPTS]) if(LoadPluginOptionsModule()) return 1;
+ return 0;
+}
+
+int InitialiseModularEngine(void)
+{
+ hookCount=serviceCount=0;
+ hook=NULL;
+ service=NULL;
+ InitializeCriticalSection(&csHooks);
+ InitializeCriticalSection(&csServices);
+
+ mainThreadId=GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hMainThread,THREAD_SET_CONTEXT,FALSE,0);
+
+ hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE);
+ return LoadDefaultModules();
+}
+
+void DestroyingModularEngine(void)
+{
+ return;
+}
+
+void DestroyModularEngine(void)
+{
+ int i;
+ for(i=0;i<hookCount;i++)
+ if(hook[i].subscriberCount) mir_free(hook[i].subscriber);
+ if(hookCount) mir_free(hook);
+ if(serviceCount) mir_free(service);
+ DeleteCriticalSection(&csHooks);
+ DeleteCriticalSection(&csServices);
+ CloseHandle(hMainThread);
+}
+
+
+#if __GNUC__
+#define NOINLINEASM
+#endif
+
+DWORD NameHashFunction(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined NOINLINEASM
+ __asm { //this breaks if szStr is empty
+ xor edx,edx
+ xor eax,eax
+ mov esi,szStr
+ mov al,[esi]
+ xor cl,cl
+ lph_top: //only 4 of 9 instructions in here don't use AL, so optimal pipe use is impossible
+ xor edx,eax
+ inc esi
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ add cl,5
+ test al,al
+ rol eax,cl //rol is u-pipe only, but pairable
+ //rol doesn't touch z-flag
+ jnz lph_top //5 clock tick loop. not bad.
+
+ xor eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i++) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) hash^=(szStr[i]>>(32-shift))&0x7F;
+ shift=(shift+5)&0x1F;
+ }
+ return hash;
+#endif
+}
+
+///////////////////////////////HOOKS
+
+static int FindHookByName(const char *name)
+{
+ int i;
+
+ for(i=0;i<hookCount;i++)
+ if(!strcmp(hook[i].name,name)) return i;
+ return -1;
+}
+
+static int FindHookByHashAndName(DWORD Hash, const char *name)
+{
+ int i;
+ for (i=0; i<hookCount; i++)
+ if (hook[i].hookHash==Hash)
+ {
+ if (!strcmp(hook[i].name, name)) return i;
+ }
+ return -1;
+}
+
+HANDLE CreateHookableEvent(const char *name)
+{
+ DWORD Hash = NameHashFunction(name);
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ //if(FindHookByName(name)!=-1) {LeaveCriticalSection(&csHooks); return NULL;}
+ if (FindHookByHashAndName(Hash, name) != -1)
+ {
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook=(THookList*)mir_realloc(hook,sizeof(THookList)*(hookCount+1));
+ strcpy(hook[hookCount].name,name);
+ hook[hookCount].hookHash=Hash;
+ hook[hookCount].subscriberCount=0;
+ hook[hookCount].subscriber=NULL;
+ hook[hookCount].pfnHook=NULL;
+ hookCount++;
+ ret=(HANDLE)hookCount;
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+int DestroyHookableEvent(HANDLE hEvent)
+{
+ int hookId=(int)hEvent-1;
+ EnterCriticalSection(&csHooks);
+ if(hookId>=hookCount || hookId<0) {LeaveCriticalSection(&csHooks); return 1;}
+ if(hook[hookId].name[0]==0) {LeaveCriticalSection(&csHooks); return 1;}
+ hook[hookId].name[0]=0;
+ if(hook[hookId].subscriberCount) {
+ mir_free(hook[hookId].subscriber);
+ hook[hookId].subscriber=NULL;
+ hook[hookId].subscriberCount=0;
+ }
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook)
+{
+ int hookId = (int) hEvent - 1;
+ if ( hookId < 0 || hookId >= hookCount ) return 1;
+ EnterCriticalSection(&csHooks);
+ hook[hookId].pfnHook = pfnHook;
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+static int CallHookSubscribers(int hookId,WPARAM wParam,LPARAM lParam)
+{
+ int i,returnVal=0;
+
+ EnterCriticalSection(&csHooks);
+ if(hookId>=hookCount || hookId<0 || hook[hookId].name[0]==0) returnVal=-1;
+ else {
+ //NOTE: We've got the critical section while all this lot are called. That's mostly safe, though.
+ for(i=0;i<hook[hookId].subscriberCount;i++) {
+ if(hook[hookId].subscriber[i].pfnHook!=NULL) {
+ returnVal=hook[hookId].subscriber[i].pfnHook(wParam,lParam);
+ if( returnVal ) break;
+ }
+ else if(hook[hookId].subscriber[i].hwnd!=NULL) {
+ returnVal=SendMessage(hook[hookId].subscriber[i].hwnd,hook[hookId].subscriber[i].message,wParam,lParam);
+ if( returnVal ) break;
+ }//if
+ }//for
+ // check for no hooks and call the default hook if any
+ if ( hook[hookId].subscriberCount == 0 && hook[hookId].pfnHook != 0 ) returnVal = hook[hookId].pfnHook(wParam,lParam);
+ }
+ LeaveCriticalSection(&csHooks);
+ return returnVal;
+}
+
+static void CALLBACK HookToMainAPCFunc(DWORD dwParam)
+{
+ THookToMainThreadItem *item=(THookToMainThreadItem*)dwParam;
+
+ item->result=CallHookSubscribers(item->hookId,item->wParam,item->lParam);
+ SetEvent(item->hDoneEvent);
+ return;
+}
+
+int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam)
+{
+ extern HWND hAPCWindow;
+
+ if(GetCurrentThreadId()!=mainThreadId) {
+ THookToMainThreadItem item;
+
+ item.hDoneEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ item.hookId=(int)hEvent-1;
+ item.wParam=wParam;
+ item.lParam=lParam;
+
+ QueueUserAPC(HookToMainAPCFunc,hMainThread,(DWORD)&item);
+ PostMessage(hAPCWindow,WM_NULL,0,0); // let it process APC even if we're in a common dialog
+ WaitForSingleObject(item.hDoneEvent,INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+ else
+ return CallHookSubscribers((int)hEvent-1,wParam,lParam);
+}
+
+HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc)
+{
+ int hookId;
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ hookId=FindHookByName(name);
+ if(hookId==-1) {
+#ifdef _DEBUG
+ OutputDebugStringA("Attempt to hook: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+#endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook[hookId].subscriber=(THookSubscriber*)mir_realloc(hook[hookId].subscriber,sizeof(THookSubscriber)*(hook[hookId].subscriberCount+1));
+ hook[hookId].subscriber[hook[hookId].subscriberCount].pfnHook = hookProc;
+ hook[hookId].subscriber[hook[hookId].subscriberCount].hOwner = GetInstByAddress(hookProc);
+ hook[hookId].subscriber[hook[hookId].subscriberCount].hwnd = NULL;
+ hook[hookId].subscriberCount++;
+
+ ret=(HANDLE)((hookId<<16)|hook[hookId].subscriberCount);
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message)
+{
+ int hookId;
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ hookId=FindHookByName(name);
+ if(hookId==-1) {
+#ifdef _DEBUG
+ MessageBoxA(NULL,"Attempt to hook non-existant event",name,MB_OK);
+#endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook[hookId].subscriber=(THookSubscriber*)mir_realloc(hook[hookId].subscriber,sizeof(THookSubscriber)*(hook[hookId].subscriberCount+1));
+ hook[hookId].subscriber[hook[hookId].subscriberCount].pfnHook=NULL;
+ hook[hookId].subscriber[hook[hookId].subscriberCount].hwnd=hwnd;
+ hook[hookId].subscriber[hook[hookId].subscriberCount].message=message;
+ hook[hookId].subscriberCount++;
+ ret=(HANDLE)((hookId<<16)|hook[hookId].subscriberCount);
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+int UnhookEvent(HANDLE hHook)
+{
+ int hookId=(int)hHook>>16;
+ int subscriberId=((int)hHook&0xFFFF)-1;
+
+ EnterCriticalSection(&csHooks);
+ if(hookId>=hookCount || hookId<0) {LeaveCriticalSection(&csHooks); return 1;}
+ if(hook[hookId].name[0]==0) {LeaveCriticalSection(&csHooks); return 1;}
+ if(subscriberId>=hook[hookId].subscriberCount || subscriberId<0) {LeaveCriticalSection(&csHooks); return 1;}
+ hook[hookId].subscriber[subscriberId].pfnHook=NULL;
+ hook[hookId].subscriber[subscriberId].hwnd=NULL;
+ while(hook[hookId].subscriberCount && hook[hookId].subscriber[hook[hookId].subscriberCount-1].pfnHook==NULL && hook[hookId].subscriber[hook[hookId].subscriberCount-1].hwnd==NULL)
+ hook[hookId].subscriberCount--;
+ if (hook[hookId].subscriberCount==0) {
+ if(hook[hookId].subscriber) mir_free(hook[hookId].subscriber);
+ hook[hookId].subscriber=NULL;
+ }
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+void KillModuleEventHooks( HINSTANCE hInst )
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for ( i = hookCount-1; i >= 0; i-- ) {
+ if ( hook[i].subscriberCount == 0 )
+ continue;
+
+ for ( j = hook[i].subscriberCount-1; j >= 0; j-- ) {
+ if ( hook[i].subscriber[j].hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( hook[i].subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A hook %08x for event '%s' was abnormally deleted because module '%s' didn't released it",
+ hook[i].subscriber[j].pfnHook, hook[i].name, szModuleName );
+ UnhookEvent(( HANDLE )(( i << 16 ) + j + 1 ));
+ if ( hook[i].subscriberCount == 0 )
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+/////////////////////SERVICES
+
+static __inline TServiceList *FindServiceByHash(DWORD hash)
+{
+ int first,last,mid;
+
+ if(serviceCount==0) return NULL;
+ first=0; last=serviceCount-1;
+ if(hash>=service[last].nameHash) {
+ if(hash==service[last].nameHash) return &service[last];
+ return NULL;
+ }
+ for(;;) {
+ mid=(first+last)>>1;
+ if(hash>service[mid].nameHash) {
+ if(last-first<=1) break;
+ first=mid;
+ }
+ else if(hash<service[mid].nameHash) {
+ if(last-first<=1) break;
+ last=mid;
+ }
+ else return &service[mid];
+ }
+ return NULL;
+}
+
+static __inline TServiceList *FindServiceByName(const char *name)
+{
+ return FindServiceByHash(NameHashFunction(name));
+}
+
+/* assume critical section csServices is owned */
+static int FindHashForService(DWORD hash, int * shift)
+{
+ int i=0;
+ unsigned int mid = 0;
+ unsigned int min = 0;
+ unsigned int max = serviceCount - 1;
+ if (serviceCount==0) {
+ if (shift) *shift=0;
+ return 0;
+ }
+ if ( serviceCount > 0 && hash > service[serviceCount - 1].nameHash) {
+ if (shift) *shift = 0;
+ return serviceCount;
+ }
+ if ( serviceCount > 2 )
+ {
+ for ( ; (max - min) > 1 ; )
+ {
+ mid = ( min + max ) >> 1;
+ if ( hash > service[mid].nameHash ) min = mid;
+ else if ( hash < service[mid].nameHash ) max = mid;
+ else return -1;
+ } // for
+ i = mid - 1;
+ }
+ /* its O(N) but we might reduce it to M=(log2 N), then looking for the hash is only O(2) */
+ for(; i < serviceCount ; i++) {
+ if ( hash <= service[i].nameHash ) break;
+ }
+ return i;
+}
+
+HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc)
+{
+ DWORD hash;
+ int i;
+ int shift = 1;
+#ifdef _DEBUG
+ if (name==NULL) {
+ MessageBoxA(0,"Someone tried to create a NULL'd service, see call stack for more info","",0);
+ DebugBreak();
+ return NULL;
+ }
+#else
+ if (name==NULL) return NULL;
+#endif
+ hash=NameHashFunction(name);
+ EnterCriticalSection(&csServices);
+ i=FindHashForService(hash,&shift);
+ if (i==-1) {
+ LeaveCriticalSection(&csServices);
+ return NULL;
+ }
+ service=(TServiceList*)mir_realloc(service,sizeof(TServiceList)*(serviceCount+1));
+ if ( serviceCount > 0 && shift) MoveMemory(service+i+1,service+i,sizeof(TServiceList)*(serviceCount-i));
+ strncpy(service[i].name,name,sizeof(service[i].name));
+ service[i].nameHash = hash;
+ service[i].pfnService = serviceProc;
+ service[i].hOwner = GetInstByAddress( serviceProc );
+ serviceCount++;
+ LeaveCriticalSection(&csServices);
+ return (HANDLE)hash;
+}
+
+int DestroyServiceFunction(HANDLE hService)
+{
+ TServiceList *pService;
+ int i;
+
+ EnterCriticalSection(&csServices);
+ pService=FindServiceByHash((DWORD)hService);
+ if(pService==NULL) {LeaveCriticalSection(&csServices); return 1;}
+ i=(int)(pService-service);
+ MoveMemory(service+i,service+i+1,sizeof(TServiceList)*(--serviceCount-i));
+ LeaveCriticalSection(&csServices);
+ return 0;
+}
+
+int ServiceExists(const char *name)
+{
+ int ret;
+ EnterCriticalSection(&csServices);
+ ret=FindServiceByName(name)!=NULL;
+ LeaveCriticalSection(&csServices);
+ return ret;
+}
+
+int CallService(const char *name,WPARAM wParam,LPARAM lParam)
+{
+ TServiceList *pService;
+ MIRANDASERVICE pfnService;
+
+#ifdef _DEBUG
+ if (name==NULL) {
+ MessageBoxA(0,"Someone tried to CallService(NULL,..) see stack trace for details","",0);
+ DebugBreak();
+ return CALLSERVICE_NOTFOUND;
+ }
+#else
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+#endif
+
+ EnterCriticalSection(&csServices);
+ pService=FindServiceByName(name);
+ if(pService==NULL) {
+ LeaveCriticalSection(&csServices);
+#ifdef _DEBUG
+ //MessageBoxA(NULL,"Attempt to call non-existant service",name,MB_OK);
+ OutputDebugStringA("Missing service called: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+#endif
+/* { MISSING_SERVICE_PARAMS params = { name, wParam, lParam };
+ int result = NotifyEventHooks(hMissingService,0,(LPARAM)¶ms);
+ if (result != 0)
+ return params.lParam;
+ } */
+ return CALLSERVICE_NOTFOUND;
+ }
+ pfnService=pService->pfnService;
+ LeaveCriticalSection(&csServices);
+ return ((int (*)(WPARAM,LPARAM))pfnService)(wParam,lParam);
+}
+
+static void CALLBACK CallServiceToMainAPCFunc(DWORD dwParam)
+{
+ TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam;
+ item->result = CallService(item->name, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+int CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
+{
+
+ extern HWND hAPCWindow;
+
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+ // the service is looked up within the main thread, since the time it takes
+ // for the APC queue to clear the service being called maybe removed.
+ // even thou it may exists before the call, the critsec can't be locked between calls.
+ if (GetCurrentThreadId() != mainThreadId) {
+ TServiceToMainThreadItem item;
+ item.wParam = wParam;
+ item.lParam = lParam;
+ item.name = name;
+ item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(CallServiceToMainAPCFunc, hMainThread, (DWORD) &item);
+ PostMessage(hAPCWindow,WM_NULL,0,0); // let this get processed in its own time
+ WaitForSingleObject(item.hDoneEvent, INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+
+ return CallService(name, wParam, lParam);
+}
+
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg)
+{
+ extern HWND hAPCWindow;
+ int r = 0;
+ r=QueueUserAPC((void (__stdcall *)(DWORD))func,hMainThread,(DWORD)arg);
+ PostMessage(hAPCWindow,WM_NULL,0,0);
+ return r;
+}
+
+void KillModuleServices( HINSTANCE hInst )
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for ( i = serviceCount-1; i >= 0; i-- ) {
+ if ( service[i].hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( service[i].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A service function '%s' was abnormally deleted because module '%s' didn't released it",
+ service[i].name, szModuleName );
+ DestroyServiceFunction(( HANDLE )service[i].nameHash );
+ } }
+
+ LeaveCriticalSection(&csServices);
+}
diff --git a/miranda-wine/src/core/modules.h b/miranda-wine/src/core/modules.h new file mode 100644 index 0000000..4e488d3 --- /dev/null +++ b/miranda-wine/src/core/modules.h @@ -0,0 +1,184 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+//Modules Core - Richard
+#ifndef MODULES_H_
+#define MODULES_H_
+
+/* MAXMODULELABELLENGTH
+The maximum allowed length of a 'name' parameter. Very likely to change with
+restructuring modules.c for performance.
+*/
+#define MAXMODULELABELLENGTH 64
+
+typedef int (*MIRANDAHOOK)(WPARAM,LPARAM);
+typedef int (*MIRANDASERVICE)(WPARAM,LPARAM);
+
+/**************************hook functions****************************/
+/* CreateHookableEvent
+Adds an named event to the list and returns a handle referring to it, or NULL
+on failure. Will be automatically destroyed on exit, or can be removed from the
+list earlier using DestroyHookableEvent()
+Will fail if the given name has already been used
+*/
+HANDLE CreateHookableEvent(const char *name);
+
+/* DestroyHookableEvent
+Removes the event hEvent from the list of events. All modules hooked to it are
+automatically unhooked. NotifyEventHooks() will fail if called with this hEvent
+again. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success, or nonzero if hEvent is invalid
+*/
+int DestroyHookableEvent(HANDLE hEvent);
+
+/* NotifyEventHooks
+Calls every module in turn that has hooked hEvent, using the parameters wParam
+and lParam. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success
+ -1 if hEvent is invalid
+ If one of the hooks returned nonzero to indicate abort, returns that abort
+ value immediately, without calling the rest of the hooks in the chain
+
+Notes on calling NotifyEventHooks() from a thread other than that which owns
+the main Miranda window:
+It works. The call is routed to the main thread and all hook subcribers are
+called in the context of the main thread. The thread which called
+NotifyHookEvents() is paused until all the processing is complete at which
+point it returns with the correct return value.
+This procedure requires more than one wait object so naturally there are
+possibilities for deadlocks, but not many.
+Calling NotifyEventHooks() from other than the main thread will be
+considerably slower than from the main thread, but will consume only slightly
+more actual CPU time, the rest will mostly be spent waiting for the main thread
+to return to the message loop so it can be interrupted neatly.
+*/
+int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam);
+
+/*
+ hEvent : a HANDLE which has been returned by CreateHookableEvent()
+ pfnHook: a function pointer (MIRANDAHOOK) which is called when there are no hooks.
+ Affect: This core service allows hooks to have a 'default' hook which is called
+ when no one has hooked the given event, this allows hook creators to add default
+ processing which is ONLY CALLED when no one else has HookEvent()'d
+ Notes: The return value from pfnHook() is returned to NotifyEventHooks()
+ Returns: 0 on success, non zero on failure
+ Version: 0.3.4+ (2004/09/15)
+*/
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook);
+
+/* HookEvent
+Adds a new hook to the chain 'name', to be called when the hook owner calls
+NotifyEventHooks(). Returns NULL if name is not a valid event or a handle
+referring to the hook otherwise. Note that debug builds will warn with a
+MessageBoxA if a hook is attempted on an unknown event. All hooks will be
+automatically destroyed when their parent event is destroyed or the programme
+ends, but can be unhooked earlier using UnhookEvent(). hookProc() is defined as
+ int HookProc(WPARAM wParam,LPARAM lParam)
+where you can substitute your own name for HookProc. wParam and lParam are
+defined by the creator of the event when NotifyEventHooks() is called.
+The return value is 0 to continue processing the other hooks, or nonzero
+to stop immediately. This abort value is returned to the caller of
+NotifyEventHooks() and should not be -1 since that is a special return code
+for NotifyEventHooks() (see above)
+*/
+HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc);
+
+/* HookEventMessage
+Works as for HookEvent(), except that when the notifier is called a message is
+sent to a window, rather than a function being called.
+Note that SendMessage() is a decidedly slow function so please limit use of
+this function to events that are not called frequently, or to hooks that are
+only installed briefly
+The window procedure is called with the message 'message' and the wParam and
+lParam given to NotifyEventHooks(). The return value of SendMessage() is used
+in the same way as the return value in HookEvent().
+*/
+HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message);
+
+/* UnhookEvent
+Removes a hook from its event chain. It will no longer receive any events.
+hHook must have been returned by HookEvent() or HookEventMessage().
+Returns 0 on success or nonzero if hHook is invalid.
+*/
+int UnhookEvent(HANDLE hHook);
+
+
+/*************************service functions**************************/
+/* CreateServiceFunction
+Adds a new service function called 'name' to the global list and returns a
+handle referring to it. Service function handles are destroyed automatically
+on exit, but can be removed from the list earlier using
+DestroyServiceFunction()
+Returns NULL if name has already been used. serviceProc is defined by the
+caller as
+ int ServiceProc(WPARAM wParam,LPARAM lParam)
+where the creator publishes the meanings of wParam, lParam and the return value
+Service functions must not return CALLSERVICE_NOTFOUND since that would confuse
+callers of CallService().
+*/
+HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc);
+
+/* DestroyServiceFunction
+Removes the function associated with hService from the global service function
+list. Modules calling CallService() will fail if they try to call this
+service's name. hService must have been returned by CreateServiceFunction().
+Returns 0 on success or non-zero if hService is invalid.
+*/
+int DestroyServiceFunction(HANDLE hService);
+
+/* CallService
+Finds and calls the service function 'name' using the parameters wParam and
+lParam.
+Returns CALLSERVICE_NOTFOUND if no service function called 'name' has been
+created, or the value the service function returned otherwise.
+*/
+#define CALLSERVICE_NOTFOUND ((int)0x80000000)
+int CallService(const char *name,WPARAM wParam,LPARAM lParam);
+
+/* ServiceExists
+Finds if a service with the given name exists
+Returns nonzero if the service was found, and zero if it was not
+*/
+int ServiceExists(const char *name);
+
+/* CallServiceSync
+Calls a given service executed within the context of the main thread
+only useful to multi threaded modules calling thread unsafe services!
+*/
+int CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam);
+
+/* CallFunctionAsync
+Calls a given function pointer, it doesn't go thru the core at all, it is
+just a wrapper around QueueUserAPC() and other workarounds to make APC
+work even if there are non APC message loops, this allows plugins who
+need this feature to get it without recoding it themselves.
+
+The function 'func' will always be called from the main thread in idle time even
+if it is invokved from a worker thread, 'arg' must not be on the stack.
+
+Returns nonzero on success, zero on failure
+
+added during 0.3.4+ (2004/08/14)
+*/
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg);
+
+#endif // MODULES_H_
diff --git a/miranda-wine/src/modules/addcontact/addcontact.c b/miranda-wine/src/modules/addcontact/addcontact.c new file mode 100644 index 0000000..9c441f8 --- /dev/null +++ b/miranda-wine/src/modules/addcontact/addcontact.c @@ -0,0 +1,235 @@ +/*
+Miranda ICQ: the free icq client for MS Windows
+Copyright (C) 2000-2 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "commonheaders.h"
+
+BOOL CALLBACK AddContactDlgProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam)
+{
+ ADDCONTACTSTRUCT *acs;
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char idstr[4],szUin[10];
+ DBVARIANT dbv;
+ int groupId;
+ DWORD flags=0;
+
+ acs=(ADDCONTACTSTRUCT *)lparam;
+ SetWindowLong(hdlg,GWL_USERDATA,(LONG)acs);
+
+ TranslateDialogDefault(hdlg);
+ SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT)));
+ if(acs->handleType==HANDLE_EVENT)
+ {
+ DBEVENTINFO dbei;
+ DWORD dwUin;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=sizeof(DWORD);
+ dbei.pBlob=(PBYTE)&dwUin;
+ CallService(MS_DB_EVENT_GET,(WPARAM)acs->handle,(LPARAM)&dbei);
+ _ltoa(dwUin,szUin,10);
+ acs->szProto = dbei.szModule;
+ }
+ { TCHAR* szName;
+ if ( acs->handleType == HANDLE_CONTACT )
+ szName = (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)acs->handle, GCDNF_TCHAR );
+ else {
+ char* p = (acs->handleType == HANDLE_EVENT) ? szUin : acs->psr->nick;
+ #if defined( _UNICODE )
+ szName =( TCHAR* )alloca( 128*sizeof( TCHAR ));
+ MultiByteToWideChar( CP_ACP, 0, p, -1, szName, 128 );
+ #else
+ szName = p;
+ #endif
+ }
+
+ if ( lstrlen( szName )) {
+ TCHAR szTitle[128];
+ mir_sntprintf( szTitle, SIZEOF(szTitle), TranslateT("Add %s"), szName );
+ SetWindowText( hdlg, szTitle );
+ }
+ else SetWindowText( hdlg, TranslateT("Add Contact"));
+ }
+
+ if ( acs->handleType == HANDLE_CONTACT && acs->handle ) {
+ if ( acs->szProto == NULL || (acs->szProto != NULL && strcmp(acs->szProto,"") == 0) )
+ acs->szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)acs->handle,0);
+ }
+
+ for(groupId=0;groupId<999;groupId++)
+ {
+ _itoa(groupId,idstr,10);
+ if(DBGetContactSettingTString(NULL,"CListGroups",idstr,&dbv)) break;
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_ADDSTRING,0,(LPARAM)(dbv.ptszVal+1));
+ DBFreeVariant(&dbv);
+ }
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_INSERTSTRING,0,(LPARAM)TranslateT("None"));
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_SETCURSEL,0,0);
+ /* acs->szProto may be NULL don't expect it */
+ if (acs->szProto) flags=CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ else flags=0;
+ if (flags&PF4_FORCEADDED) { // force you were added requests for this protocol
+ CheckDlgButton(hdlg,IDC_ADDED,BST_CHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_ADDED),FALSE);
+ }
+ if (flags&PF4_FORCEAUTH) { // force auth requests for this protocol
+ CheckDlgButton(hdlg,IDC_AUTH,BST_CHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTH),FALSE);
+ }
+ if (flags&PF4_NOCUSTOMAUTH) {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),FALSE);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),FALSE);
+ }
+ SetDlgItemText(hdlg,IDC_AUTHREQ,TranslateT("Please authorize my request and add me to your contact list."));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ }
+ break;
+
+ case WM_COMMAND:
+ acs=(ADDCONTACTSTRUCT *)GetWindowLong(hdlg,GWL_USERDATA);
+
+ switch(LOWORD(wparam))
+ {
+ case IDC_AUTH:
+ {
+ DWORD flags=0;
+
+ flags=CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (flags&PF4_NOCUSTOMAUTH) {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),FALSE);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),FALSE);
+ }
+ else {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ }
+ }
+ break;
+ case IDOK:
+ {
+ HANDLE hcontact=INVALID_HANDLE_VALUE;
+ if(acs->handleType==HANDLE_EVENT)
+ {
+ DBEVENTINFO dbei;
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)acs->handle,(LPARAM)&dbei);
+ hcontact=(HANDLE)CallProtoService(dbei.szModule,PS_ADDTOLISTBYEVENT,0,(LPARAM)acs->handle);
+ }
+ else if(acs->handleType==HANDLE_SEARCHRESULT)
+ hcontact=(HANDLE)CallProtoService(acs->szProto,PS_ADDTOLIST,0,(LPARAM)acs->psr);
+
+ else if(acs->handleType==HANDLE_CONTACT)
+ hcontact=acs->handle;
+
+ if ( hcontact == NULL ) break;
+
+ { TCHAR szHandle[256];
+ if ( GetDlgItemText( hdlg, IDC_MYHANDLE, szHandle, SIZEOF(szHandle)))
+ DBWriteContactSettingTString( hcontact, "CList", "MyHandle", szHandle );
+
+ GetDlgItemText( hdlg, IDC_GROUP, szHandle, SIZEOF(szHandle));
+ if ( lstrcmp( szHandle, TranslateT( "None" )))
+ DBWriteContactSettingTString( hcontact, "CList", "Group", szHandle );
+ }
+
+ if(IsDlgButtonChecked(hdlg,IDC_ADDED)) CallContactService(hcontact,PSS_ADDED,0,0);
+ if(IsDlgButtonChecked(hdlg,IDC_AUTH)) {
+ DWORD flags;
+ flags=CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (flags&PF4_NOCUSTOMAUTH) CallContactService(hcontact,PSS_AUTHREQUEST,0,(LPARAM)"");
+ else {
+ char szReason[256];
+
+ GetDlgItemTextA(hdlg,IDC_AUTHREQ,szReason,256);
+ CallContactService(hcontact,PSS_AUTHREQUEST,0,(LPARAM)szReason);
+ } }
+
+ DBDeleteContactSetting(hcontact,"CList","NotOnList");
+ }
+ // fall through
+ case IDCANCEL:
+ if (GetParent(hdlg)==NULL) DestroyWindow(hdlg);
+ else EndDialog(hdlg,0);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ /* if there is no parent for the dialog, its a modeless dialog and can't be killed using EndDialog() */
+ if(GetParent(hdlg)==NULL) DestroyWindow(hdlg);
+ else EndDialog(hdlg,0);
+ break;
+
+ case WM_DESTROY:
+ acs=(ADDCONTACTSTRUCT *)GetWindowLong(hdlg,GWL_USERDATA);
+ if (acs) {
+ if (acs->psr) {
+ if (acs->psr->nick) mir_free(acs->psr->nick);
+ if (acs->psr->firstName) mir_free(acs->psr->firstName);
+ if (acs->psr->lastName) mir_free(acs->psr->lastName);
+ if (acs->psr->email) mir_free(acs->psr->email);
+ mir_free(acs->psr);
+ }
+ mir_free(acs);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+int AddContactDialog(WPARAM wParam,LPARAM lParam)
+{
+ ADDCONTACTSTRUCT *acs;
+ if (lParam) {
+ acs=mir_alloc(sizeof(ADDCONTACTSTRUCT));
+ memmove(acs,(ADDCONTACTSTRUCT*)lParam,sizeof(ADDCONTACTSTRUCT));
+ if (acs->psr) {
+ PROTOSEARCHRESULT *psr;
+ /* bad! structures that are bigger than psr will cause crashes if they define pointers within unreachable structural space */
+ psr=mir_alloc(acs->psr->cbSize);
+ memmove(psr,acs->psr,acs->psr->cbSize);
+ if (psr->nick) psr->nick=mir_strdup(psr->nick);
+ if (psr->firstName) psr->firstName=mir_strdup(psr->firstName);
+ if (psr->lastName) psr->lastName=mir_strdup(psr->lastName);
+ if (psr->email) psr->email=mir_strdup(psr->email);
+ acs->psr=psr;
+ /* copied the passed acs structure, the psr structure with, the pointers within that */
+ } //if
+ if (wParam) {
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ADDCONTACT),(HWND)wParam,AddContactDlgProc,(LPARAM)acs);
+ } else {
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ADDCONTACT),(HWND)wParam,AddContactDlgProc,(LPARAM)acs);
+ } //if
+ return 0;
+ }
+ return 1;
+}
+
+int LoadAddContactModule(void)
+{
+ CreateServiceFunction(MS_ADDCONTACT_SHOW,AddContactDialog);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/autoaway/autoaway.c b/miranda-wine/src/modules/autoaway/autoaway.c new file mode 100644 index 0000000..5cb10ce --- /dev/null +++ b/miranda-wine/src/modules/autoaway/autoaway.c @@ -0,0 +1,82 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#define AA_MODULE "AutoAway"
+
+static void AutoAwaySetProtocol(const char * proto, unsigned status)
+{
+ char * awayMsg = (char *) CallService(MS_AWAYMSG_GETSTATUSMSG, (WPARAM) status, 0);
+ CallProtoService(proto, PS_SETSTATUS, status, 0);
+ if ( awayMsg != NULL ) {
+ if (CallProtoService(proto,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGSEND)
+ CallProtoService(proto, PS_SETAWAYMSG, status, (LPARAM) awayMsg);
+ miranda_sys_free(awayMsg);
+ }
+}
+
+static int AutoAwayEvent(WPARAM wParam, LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR **proto=0;
+ int protoCount=0;
+ int j;
+ MIRANDA_IDLE_INFO mii;
+ int status;
+
+ mii.cbSize = sizeof(mii);
+ CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii);
+ if (mii.aaStatus==0) return 0;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&proto);
+ for (j=0; j<protoCount; j++) {
+ if ( proto[j]->type == PROTOTYPE_PROTOCOL ) {
+ int statusbits = CallProtoService(proto[j]->szName, PS_GETCAPS, PFLAGNUM_2, 0);
+ int currentstatus = CallProtoService(proto[j]->szName, PS_GETSTATUS, 0, 0);
+ status = mii.aaStatus;
+ if ( !(statusbits & Proto_Status2Flag(status)) ) {
+ // the protocol doesnt support the given status
+ if ( statusbits & Proto_Status2Flag(ID_STATUS_AWAY) ) status=ID_STATUS_AWAY;
+ else {
+ // the proto doesnt support user mode or even away, bail.
+ continue;
+ }
+ }
+ if ( currentstatus >= ID_STATUS_ONLINE && currentstatus != ID_STATUS_INVISIBLE ) {
+ if ( (lParam&IDF_ISIDLE) && ( currentstatus == ID_STATUS_ONLINE || currentstatus == ID_STATUS_FREECHAT )) {
+ DBWriteContactSettingByte(NULL,AA_MODULE,proto[j]->szName,1);
+ AutoAwaySetProtocol(proto[j]->szName, status);
+ } else if ( !(lParam&IDF_ISIDLE) && DBGetContactSettingByte(NULL,AA_MODULE,proto[j]->szName,0) ) {
+ // returning from idle and this proto was set away, set it back
+ DBWriteContactSettingByte(NULL,AA_MODULE,proto[j]->szName,0);
+ if ( !mii.aaLock ) AutoAwaySetProtocol(proto[j]->szName, ID_STATUS_ONLINE);
+ } } } }
+
+ return 0;
+}
+
+int LoadAutoAwayModule(void)
+{
+ HookEvent(ME_IDLE_CHANGED, AutoAwayEvent);
+ return 0;
+}
+
+
diff --git a/miranda-wine/src/modules/button/button.c b/miranda-wine/src/modules/button/button.c new file mode 100644 index 0000000..e5b203c --- /dev/null +++ b/miranda-wine/src/modules/button/button.c @@ -0,0 +1,540 @@ +/*
+Miranda IM
+Copyright (C) 2002 Robert Rainwater
+
+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 "commonheaders.h"
+
+// TODO:
+// - Support for bitmap buttons (simple call to DrawIconEx())
+
+static LRESULT CALLBACK MButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+typedef struct {
+ HWND hwnd;
+ int stateId; // button state
+ int focus; // has focus (1 or 0)
+ HFONT hFont; // font
+ HICON arrow; // uses down arrow
+ int defbutton; // default button
+ HICON hIcon;
+ HBITMAP hBitmap;
+ int pushBtn;
+ int pbState;
+ HANDLE hThemeButton;
+ HANDLE hThemeToolbar;
+ char cHot;
+ int flatBtn;
+} MButtonCtrl;
+
+
+// External theme methods and properties
+static HMODULE themeAPIHandle = NULL; // handle to uxtheme.dll
+static HANDLE (WINAPI *MyOpenThemeData)(HWND,LPCWSTR);
+static HRESULT (WINAPI *MyCloseThemeData)(HANDLE);
+static BOOL (WINAPI *MyIsThemeBackgroundPartiallyTransparent)(HANDLE,int,int);
+static HRESULT (WINAPI *MyDrawThemeParentBackground)(HWND,HDC,RECT *);
+static HRESULT (WINAPI *MyDrawThemeBackground)(HANDLE,HDC,int,int,const RECT *,const RECT *);
+static HRESULT (WINAPI *MyDrawThemeText)(HANDLE,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *);
+
+static CRITICAL_SECTION csTips;
+static HWND hwndToolTips = NULL;
+
+int UnloadButtonModule(WPARAM wParam, LPARAM lParam) {
+ DeleteCriticalSection(&csTips);
+ return 0;
+}
+
+int LoadButtonModule(void) {
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDABUTTONCLASS;
+ wc.lpfnWndProc = MButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MButtonCtrl*);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS;
+ RegisterClassEx(&wc);
+ InitializeCriticalSection(&csTips);
+ HookEvent(ME_SYSTEM_SHUTDOWN, UnloadButtonModule);
+ return 0;
+}
+
+// Used for our own cheap TrackMouseEvent
+#define BUTTON_POLLID 100
+#define BUTTON_POLLDELAY 50
+
+#define MGPROC(x) GetProcAddress(themeAPIHandle,x)
+static int ThemeSupport() {
+ if (IsWinVerXPPlus()) {
+ if (!themeAPIHandle) {
+ themeAPIHandle = GetModuleHandleA("uxtheme");
+ if (themeAPIHandle) {
+ MyOpenThemeData = (HANDLE (WINAPI *)(HWND,LPCWSTR))MGPROC("OpenThemeData");
+ MyCloseThemeData = (HRESULT (WINAPI *)(HANDLE))MGPROC("CloseThemeData");
+ MyIsThemeBackgroundPartiallyTransparent = (BOOL (WINAPI *)(HANDLE,int,int))MGPROC("IsThemeBackgroundPartiallyTransparent");
+ MyDrawThemeParentBackground = (HRESULT (WINAPI *)(HWND,HDC,RECT *))MGPROC("DrawThemeParentBackground");
+ MyDrawThemeBackground = (HRESULT (WINAPI *)(HANDLE,HDC,int,int,const RECT *,const RECT *))MGPROC("DrawThemeBackground");
+ MyDrawThemeText = (HRESULT (WINAPI *)(HANDLE,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *))MGPROC("DrawThemeText");
+ }
+ }
+ // Make sure all of these methods are valid (i would hope either all or none work)
+ if (MyOpenThemeData
+ &&MyCloseThemeData
+ &&MyIsThemeBackgroundPartiallyTransparent
+ &&MyDrawThemeParentBackground
+ &&MyDrawThemeBackground
+ &&MyDrawThemeText) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void DestroyTheme(MButtonCtrl *ctl) {
+ if (ThemeSupport()) {
+ if (ctl->hThemeButton) {
+ MyCloseThemeData(ctl->hThemeButton);
+ ctl->hThemeButton = NULL;
+ }
+ if (ctl->hThemeToolbar) {
+ MyCloseThemeData(ctl->hThemeToolbar);
+ ctl->hThemeToolbar = NULL;
+ }
+ }
+}
+
+static void LoadTheme(MButtonCtrl *ctl) {
+ if (ThemeSupport()) {
+ DestroyTheme(ctl);
+ ctl->hThemeButton = MyOpenThemeData(ctl->hwnd,L"BUTTON");
+ ctl->hThemeToolbar = MyOpenThemeData(ctl->hwnd,L"TOOLBAR");
+ }
+}
+
+static int TBStateConvert2Flat(int state) {
+ switch(state) {
+ case PBS_NORMAL: return TS_NORMAL;
+ case PBS_HOT: return TS_HOT;
+ case PBS_PRESSED: return TS_PRESSED;
+ case PBS_DISABLED: return TS_DISABLED;
+ case PBS_DEFAULTED: return TS_NORMAL;
+ }
+ return TS_NORMAL;
+}
+
+static void PaintWorker(MButtonCtrl *ctl, HDC hdcPaint) {
+ if (hdcPaint) {
+ HDC hdcMem;
+ HBITMAP hbmMem;
+ HDC hOld;
+ RECT rcClient;
+
+ GetClientRect(ctl->hwnd, &rcClient);
+ hdcMem = CreateCompatibleDC(hdcPaint);
+ hbmMem = CreateCompatibleBitmap(hdcPaint, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
+ hOld = SelectObject(hdcMem, hbmMem);
+
+ // If its a push button, check to see if it should stay pressed
+ if (ctl->pushBtn && ctl->pbState) ctl->stateId = PBS_PRESSED;
+
+ // Draw the flat button
+ if (ctl->flatBtn) {
+ if (ctl->hThemeToolbar) {
+ int state = IsWindowEnabled(ctl->hwnd)?(ctl->stateId==PBS_NORMAL&&ctl->defbutton?PBS_DEFAULTED:ctl->stateId):PBS_DISABLED;
+ if (MyIsThemeBackgroundPartiallyTransparent(ctl->hThemeToolbar, TP_BUTTON, TBStateConvert2Flat(state))) {
+ MyDrawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ MyDrawThemeBackground(ctl->hThemeToolbar, hdcMem, TP_BUTTON, TBStateConvert2Flat(state), &rcClient, &rcClient);
+ }
+ else {
+ HBRUSH hbr;
+
+ if (ctl->stateId==PBS_PRESSED||ctl->stateId==PBS_HOT)
+ hbr = GetSysColorBrush(COLOR_3DLIGHT);
+ else {
+ HWND hwndParent = GetParent(ctl->hwnd);
+ HDC dc = GetDC(hwndParent);
+ HBRUSH oldBrush = GetCurrentObject( dc, OBJ_BRUSH );
+ hbr = (HBRUSH)SendMessage(hwndParent, WM_CTLCOLORDLG, (WPARAM)dc, (LPARAM)hwndParent);
+ SelectObject(dc,oldBrush);
+ ReleaseDC(hwndParent,dc);
+ }
+ if (hbr) {
+ FillRect(hdcMem, &rcClient, hbr);
+ DeleteObject(hbr);
+ }
+ if (ctl->stateId==PBS_HOT||ctl->focus) {
+ if (ctl->pbState)
+ DrawEdge(hdcMem,&rcClient, EDGE_ETCHED,BF_RECT|BF_SOFT);
+ else DrawEdge(hdcMem,&rcClient, BDR_RAISEDOUTER,BF_RECT|BF_SOFT|BF_FLAT);
+ }
+ else if (ctl->stateId==PBS_PRESSED)
+ DrawEdge(hdcMem, &rcClient, BDR_SUNKENOUTER,BF_RECT|BF_SOFT);
+ }
+ }
+ else {
+ // Draw background/border
+ if (ctl->hThemeButton) {
+ int state = IsWindowEnabled(ctl->hwnd)?(ctl->stateId==PBS_NORMAL&&ctl->defbutton?PBS_DEFAULTED:ctl->stateId):PBS_DISABLED;
+ if (MyIsThemeBackgroundPartiallyTransparent(ctl->hThemeButton, BP_PUSHBUTTON, state)) {
+ MyDrawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ MyDrawThemeBackground(ctl->hThemeButton, hdcMem, BP_PUSHBUTTON, state, &rcClient, &rcClient);
+ }
+ else {
+ UINT uState = DFCS_BUTTONPUSH|((ctl->stateId==PBS_HOT)?DFCS_HOT:0)|((ctl->stateId == PBS_PRESSED)?DFCS_PUSHED:0);
+ if (ctl->defbutton&&ctl->stateId==PBS_NORMAL) uState |= DLGC_DEFPUSHBUTTON;
+ DrawFrameControl(hdcMem, &rcClient, DFC_BUTTON, uState);
+ }
+
+ // Draw focus rectangle if button has focus
+ if (ctl->focus) {
+ RECT focusRect = rcClient;
+ InflateRect(&focusRect, -3, -3);
+ DrawFocusRect(hdcMem, &focusRect);
+ }
+ }
+
+ // If we have an icon or a bitmap, ignore text and only draw the image on the button
+ if (ctl->hIcon) {
+ int ix = (rcClient.right-rcClient.left)/2 - (GetSystemMetrics(SM_CXSMICON)/2);
+ int iy = (rcClient.bottom-rcClient.top)/2 - (GetSystemMetrics(SM_CYSMICON)/2);
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ {
+ HIMAGELIST hImageList;
+ HICON hIconNew;
+
+ hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus()? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, ctl->hIcon);
+ hIconNew = ImageList_GetIcon(hImageList, 0, ILD_NORMAL);
+ DrawState(hdcMem,NULL,NULL,(LPARAM)hIconNew,0,ix,iy,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),IsWindowEnabled(ctl->hwnd)?DST_ICON|DSS_NORMAL:DST_ICON|DSS_DISABLED);
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ DestroyIcon(hIconNew);
+ }
+ }
+ else if (ctl->hBitmap) {
+ BITMAP bminfo;
+ int ix,iy;
+
+ GetObject(ctl->hBitmap, sizeof(bminfo), &bminfo);
+ ix = (rcClient.right-rcClient.left)/2 - (bminfo.bmWidth/2);
+ iy = (rcClient.bottom-rcClient.top)/2 - (bminfo.bmHeight/2);
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ DrawState(hdcMem,NULL,NULL,(LPARAM)ctl->hBitmap,0,ix,iy,bminfo.bmWidth,bminfo.bmHeight,IsWindowEnabled(ctl->hwnd)?DST_BITMAP:DST_BITMAP|DSS_DISABLED);
+ }
+ else if (GetWindowTextLength(ctl->hwnd)) {
+ // Draw the text and optinally the arrow
+ TCHAR szText[MAX_PATH];
+ SIZE sz;
+ RECT rcText;
+ HFONT hOldFont;
+
+ CopyRect(&rcText, &rcClient);
+ GetWindowText(ctl->hwnd, szText, SIZEOF(szText));
+ SetBkMode(hdcMem, TRANSPARENT);
+ hOldFont = SelectObject(hdcMem, ctl->hFont);
+ // XP w/themes doesn't used the glossy disabled text. Is it always using COLOR_GRAYTEXT? Seems so.
+ SetTextColor(hdcMem, IsWindowEnabled(ctl->hwnd)||!ctl->hThemeButton?GetSysColor(COLOR_BTNTEXT):GetSysColor(COLOR_GRAYTEXT));
+ GetTextExtentPoint32(hdcMem, szText, lstrlen(szText), &sz);
+ if (ctl->cHot) {
+ SIZE szHot;
+
+ GetTextExtentPoint32 (hdcMem, _T("&"), 1, &szHot);
+ sz.cx -= szHot.cx;
+ }
+ if (ctl->arrow) {
+ DrawState(hdcMem,NULL,NULL,(LPARAM)ctl->arrow,0,rcClient.right-rcClient.left-5-GetSystemMetrics(SM_CXSMICON)+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),(rcClient.bottom-rcClient.top)/2-GetSystemMetrics(SM_CYSMICON)/2+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),IsWindowEnabled(ctl->hwnd)?DST_ICON:DST_ICON|DSS_DISABLED);
+ }
+ SelectObject(hdcMem, ctl->hFont);
+ DrawState(hdcMem,NULL,NULL,(LPARAM)szText,0,(rcText.right-rcText.left-sz.cx)/2+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),ctl->hThemeButton?(rcText.bottom-rcText.top-sz.cy)/2:(rcText.bottom-rcText.top-sz.cy)/2-(ctl->stateId==PBS_PRESSED?0:1),sz.cx,sz.cy,IsWindowEnabled(ctl->hwnd)||ctl->hThemeButton?DST_PREFIXTEXT|DSS_NORMAL:DST_PREFIXTEXT|DSS_DISABLED);
+ SelectObject(hdcMem, hOldFont);
+ }
+ BitBlt(hdcPaint, 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hOld);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+
+ }
+}
+
+static LRESULT CALLBACK MButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
+ MButtonCtrl* bct = (MButtonCtrl *)GetWindowLong(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ {
+ SetWindowLong(hwndDlg, GWL_STYLE, GetWindowLong(hwndDlg, GWL_STYLE)|BS_OWNERDRAW);
+ bct = mir_alloc(sizeof(MButtonCtrl));
+ if (bct==NULL) return FALSE;
+ bct->hwnd = hwndDlg;
+ bct->stateId = PBS_NORMAL;
+ bct->focus = 0;
+ bct->hFont = GetStockObject(DEFAULT_GUI_FONT);
+ bct->arrow = NULL;
+ bct->defbutton = 0;
+ bct->hIcon = NULL;
+ bct->hBitmap = NULL;
+ bct->pushBtn = 0;
+ bct->pbState = 0;
+ bct->hThemeButton = NULL;
+ bct->hThemeToolbar = NULL;
+ bct->cHot = 0;
+ bct->flatBtn = 0;
+ LoadTheme(bct);
+ SetWindowLong(hwndDlg, 0, (LONG)bct);
+ if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
+ return TRUE;
+ }
+ case WM_DESTROY:
+ {
+ if (bct) {
+ EnterCriticalSection(&csTips);
+ if (hwndToolTips) {
+ TOOLINFO ti;
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti)==0) {
+ DestroyWindow(hwndToolTips);
+ hwndToolTips = NULL;
+ }
+ }
+ LeaveCriticalSection(&csTips);
+ DestroyTheme(bct);
+ mir_free(bct);
+ }
+ SetWindowLong(hwndDlg,0,(LONG)NULL);
+ break; // DONT! fall thru
+ }
+ case WM_SETTEXT:
+ {
+ bct->cHot = 0;
+ if ( lParam != 0 ) {
+ TCHAR *tmp = ( TCHAR* )lParam;
+ while (*tmp) {
+ if (*tmp=='&' && *(tmp+1)) {
+ bct->cHot = _tolower(*(tmp+1));
+ break;
+ }
+ tmp++;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_SYSKEYUP:
+ if (bct->stateId!=PBS_DISABLED && bct->cHot && bct->cHot == tolower((int)wParam)) {
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+ case WM_THEMECHANGED: {
+ // themed changed, reload theme object
+ LoadTheme(bct);
+ InvalidateRect(bct->hwnd, NULL, TRUE); // repaint it
+ break;
+ }
+ case WM_SETFONT: // remember the font so we can use it later
+ {
+ bct->hFont = (HFONT)wParam; // maybe we should redraw?
+ break;
+ }
+ case WM_NCPAINT:
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdcPaint;
+
+ hdcPaint = BeginPaint(hwndDlg, &ps);
+ if (hdcPaint) {
+ PaintWorker(bct, hdcPaint);
+ EndPaint(hwndDlg, &ps);
+ }
+ break;
+ }
+ case BM_SETIMAGE:
+ if (wParam == IMAGE_ICON) {
+ bct->hIcon = (HICON)lParam;
+ bct->hBitmap = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ else if (wParam == IMAGE_BITMAP) {
+ bct->hBitmap = (HBITMAP)lParam;
+ bct->hIcon = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ case BM_SETCHECK:
+ if (!bct->pushBtn) break;
+ if (wParam == BST_CHECKED) {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ }
+ else if (wParam == BST_UNCHECKED) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BM_GETCHECK:
+ if (bct->pushBtn) {
+ return bct->pbState?BST_CHECKED:BST_UNCHECKED;
+ }
+ return 0;
+ case BUTTONSETARROW: // turn arrow on/off
+ if (wParam) {
+ if (!bct->arrow)
+ bct->arrow = (HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ }
+ else {
+ if (bct->arrow) {
+ DestroyIcon(bct->arrow);
+ bct->arrow = NULL;
+ }
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETDEFAULT:
+ bct->defbutton = wParam?1:0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASPUSHBTN:
+ bct->pushBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASFLATBTN:
+ bct->flatBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONADDTOOLTIP:
+ {
+ TOOLINFOA ti;
+
+ if (!(char*)wParam) break;
+ EnterCriticalSection(&csTips);
+ if (!hwndToolTips)
+ hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
+ ti.uId = (UINT)bct->hwnd;
+ ti.lpszText=(char*)wParam;
+ SendMessageA( hwndToolTips, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+ LeaveCriticalSection(&csTips);
+ break;
+ }
+ case WM_SETFOCUS: // set keybord focus and redraw
+ bct->focus = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_KILLFOCUS: // kill focus and redraw
+ bct->focus = 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_WINDOWPOSCHANGED:
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_ENABLE: // windows tells us to enable/disable
+ {
+ bct->stateId = wParam?PBS_NORMAL:PBS_DISABLED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ }
+ case WM_MOUSELEAVE: // faked by the WM_TIMER
+ {
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ {
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_PRESSED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_LBUTTONUP:
+ {
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ }
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ if (msg==WM_LBUTTONUP) bct->stateId = PBS_HOT;
+ else bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Tell your daddy you got clicked.
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (bct->stateId == PBS_NORMAL) {
+ bct->stateId = PBS_HOT;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Call timer, used to start cheesy TrackMouseEvent faker
+ SetTimer(hwndDlg,BUTTON_POLLID,BUTTON_POLLDELAY,NULL);
+ break;
+ case WM_TIMER: // use a timer to check if they have did a mouseout
+ {
+ if (wParam==BUTTON_POLLID) {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(hwndDlg,&rc);
+ GetCursorPos(&pt);
+ if(!PtInRect(&rc,pt)) { // mouse must be gone, trigger mouse leave
+ PostMessage(hwndDlg,WM_MOUSELEAVE,0,0L);
+ KillTimer(hwndDlg,BUTTON_POLLID);
+ }
+ }
+ break;
+ }
+ case WM_ERASEBKGND:
+ return 1;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/miranda-wine/src/modules/clist/Docking.c b/miranda-wine/src/modules/clist/Docking.c new file mode 100644 index 0000000..f0a75de --- /dev/null +++ b/miranda-wine/src/modules/clist/Docking.c @@ -0,0 +1,293 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+#define WM_DOCKCALLBACK (WM_USER+121)
+#define WM_CREATEDOCKED (WM_USER+122)
+#define EDGESENSITIVITY 3
+
+#define DOCKED_NONE 0
+#define DOCKED_LEFT 1
+#define DOCKED_RIGHT 2
+static int docked;
+
+typedef HMONITOR WINAPI MyMonitorFromPoint(POINT, DWORD);
+typedef BOOL WINAPI MyGetMonitorInfo(HMONITOR, LPMONITORINFO);
+
+static void Docking_GetMonitorRectFromPoint(POINT pt, RECT * rc)
+{
+ HMODULE hUserInstance = GetModuleHandleA("user32");
+
+ MyMonitorFromPoint *LPMyMonitorFromPoint = (MyMonitorFromPoint *) GetProcAddress(hUserInstance, "MonitorFromPoint");
+ if (LPMyMonitorFromPoint) {
+ MONITORINFO monitorInfo;
+ HMONITOR hMonitor = LPMyMonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); // always returns a valid value
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+
+ if ((MyGetMonitorInfo *) GetProcAddress(hUserInstance, "GetMonitorInfoA") (hMonitor, &monitorInfo)) {
+ CopyMemory(rc, &monitorInfo.rcMonitor, sizeof(RECT));
+ return;
+ }
+ }
+
+ // "generic" win95/NT support, also serves as failsafe
+ rc->left = 0;
+ rc->top = 0;
+ rc->bottom = GetSystemMetrics(SM_CYSCREEN);
+ rc->right = GetSystemMetrics(SM_CXSCREEN);
+}
+
+static void Docking_GetMonitorRectFromWindow(HWND hWnd, RECT * rc)
+{
+ POINT ptWindow;
+ GetWindowRect(hWnd, rc);
+ ptWindow.x = rc->left;
+ ptWindow.y = rc->top;
+ Docking_GetMonitorRectFromPoint(ptWindow, rc);
+}
+
+static void Docking_AdjustPosition(HWND hwnd, RECT * rcDisplay, RECT * rc)
+{
+ APPBARDATA abd;
+
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = hwnd;
+ abd.uEdge = docked == DOCKED_LEFT ? ABE_LEFT : ABE_RIGHT;
+ abd.rc = *rc;
+ abd.rc.top = rcDisplay->top;
+ abd.rc.bottom = rcDisplay->bottom;
+ if (docked == DOCKED_LEFT) {
+ abd.rc.right = rcDisplay->left + abd.rc.right - abd.rc.left;
+ abd.rc.left = rcDisplay->left;
+ }
+ else {
+ abd.rc.left = rcDisplay->right - (abd.rc.right - abd.rc.left);
+ abd.rc.right = rcDisplay->right;
+
+ }
+ SHAppBarMessage(ABM_SETPOS, &abd);
+ *rc = abd.rc;
+}
+
+int Docking_IsDocked(WPARAM wParam, LPARAM lParam)
+{
+ return docked;
+}
+
+int fnDocking_ProcessWindowMessage(WPARAM wParam, LPARAM lParam)
+{
+ APPBARDATA abd;
+ static int draggingTitle;
+ MSG *msg = (MSG *) wParam;
+
+ if (msg->message == WM_DESTROY)
+ DBWriteContactSettingByte(NULL, "CList", "Docked", (BYTE) docked);
+ if (!docked && msg->message != WM_CREATE && msg->message != WM_MOVING && msg->message != WM_CREATEDOCKED && msg->message != WM_MOVE)
+ return 0;
+ switch (msg->message) {
+ case WM_CREATE:
+ //if(GetSystemMetrics(SM_CMONITORS)>1) return 0;
+ if (DBGetContactSettingByte(NULL, "CList", "Docked", 0))
+ PostMessage(msg->hwnd, WM_CREATEDOCKED, 0, 0);
+ draggingTitle = 0;
+ return 0;
+ case WM_CREATEDOCKED:
+ //we need to post a message just after creation to let main message function do some work
+ docked = (int) (char) DBGetContactSettingByte(NULL, "CList", "Docked", 0);
+ if (IsWindowVisible(msg->hwnd) && !IsIconic(msg->hwnd)) {
+ RECT rc, rcMonitor;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ }
+ break;
+ case WM_ACTIVATE:
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_ACTIVATE, &abd);
+ return 0;
+ case WM_WINDOWPOSCHANGED:
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
+ return 0;
+ case WM_MOVING:
+ {
+ RECT rcMonitor;
+ POINT ptCursor;
+
+ // stop early
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+ return 0;
+
+ // GetMessagePos() is no good, position is always unsigned
+ GetCursorPos(&ptCursor);
+ Docking_GetMonitorRectFromPoint(ptCursor, &rcMonitor);
+
+ if ((ptCursor.x < rcMonitor.left + EDGESENSITIVITY) || (ptCursor.x >= rcMonitor.right - EDGESENSITIVITY)) {
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ if (ptCursor.x < rcMonitor.left + EDGESENSITIVITY)
+ docked = DOCKED_LEFT;
+ else
+ docked = DOCKED_RIGHT;
+ PostMessage(msg->hwnd, WM_LBUTTONUP, 0, MAKELPARAM(ptCursor.x, ptCursor.y));
+ GetWindowRect(msg->hwnd, (LPRECT) msg->lParam);
+ Docking_AdjustPosition(msg->hwnd, (LPRECT) & rcMonitor, (LPRECT) msg->lParam);
+ PostMessage(msg->hwnd, WM_SIZE, 0, 0);
+ return TRUE;
+ }
+ return 0;
+ }
+ case WM_MOVE:
+ {
+ if (docked) {
+ RECT rc, rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ return 1;
+ }
+ return 0;
+ }
+ case WM_SIZING:
+ {
+ RECT rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, (LPRECT) msg->lParam);
+ *((LRESULT *) lParam) = TRUE;
+ return TRUE;
+ }
+ case WM_SHOWWINDOW:
+ if (msg->lParam)
+ return 0;
+ if ((msg->wParam && docked < 0) || (!msg->wParam && docked > 0))
+ docked = -docked;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ if (msg->wParam) {
+ RECT rc, rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
+ }
+ else {
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ }
+ return 0;
+ case WM_NCHITTEST:
+ {
+ LONG result;
+ result = DefWindowProc(msg->hwnd, WM_NCHITTEST, msg->wParam, msg->lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT ||
+ result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT) {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ if (docked == DOCKED_LEFT && result == HTLEFT) {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ if (docked == DOCKED_RIGHT && result == HTRIGHT) {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ return 0;
+ }
+ case WM_SYSCOMMAND:
+ if ((msg->wParam & 0xFFF0) != SC_MOVE)
+ return 0;
+ SetActiveWindow(msg->hwnd);
+ SetCapture(msg->hwnd);
+ draggingTitle = 1;
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ case WM_MOUSEMOVE:
+ if (!draggingTitle)
+ return 0;
+ {
+ RECT rc;
+ POINT pt;
+ GetClientRect(msg->hwnd, &rc);
+ if (((docked == DOCKED_LEFT || docked == -DOCKED_LEFT) && (short) LOWORD(msg->lParam) > rc.right) ||
+ ((docked == DOCKED_RIGHT || docked == -DOCKED_RIGHT) && (short) LOWORD(msg->lParam) < 0)) {
+ ReleaseCapture();
+ draggingTitle = 0;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ docked = 0;
+ GetCursorPos(&pt);
+ PostMessage(msg->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ SetWindowPos(msg->hwnd, 0, pt.x - rc.right / 2, pt.y - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYSMCAPTION) / 2,
+ DBGetContactSettingDword(NULL, "CList", "Width", 0), DBGetContactSettingDword(NULL, "CList", "Height", 0),
+ SWP_NOZORDER);
+ }
+ return 1;
+ }
+ case WM_LBUTTONUP:
+ if (draggingTitle) {
+ ReleaseCapture();
+ draggingTitle = 0;
+ }
+ return 0;
+ case WM_DOCKCALLBACK:
+ switch (msg->wParam) {
+ case ABN_WINDOWARRANGE:
+ ShowWindow(msg->hwnd, msg->lParam ? SW_HIDE : SW_SHOW);
+ break;
+ }
+ return TRUE;
+ case WM_DESTROY:
+ if (docked > 0) {
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/clc.c b/miranda-wine/src/modules/clist/clc.c new file mode 100644 index 0000000..1689ea1 --- /dev/null +++ b/miranda-wine/src/modules/clist/clc.c @@ -0,0 +1,1321 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+
+static HANDLE hClcWindowList;
+static HANDLE hShowInfoTipEvent;
+HANDLE hHideInfoTipEvent;
+static HANDLE hAckHook;
+static HANDLE hClcSettingsChanged;
+
+int g_IconWidth, g_IconHeight;
+
+void FreeDisplayNameCache(void);
+
+void fnClcBroadcast( int msg, WPARAM wParam, LPARAM lParam )
+{
+ WindowList_Broadcast(hClcWindowList, msg, wParam, lParam);
+}
+
+void fnClcOptionsChanged(void)
+{
+ cli.pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0);
+}
+
+HMENU fnBuildGroupPopupMenu( struct ClcGroup* group )
+{
+ static HMENU result = NULL;
+
+ if ( result == NULL ) {
+ result = GetSubMenu(LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 2);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) result, 0);
+ }
+ CheckMenuItem(result, POPUP_GROUPHIDEOFFLINE, group->hideOffline ? MF_CHECKED : MF_UNCHECKED);
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// standard CLC services
+
+static int ClcSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ char *szProto;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ if ( (HANDLE)wParam != NULL && !strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "MyHandle")) {
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE) wParam);
+ cli.pfnClcBroadcast( INTM_NAMECHANGED, wParam, lParam);
+ }
+ else if (!strcmp(cws->szSetting, "Group"))
+ cli.pfnClcBroadcast( INTM_GROUPCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "Hidden"))
+ cli.pfnClcBroadcast( INTM_HIDDENCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "NotOnList"))
+ cli.pfnClcBroadcast( INTM_NOTONLISTCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "Status"))
+ cli.pfnClcBroadcast( INTM_INVALIDATE, 0, 0);
+ else if (!strcmp(cws->szSetting, "NameOrder"))
+ cli.pfnClcBroadcast( INTM_NAMEORDERCHANGED, 0, 0);
+ }
+ else if (!strcmp(cws->szModule, "CListGroups")) {
+ cli.pfnClcBroadcast( INTM_GROUPSCHANGED, wParam, lParam);
+ }
+ else {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL && (HANDLE) wParam != NULL) {
+ char *id = NULL;
+ if (!strcmp(cws->szModule, "Protocol") && !strcmp(cws->szSetting, "p")) {
+ cli.pfnClcBroadcast( INTM_PROTOCHANGED, wParam, lParam);
+ }
+ // something is being written to a protocol module
+ if (!strcmp(szProto, cws->szModule)) {
+ // was a unique setting key written?
+ id = (char *) CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
+ if ((int) id != CALLSERVICE_NOTFOUND && id != NULL && !strcmp(id, cws->szSetting)) {
+ cli.pfnClcBroadcast( INTM_PROTOCHANGED, wParam, lParam);
+ }
+ }
+ }
+ if (szProto == NULL || strcmp(szProto, cws->szModule))
+ return 0;
+ if (!strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName") || !strcmp(cws->szSetting, "e-mail")
+ || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "UIN"))
+ cli.pfnClcBroadcast( INTM_NAMECHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "ApparentMode"))
+ cli.pfnClcBroadcast( INTM_APPARENTMODECHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "IdleTS"))
+ cli.pfnClcBroadcast( INTM_IDLECHANGED, wParam, lParam);
+ }
+ return 0;
+}
+
+static int ClcModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR **proto;
+ int protoCount, i;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ for (i = 0; i < protoCount; i++) {
+ if (proto[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ cli.clcProto = (ClcProtoStatus *) mir_realloc(cli.clcProto, sizeof(ClcProtoStatus) * (cli.hClcProtoCount + 1));
+ cli.clcProto[cli.hClcProtoCount].szProto = proto[i]->szName;
+ cli.clcProto[cli.hClcProtoCount].dwStatus = ID_STATUS_OFFLINE;
+ cli.hClcProtoCount++;
+ }
+ return 0;
+}
+
+static int ClcProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+ int i;
+
+ if (ack->type == ACKTYPE_STATUS) {
+ WindowList_BroadcastAsync(hClcWindowList,INTM_INVALIDATE,0,0);
+ if (ack->result == ACKRESULT_SUCCESS) {
+ for (i = 0; i < cli.hClcProtoCount; i++) {
+ if (!lstrcmpA(cli.clcProto[i].szProto, ack->szModule)) {
+ cli.clcProto[i].dwStatus = (WORD) ack->lParam;
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int ClcContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_CONTACTADDED,wParam,lParam);
+ return 0;
+}
+
+static int ClcContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_CONTACTDELETED,wParam,lParam);
+ return 0;
+}
+
+static int ClcContactIconChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_ICONCHANGED,wParam,lParam);
+ return 0;
+}
+
+static int ClcIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_INVALIDATE,0,0);
+ return 0;
+}
+
+static int SetInfoTipHoverTime(WPARAM wParam, LPARAM lParam)
+{
+ DBWriteContactSettingWord(NULL, "CLC", "InfoTipHoverTime", (WORD) wParam);
+ cli.pfnClcBroadcast( INTM_SETINFOTIPHOVERTIME, wParam, 0);
+ return 0;
+}
+
+static int GetInfoTipHoverTime(WPARAM wParam, LPARAM lParam)
+{
+ return DBGetContactSettingWord(NULL, "CLC", "InfoTipHoverTime", 750);
+}
+
+static int ClcShutdown(WPARAM wParam, LPARAM lParam)
+{
+ UnhookEvent(hAckHook);
+ UnhookEvent(hClcSettingsChanged);
+ if (cli.clcProto) mir_free(cli.clcProto);
+ FreeFileDropping();
+ FreeDisplayNameCache();
+ return 0;
+}
+
+static void SortClcByTimer( HWND hwnd )
+{
+ KillTimer( hwnd, TIMERID_DELAYEDRESORTCLC );
+ SetTimer( hwnd, TIMERID_DELAYEDRESORTCLC, 200, NULL );
+}
+
+int LoadCLCModule(void)
+{
+ g_IconWidth = GetSystemMetrics(SM_CXSMICON);
+ g_IconHeight = GetSystemMetrics(SM_CYSMICON);
+
+ hClcWindowList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ hShowInfoTipEvent = CreateHookableEvent(ME_CLC_SHOWINFOTIP);
+ hHideInfoTipEvent = CreateHookableEvent(ME_CLC_HIDEINFOTIP);
+ CreateServiceFunction(MS_CLC_SETINFOTIPHOVERTIME, SetInfoTipHoverTime);
+ CreateServiceFunction(MS_CLC_GETINFOTIPHOVERTIME, GetInfoTipHoverTime);
+
+ InitFileDropping();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, ClcModulesLoaded);
+ hClcSettingsChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ClcSettingChanged);
+ HookEvent(ME_DB_CONTACT_ADDED, ClcContactAdded);
+ HookEvent(ME_DB_CONTACT_DELETED, ClcContactDeleted);
+ HookEvent(ME_CLIST_CONTACTICONCHANGED, ClcContactIconChanged);
+ HookEvent(ME_SKIN_ICONSCHANGED, ClcIconsChanged);
+ hAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, ClcProtoAck);
+ HookEvent(ME_SYSTEM_SHUTDOWN, ClcShutdown);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default contact list control window procedure
+
+LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct ClcData *dat;
+
+ dat = (struct ClcData *) GetWindowLong(hwnd, 0);
+ if (msg >= CLM_FIRST && msg < CLM_LAST)
+ return cli.pfnProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
+
+ switch (msg) {
+ case WM_CREATE:
+ WindowList_Add(hClcWindowList, hwnd, NULL);
+ cli.pfnRegisterFileDropping(hwnd);
+ if ( dat == NULL ) {
+ dat = (struct ClcData *) mir_calloc(sizeof(struct ClcData));
+ SetWindowLong(hwnd, 0, (LONG) dat);
+ }
+ {
+ int i;
+ for (i = 0; i <= FONTID_MAX; i++)
+ dat->fontInfo[i].changed = 1;
+ }
+ dat->selection = -1;
+ dat->iconXSpace = 20;
+ dat->checkboxSize = 13;
+ dat->dragAutoScrollHeight = 30;
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ dat->insertionMarkHitHeight = 5;
+ dat->iHotTrack = -1;
+ dat->infoTipTimeout = DBGetContactSettingWord(NULL, "CLC", "InfoTipHoverTime", 750);
+ dat->extraColumnSpacing = 20;
+ dat->list.cl.increment = 30;
+ dat->needsResort = 1;
+ cli.pfnLoadClcOptions(hwnd, dat);
+ if (!IsWindowVisible(hwnd))
+ SetTimer(hwnd,TIMERID_REBUILDAFTER,10,NULL);
+ else
+ cli.pfnRebuildEntireList(hwnd,dat);
+ {
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ break;
+ case INTM_SCROLLBARCHANGED:
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar)
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ else
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ }
+ break;
+
+ case INTM_RELOADOPTIONS:
+ cli.pfnLoadClcOptions(hwnd, dat);
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+ case WM_THEMECHANGED:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ case WM_SIZE:
+ cli.pfnEndRename(hwnd, dat, 1);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ { //creating imagelist containing blue line for highlight
+ HBITMAP hBmp, hBmpMask, hoBmp, hoMaskBmp;
+ HDC hdc,hdcMem;
+ RECT rc;
+ int depth;
+ HBRUSH hBrush;
+
+ GetClientRect(hwnd, &rc);
+ if (rc.right == 0)
+ break;
+ rc.bottom = dat->rowHeight;
+ hdc = GetDC(hwnd);
+ depth = GetDeviceCaps(hdc, BITSPIXEL);
+ if (depth < 16)
+ depth = 16;
+ hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL);
+ hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL);
+ hdcMem = CreateCompatibleDC(hdc);
+ hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp);
+ hBrush = CreateSolidBrush(dat->useWindowsColours ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour);
+ FillRect(hdcMem, &rc, hBrush);
+ DeleteObject(hBrush);
+
+ hoMaskBmp = SelectObject(hdcMem, hBmpMask);
+ FillRect(hdcMem, &rc, GetStockObject(BLACK_BRUSH));
+ SelectObject(hdcMem, hoMaskBmp);
+ SelectObject(hdcMem, hoBmp);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd, hdc);
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 1, 1);
+ ImageList_Add(dat->himlHighlight, hBmp, hBmpMask);
+ DeleteObject(hBmpMask);
+ DeleteObject(hBmp);
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ break;
+
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN) {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0)
+ return 0;
+ }
+ if (msg->message == WM_CHAR) {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27 && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+
+ case WM_KILLFOCUS:
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ case WM_SETFOCUS:
+ case WM_ENABLE:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case WM_GETFONT:
+ return (LRESULT) dat->fontInfo[FONTID_CONTACTS].hFont;
+
+ case INTM_GROUPSCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ if (dbcws->value.type == DBVT_ASCIIZ || dbcws->value.type == DBVT_UTF8) {
+ int groupId = atoi(dbcws->szSetting) + 1;
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ TCHAR szFullName[512];
+ int i, nameLen, eq;
+ //check name of group and ignore message if just being expanded/collapsed
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) (groupId | HCONTACT_ISGROUP), &contact, &group, NULL)) {
+ lstrcpy(szFullName, contact->szText);
+ while (group->parent) {
+ for (i = 0; i < group->parent->cl.count; i++)
+ if (group->parent->cl.items[i]->group == group)
+ break;
+ if (i == group->parent->cl.count) {
+ szFullName[0] = '\0';
+ break;
+ }
+ group = group->parent;
+ nameLen = lstrlen(group->cl.items[i]->szText);
+ if (lstrlen(szFullName) + 1 + nameLen > SIZEOF(szFullName)) {
+ szFullName[0] = '\0';
+ break;
+ }
+ memmove(szFullName + 1 + nameLen, szFullName, sizeof( TCHAR )*( lstrlen(szFullName) + 1));
+ memcpy(szFullName, group->cl.items[i]->szText, sizeof( TCHAR )*nameLen);
+ szFullName[nameLen] = '\\';
+ }
+
+ if ( dbcws->value.type == DBVT_ASCIIZ )
+ #if defined( UNICODE )
+ { WCHAR* wszGrpName = a2u(dbcws->value.pszVal+1);
+ eq = !lstrcmp( szFullName, wszGrpName );
+ mir_free( wszGrpName );
+ }
+ #else
+ eq = !lstrcmp( szFullName, dbcws->value.pszVal+1 );
+ #endif
+ else {
+ char* szGrpName = NEWSTR_ALLOCA(dbcws->value.pszVal+1);
+ #if defined( UNICODE )
+ WCHAR* wszGrpName;
+ Utf8Decode(szGrpName, &wszGrpName );
+ eq = !lstrcmp( szFullName, wszGrpName );
+ mir_free( wszGrpName );
+
+ #else
+ Utf8Decode(szGrpName, NULL);
+ eq = !lstrcmp( szFullName, szGrpName );
+ #endif
+ }
+ if ( eq && (contact->group->hideOffline != 0) == ((dbcws->value.pszVal[0] & GROUPF_HIDEOFFLINE) != 0))
+ break; //only expanded has changed: no action reqd
+ }
+ }
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+ }
+ case INTM_NAMEORDERCHANGED:
+ PostMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case INTM_CONTACTADDED:
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ SortClcByTimer(hwnd);
+ break;
+
+ case INTM_CONTACTDELETED:
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ SortClcByTimer(hwnd);
+ break;
+
+ case INTM_HIDDENCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN)
+ break;
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0) {
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, NULL, NULL, NULL))
+ break;
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ }
+ else cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+
+ dat->needsResort = 1;
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_GROUPCHANGED:
+ {
+ struct ClcContact *contact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ memset(iExtraImage, 0xFF, SIZEOF(iExtraImage));
+ else
+ CopyMemory(iExtraImage, contact->iExtraImage, SIZEOF(iExtraImage));
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0)) {
+ NMCLISTCONTROL nm;
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ CopyMemory(contact->iExtraImage, iExtraImage, SIZEOF(iExtraImage));
+ nm.hdr.code = CLN_CONTACTMOVED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = (HANDLE) wParam;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ dat->needsResort = 1;
+ }
+ SetTimer(hwnd,TIMERID_REBUILDAFTER,1,NULL);
+ break;
+ }
+ case INTM_ICONCHANGED:
+ {
+ struct ClcContact *contact = NULL;
+ struct ClcGroup *group = NULL;
+ int recalcScrollBar = 0, shouldShow;
+ WORD status;
+ char *szProto;
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ status = ID_STATUS_OFFLINE;
+ else
+ status = DBGetContactSettingWord((HANDLE) wParam, szProto, "Status", ID_STATUS_OFFLINE);
+
+ shouldShow = (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0))
+ && (!cli.pfnIsHiddenMode(dat, status)
+ || CallService(MS_CLIST_GETCONTACTICON, wParam, 0) != lParam); //this means an offline msg is flashing, so the contact should be shown
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL)) {
+ if (shouldShow) {
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 0, 0);
+ recalcScrollBar = 1;
+ cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL);
+ if (contact) {
+ contact->iImage = (WORD) lParam;
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ dat->needsResort = 1;
+ } }
+ }
+ else { //item in list already
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ if (contact->iImage == (WORD) lParam)
+ break;
+ if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ HANDLE hSelItem;
+ struct ClcContact *selcontact;
+ struct ClcGroup *selgroup;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
+ hSelItem = NULL;
+ else
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ cli.pfnRemoveItemFromGroup(hwnd, group, contact, 0);
+ if (hSelItem)
+ if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf(( SortedList* )&selgroup->cl, selcontact));
+
+ recalcScrollBar = 1;
+ }
+ else {
+ contact->iImage = (WORD) lParam;
+ if (!cli.pfnIsHiddenMode(dat, status))
+ contact->flags |= CONTACTF_ONLINE;
+ else
+ contact->flags &= ~CONTACTF_ONLINE;
+ }
+ dat->needsResort = 1;
+ }
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_NAMECHANGED:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+
+ lstrcpyn(contact->szText, cli.pfnGetContactDisplayName((HANDLE)wParam,0), SIZEOF(contact->szText));
+ dat->needsResort = 1;
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_PROTOCHANGED:
+ {
+ struct ClcContact *contact = NULL;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ contact->proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam);
+ lstrcpyn(contact->szText, cli.pfnGetContactDisplayName((HANDLE)wParam,0), SIZEOF(contact->szText));
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_NOTONLISTCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (contact->type != CLCIT_CONTACT)
+ break;
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0)
+ contact->flags &= ~CONTACTF_NOTONLIST;
+ else
+ contact->flags |= CONTACTF_NOTONLIST;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case INTM_INVALIDATE:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case INTM_APPARENTMODECHANGED:
+ {
+ WORD apparentMode;
+ char *szProto;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ break;
+ apparentMode = DBGetContactSettingWord((HANDLE) wParam, szProto, "ApparentMode", 0);
+ contact->flags &= ~(CONTACTF_INVISTO | CONTACTF_VISTO);
+ if (apparentMode == ID_STATUS_OFFLINE)
+ contact->flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE)
+ contact->flags |= CONTACTF_VISTO;
+ else if (apparentMode)
+ contact->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case INTM_SETINFOTIPHOVERTIME:
+ dat->infoTipTimeout = wParam;
+ break;
+
+ case INTM_IDLECHANGED:
+ {
+ char *szProto;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ break;
+ contact->flags &= ~CONTACTF_IDLE;
+ if (DBGetContactSettingDword((HANDLE) wParam, szProto, "IdleTS", 0)) {
+ contact->flags |= CONTACTF_IDLE;
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case WM_PRINTCLIENT:
+ cli.pfnPaintClc(hwnd, dat, (HDC) wParam, NULL);
+ break;
+
+ case WM_NCPAINT:
+ if (wParam == 1)
+ break;
+ {
+ POINT ptTopLeft = { 0, 0 };
+ HRGN hClientRgn;
+ ClientToScreen(hwnd, &ptTopLeft);
+ hClientRgn = CreateRectRgn(0, 0, 1, 1);
+ CombineRgn(hClientRgn, (HRGN) wParam, NULL, RGN_COPY);
+ OffsetRgn(hClientRgn, -ptTopLeft.x, -ptTopLeft.y);
+ InvalidateRgn(hwnd, hClientRgn, FALSE);
+ DeleteObject(hClientRgn);
+ UpdateWindow(hwnd);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hwnd, &ps);
+ /* we get so many cli.pfnInvalidateRect()'s that there is no point painting,
+ Windows in theory shouldn't queue up WM_PAINTs in this case but it does so
+ we'll just ignore them */
+ if (IsWindowVisible(hwnd))
+ cli.pfnPaintClc(hwnd, dat, hdc, &ps.rcPaint);
+ EndPaint(hwnd, &ps);
+ break;
+ }
+ case WM_VSCROLL:
+ {
+ int desty;
+ RECT clRect;
+ int noSmooth = 0;
+
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ desty = dat->yScroll;
+ GetClientRect(hwnd, &clRect);
+ switch (LOWORD(wParam)) {
+ case SB_LINEUP: desty -= dat->rowHeight; break;
+ case SB_LINEDOWN: desty += dat->rowHeight; break;
+ case SB_PAGEUP: desty -= clRect.bottom - dat->rowHeight; break;
+ case SB_PAGEDOWN: desty += clRect.bottom - dat->rowHeight; break;
+ case SB_BOTTOM: desty = 0x7FFFFFFF; break;
+ case SB_TOP: desty = 0; break;
+ case SB_THUMBTRACK: desty = HIWORD(wParam); noSmooth = 1; break; //noone has more than 4000 contacts, right?
+ default: return 0;
+ }
+ cli.pfnScrollTo(hwnd, dat, desty, noSmooth);
+ break;
+ }
+ case WM_MOUSEWHEEL:
+ {
+ UINT scrollLines;
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, FALSE))
+ scrollLines = 3;
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll - (short) HIWORD(wParam) * dat->rowHeight * (signed) scrollLines / WHEEL_DELTA, 0);
+ return 0;
+ }
+ case WM_KEYDOWN:
+ {
+ int selMoved = 0;
+ int changeGroupExpand = 0;
+ int pageSize;
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU))
+ break;
+ {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ pageSize = clRect.bottom / dat->rowHeight;
+ }
+ switch (wParam) {
+ case VK_DOWN: dat->selection++; selMoved = 1; break;
+ case VK_UP: dat->selection--; selMoved = 1; break;
+ case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break;
+ case VK_NEXT: dat->selection += pageSize; selMoved = 1; break;
+ case VK_HOME: dat->selection = 0; selMoved = 1; break;
+ case VK_END: dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break;
+ case VK_LEFT: changeGroupExpand = 1; break;
+ case VK_RIGHT: changeGroupExpand = 2; break;
+ case VK_RETURN: cli.pfnDoSelectionDefaultAction(hwnd, dat); return 0;
+ case VK_F2: cli.pfnBeginRenameSelection(hwnd, dat); return 0;
+ case VK_DELETE: cli.pfnDeleteFromContactList(hwnd, dat); return 0;
+ default:
+ {
+ NMKEY nmkey;
+ nmkey.hdr.hwndFrom = hwnd;
+ nmkey.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nmkey.hdr.code = NM_KEYDOWN;
+ nmkey.nVKey = wParam;
+ nmkey.uFlags = HIWORD(lParam);
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nmkey))
+ return 0;
+ }
+ }
+ if (changeGroupExpand) {
+ int hit;
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ dat->szQuickSearch[0] = 0;
+ hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (hit != -1) {
+ if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) {
+ if (group == &dat->list)
+ return 0;
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, -1);
+ selMoved = 1;
+ }
+ else {
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, changeGroupExpand == 2);
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ if (selMoved) {
+ dat->szQuickSearch[0] = 0;
+ if (dat->selection >= cli.pfnGetGroupContentsCount(&dat->list, 1))
+ dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1;
+ if (dat->selection < 0)
+ dat->selection = 0;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+ return 0;
+ }
+ break;
+ }
+ case WM_CHAR:
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (wParam == 27) //escape
+ dat->szQuickSearch[0] = 0;
+ else if (wParam == '\b' && dat->szQuickSearch[0])
+ dat->szQuickSearch[lstrlen(dat->szQuickSearch) - 1] = '\0';
+ else if (wParam < ' ')
+ break;
+ else if (wParam == ' ' && dat->szQuickSearch[0] == '\0' && GetWindowLong(hwnd, GWL_STYLE) & CLS_CHECKBOXES) {
+ struct ClcContact *contact;
+ NMCLISTCONTROL nm;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ break;
+ if (contact->type != CLCIT_CONTACT)
+ break;
+ contact->flags ^= CONTACTF_CHECKED;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ else {
+ TCHAR szNew[2];
+ szNew[0] = (TCHAR) wParam;
+ szNew[1] = '\0';
+ if (lstrlen(dat->szQuickSearch) >= SIZEOF(dat->szQuickSearch) - 1) {
+ MessageBeep(MB_OK);
+ break;
+ }
+ _tcscat(dat->szQuickSearch, szNew);
+ }
+ if (dat->szQuickSearch[0]) {
+ int index;
+ index = cli.pfnFindRowByText(hwnd, dat, dat->szQuickSearch, 1);
+ if (index != -1)
+ dat->selection = index;
+ else {
+ MessageBeep(MB_OK);
+ dat->szQuickSearch[ lstrlen(dat->szQuickSearch) - 1] = '\0';
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ }
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case WM_SYSKEYDOWN:
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ dat->iHotTrack = -1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ ReleaseCapture();
+ if (wParam == VK_F10 && GetKeyState(VK_SHIFT) & 0x8000)
+ break;
+ SendMessage(GetParent(hwnd), msg, wParam, lParam);
+ return 0;
+
+ case WM_TIMER:
+ switch( wParam ) {
+ case TIMERID_RENAME:
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+ case TIMERID_DRAGAUTOSCROLL:
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll + dat->dragAutoScrolling * dat->rowHeight * 2, 0);
+ break;
+ case TIMERID_INFOTIP:
+ { CLCINFOTIP it;
+ struct ClcContact *contact;
+ int hit;
+ RECT clRect;
+ POINT ptClientOffset = { 0 };
+
+ KillTimer(hwnd, wParam);
+ GetCursorPos(&it.ptCursor);
+ ScreenToClient(hwnd, &it.ptCursor);
+ if (it.ptCursor.x != dat->ptInfoTip.x || it.ptCursor.y != dat->ptInfoTip.y)
+ break;
+ GetClientRect(hwnd, &clRect);
+ it.rcItem.left = 0;
+ it.rcItem.right = clRect.right;
+ hit = cli.pfnHitTest(hwnd, dat, it.ptCursor.x, it.ptCursor.y, &contact, NULL, NULL);
+ if (hit == -1)
+ break;
+ if (contact->type != CLCIT_GROUP && contact->type != CLCIT_CONTACT)
+ break;
+ ClientToScreen(hwnd, &it.ptCursor);
+ ClientToScreen(hwnd, &ptClientOffset);
+ it.isTreeFocused = GetFocus() == hwnd;
+ it.rcItem.top = cli.pfnGetRowTopY(dat, hit) - dat->yScroll;
+ it.rcItem.bottom = it.rcItem.top + cli.pfnGetRowHeight(dat, hit);
+ OffsetRect(&it.rcItem, ptClientOffset.x, ptClientOffset.y);
+ it.isGroup = contact->type == CLCIT_GROUP;
+ it.hItem = contact->type == CLCIT_GROUP ? (HANDLE) contact->groupId : contact->hContact;
+ it.cbSize = sizeof(it);
+ dat->hInfoTipItem = cli.pfnContactToHItem(contact);
+ NotifyEventHooks(hShowInfoTipEvent, 0, (LPARAM) & it);
+ break;
+ }
+ case TIMERID_REBUILDAFTER:
+ KillTimer(hwnd,TIMERID_REBUILDAFTER);
+ cli.pfnInvalidateRect(hwnd,NULL,FALSE);
+ cli.pfnSaveStateAndRebuildList(hwnd,dat);
+ break;
+
+ case TIMERID_DELAYEDRESORTCLC:
+ KillTimer(hwnd,TIMERID_DELAYEDRESORTCLC);
+ cli.pfnInvalidateRect(hwnd,NULL,FALSE);
+ cli.pfnSortCLC(hwnd,dat,1);
+ cli.pfnRecalcScrollBar(hwnd,dat);
+ break;
+ }
+ break;
+
+ case WM_MBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ int hit;
+ DWORD hitFlags;
+
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnEndRename(hwnd, dat, 1);
+ dat->ptDragStart.x = (short) LOWORD(lParam);
+ dat->ptDragStart.y = (short) HIWORD(lParam);
+ dat->szQuickSearch[0] = 0;
+ hit = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, &group, &hitFlags);
+ if (hit != -1) {
+ if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME;
+ dat->dragAutoScrolling = 0;
+ break;
+ } }
+
+ if (hit != -1 && contact->type == CLCIT_GROUP)
+ if (hitFlags & CLCHT_ONITEMICON) {
+ struct ClcGroup *selgroup;
+ struct ClcContact *selcontact;
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, &selgroup);
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (dat->selection != -1) {
+ dat->selection =
+ cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl,selcontact));
+ if (dat->selection == -1)
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, contact->group, -1);
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ UpdateWindow(hwnd);
+ break;
+ }
+ if (hit != -1 && hitFlags & CLCHT_ONITEMCHECK) {
+ NMCLISTCONTROL nm;
+ contact->flags ^= CONTACTF_CHECKED;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) {
+ NMCLISTCONTROL nm;
+ nm.hdr.code = NM_CLICK;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ if (hit == -1)
+ nm.hItem = NULL;
+ else
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1;
+ nm.pt = dat->ptDragStart;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA))
+ break;
+ dat->selection = hit;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, hit, 0);
+ UpdateWindow(hwnd);
+ if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP)
+ && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK))) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED;
+ dat->dragAutoScrolling = 0;
+ }
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (dat->iDragItem == -1) {
+ int iOldHotTrack = dat->iHotTrack;
+ if (dat->hwndRenameEdit != NULL)
+ break;
+ if (GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000)
+ break;
+ dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), NULL, NULL, NULL);
+ if (iOldHotTrack != dat->iHotTrack) {
+ if (iOldHotTrack == -1)
+ SetCapture(hwnd);
+ else if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ cli.pfnInvalidateItem(hwnd, dat, iOldHotTrack);
+ cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ }
+ cli.pfnHideInfoTip(hwnd, dat);
+ }
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (wParam == 0 && dat->hInfoTipItem == NULL) {
+ dat->ptInfoTip.x = (short) LOWORD(lParam);
+ dat->ptInfoTip.y = (short) HIWORD(lParam);
+ SetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL);
+ }
+ break;
+ }
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP)) {
+ if (abs((short) LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG)
+ || abs((short) HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG))
+ dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE;
+ }
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ HCURSOR hNewCursor;
+ RECT clRect;
+ POINT pt;
+ int target;
+
+ GetClientRect(hwnd, &clRect);
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ hNewCursor = LoadCursor(NULL, IDC_NO);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->dragAutoScrolling) {
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ dat->dragAutoScrolling = 0;
+ }
+ target = cli.pfnGetDropTargetInformation(hwnd, dat, pt);
+ if (dat->dragStage & DRAGSTAGEF_OUTSIDE && target != DROPTARGET_OUTSIDE) {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DRAGSTOP;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ dat->dragStage &= ~DRAGSTAGEF_OUTSIDE;
+ }
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ case DROPTARGET_ONCONTACT:
+ break;
+ case DROPTARGET_ONGROUP:
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ case DROPTARGET_INSERTION:
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ case DROPTARGET_OUTSIDE:
+ {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+
+ if (pt.x >= 0 && pt.x < clRect.right
+ && ((pt.y < 0 && pt.y > -dat->dragAutoScrollHeight)
+ || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) {
+ if (!dat->dragAutoScrolling) {
+ if (pt.y < 0)
+ dat->dragAutoScrolling = -1;
+ else
+ dat->dragAutoScrolling = 1;
+ SetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL);
+ }
+ SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0);
+ }
+
+ dat->dragStage |= DRAGSTAGEF_OUTSIDE;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DRAGGING;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm))
+ return 0;
+ break;
+ }
+ default:
+ {
+ struct ClcGroup *group;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, NULL, &group);
+ if (group->parent)
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ }
+ }
+ SetCursor(hNewCursor);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (dat->iDragItem == -1)
+ break;
+ SetCursor((HCURSOR) GetClassLong(hwnd, GCL_HCURSOR));
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), NULL, NULL, NULL);
+ if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ }
+ else ReleaseCapture();
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME))
+ SetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL);
+ else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ POINT pt;
+ int target;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ target = cli.pfnGetDropTargetInformation(hwnd, dat, pt);
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ break;
+ case DROPTARGET_ONCONTACT:
+ break;
+ case DROPTARGET_ONGROUP:
+ {
+ struct ClcContact *contact;
+ TCHAR *szGroup;
+ cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ szGroup = cli.pfnGetGroupName(contact->groupId, NULL);
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ if (contact->type == CLCIT_CONTACT) //dropee is a contact
+ DBWriteContactSettingTString(contact->hContact, "CList", "Group", szGroup);
+ else if (contact->type == CLCIT_GROUP) { //dropee is a group
+ TCHAR szNewName[120];
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s\\%s"), szGroup, contact->szText);
+ cli.pfnRenameGroup( contact->groupId, szNewName );
+ }
+ break;
+ }
+ case DROPTARGET_INSERTION:
+ {
+ struct ClcContact *contact, *destcontact;
+ struct ClcGroup *destgroup;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ if (cli.pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup) == -1 || destgroup != contact->group->parent)
+ CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, 0);
+ else {
+ if (destcontact->type == CLCIT_GROUP)
+ destgroup = destcontact->group;
+ else
+ destgroup = destgroup;
+ CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, destgroup->groupId);
+ }
+ break;
+ }
+ case DROPTARGET_OUTSIDE:
+ {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DROPPED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ break;
+ }
+ default:
+ {
+ struct ClcGroup *group;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group);
+ if (group->parent) { //move to root
+ if (contact->type == CLCIT_CONTACT) //dropee is a contact
+ DBDeleteContactSetting(contact->hContact, "CList", "Group");
+ else if (contact->type == CLCIT_GROUP) { //dropee is a group
+ TCHAR szNewName[120];
+ lstrcpyn(szNewName, contact->szText, SIZEOF(szNewName));
+ cli.pfnRenameGroup( contact->groupId, szNewName );
+ } } } } }
+
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ {
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ dat->szQuickSearch[0] = 0;
+ dat->selection = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL)))
+ break;
+ UpdateWindow(hwnd);
+ cli.pfnDoSelectionDefaultAction(hwnd, dat);
+ break;
+ }
+ case WM_CONTEXTMENU:
+ {
+ struct ClcContact *contact;
+ HMENU hMenu = NULL;
+ POINT pt;
+ DWORD hitFlags;
+
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ dat->iHotTrack = -1;
+ dat->szQuickSearch[0] = 0;
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ if (pt.x == -1 && pt.y == -1) {
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ pt.x = dat->iconXSpace + 15;
+ pt.y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll + (int)(cli.pfnGetRowHeight(dat, dat->selection) * .7);
+ hitFlags = dat->selection == -1 ? CLCHT_NOWHERE : CLCHT_ONITEMLABEL;
+ }
+ else {
+ ScreenToClient(hwnd, &pt);
+ dat->selection = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, NULL, &hitFlags);
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+
+ if (dat->selection != -1 && hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMCHECK | CLCHT_ONITEMLABEL)) {
+ if (contact->type == CLCIT_GROUP) {
+ hMenu = cli.pfnBuildGroupPopupMenu(contact->group);
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ return 0;
+ }
+ else if (contact->type == CLCIT_CONTACT)
+ hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) contact->hContact, 0);
+ }
+ else {
+ //call parent for new group/hide offline menu
+ SendMessage(GetParent(hwnd), WM_CONTEXTMENU, wParam, lParam);
+ }
+ if (hMenu != NULL) {
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ }
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+
+ case WM_DRAWITEM:
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+
+ case WM_COMMAND:
+ {
+ struct ClcContact *contact;
+ int hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (hit == -1)
+ break;
+ if (contact->type == CLCIT_CONTACT)
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM) contact->hContact))
+ break;
+ switch (LOWORD(wParam)) {
+ case POPUP_NEWSUBGROUP:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0);
+ break;
+ case POPUP_RENAMEGROUP:
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+ case POPUP_DELETEGROUP:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0);
+ break;
+ case POPUP_GROUPHIDEOFFLINE:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId,
+ MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE));
+ break;
+ }
+ break;
+ }
+ case WM_DESTROY:
+ cli.pfnHideInfoTip(hwnd, dat);
+ {
+ int i;
+ for (i = 0; i <= FONTID_MAX; i++)
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+ }
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ if (dat->hwndRenameEdit)
+ DestroyWindow(dat->hwndRenameEdit);
+ if (!dat->bkChanged && dat->hBmpBackground)
+ DeleteObject(dat->hBmpBackground);
+ cli.pfnFreeGroup(&dat->list);
+ mir_free(dat);
+ cli.pfnUnregisterFileDropping(hwnd);
+ WindowList_Remove(hClcWindowList, hwnd);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
diff --git a/miranda-wine/src/modules/clist/clc.h b/miranda-wine/src/modules/clist/clc.h new file mode 100644 index 0000000..4c9b80d --- /dev/null +++ b/miranda-wine/src/modules/clist/clc.h @@ -0,0 +1,154 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+struct ClcContact {
+ BYTE type;
+ BYTE flags;
+ union {
+ struct {
+ WORD iImage;
+ HANDLE hContact;
+ };
+ struct {
+ WORD groupId;
+ struct ClcGroup *group;
+ };
+ };
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ TCHAR szText[120-MAXEXTRACOLUMNS];
+ char * proto; // MS_PROTO_GETBASEPROTO
+};
+
+struct ClcData {
+ struct ClcGroup list;
+ int rowHeight;
+ int yScroll;
+ int selection;
+ struct ClcFontInfo fontInfo[FONTID_MAX + 1];
+ int scrollTime;
+ HIMAGELIST himlHighlight;
+ int groupIndent;
+ TCHAR szQuickSearch[128];
+ int iconXSpace;
+ HWND hwndRenameEdit;
+ COLORREF bkColour, selBkColour, selTextColour, hotTextColour, quickSearchColour;
+ int iDragItem, iInsertionMark;
+ int dragStage;
+ POINT ptDragStart;
+ int dragAutoScrolling;
+ int dragAutoScrollHeight;
+ int leftMargin;
+ int insertionMarkHitHeight;
+ HBITMAP hBmpBackground;
+ int backgroundBmpUse, bkChanged;
+ int iHotTrack;
+ int gammaCorrection;
+ DWORD greyoutFlags; //see m_clc.h
+ DWORD offlineModes;
+ DWORD exStyle;
+ POINT ptInfoTip;
+ int infoTipTimeout;
+ HANDLE hInfoTipItem;
+ HIMAGELIST himlExtraColumns;
+ int extraColumnsCount;
+ int extraColumnSpacing;
+ int checkboxSize;
+ int showSelAlways;
+ int showIdle;
+ int noVScrollbar;
+ int useWindowsColours;
+ int needsResort;
+};
+
+//clc.c
+extern int g_IconWidth, g_IconHeight;
+
+//clcidents.c
+int GetRowsPriorTo(struct ClcGroup *group,struct ClcGroup *subgroup,int contactIndex);
+int FindItem(HWND hwnd,struct ClcData *dat,HANDLE hItem,struct ClcContact **contact,struct ClcGroup **subgroup,int *isVisible);
+int GetRowByIndex(struct ClcData *dat,int testindex,struct ClcContact **contact,struct ClcGroup **subgroup);
+HANDLE ContactToHItem(struct ClcContact *contact);
+HANDLE ContactToItemHandle(struct ClcContact *contact,DWORD *nmFlags);
+
+//clcitems.c
+struct ClcGroup *AddGroup(HWND hwnd,struct ClcData *dat,const TCHAR *szName,DWORD flags,int groupId,int calcTotalMembers);
+void FreeGroup(struct ClcGroup *group);
+int AddInfoItemToGroup(struct ClcGroup *group,int flags,const TCHAR *pszText);
+void RebuildEntireList(HWND hwnd,struct ClcData *dat);
+struct ClcGroup *RemoveItemFromGroup(HWND hwnd,struct ClcGroup *group,struct ClcContact *contact,int updateTotalCount);
+void DeleteItemFromTree(HWND hwnd,HANDLE hItem);
+void AddContactToTree(HWND hwnd,struct ClcData *dat,HANDLE hContact,int updateTotalCount,int checkHideOffline);
+void SortCLC(HWND hwnd,struct ClcData *dat,int useInsertionSort);
+int GetGroupContentsCount(struct ClcGroup *group,int visibleOnly);
+void SaveStateAndRebuildList(HWND hwnd,struct ClcData *dat);
+
+//clcmsgs.c
+LRESULT ProcessExternalMessages(HWND hwnd,struct ClcData *dat,UINT msg,WPARAM wParam,LPARAM lParam);
+
+//clcutils.c
+void EnsureVisible(HWND hwnd,struct ClcData *dat,int iItem,int partialOk);
+void RecalcScrollBar(HWND hwnd,struct ClcData *dat);
+void SetGroupExpand(HWND hwnd,struct ClcData *dat,struct ClcGroup *group,int newState);
+void DoSelectionDefaultAction(HWND hwnd,struct ClcData *dat);
+int FindRowByText(HWND hwnd,struct ClcData *dat,const TCHAR *text,int prefixOk);
+void EndRename(HWND hwnd,struct ClcData *dat,int save);
+void DeleteFromContactList(HWND hwnd,struct ClcData *dat);
+void BeginRenameSelection(HWND hwnd,struct ClcData *dat);
+char *GetGroupCountsText(struct ClcData *dat,struct ClcContact *contact);
+int HitTest(HWND hwnd,struct ClcData *dat,int testx,int testy,struct ClcContact **contact,struct ClcGroup **group,DWORD *flags);
+void ScrollTo(HWND hwnd,struct ClcData *dat,int desty,int noSmooth);
+
+int GetDropTargetInformation(HWND hwnd,struct ClcData *dat,POINT pt);
+int ClcStatusToPf2(int status);
+int IsHiddenMode(struct ClcData *dat,int status);
+void HideInfoTip(HWND hwnd,struct ClcData *dat);
+void NotifyNewContact(HWND hwnd,HANDLE hContact);
+void LoadClcOptions(HWND hwnd,struct ClcData *dat);
+void RecalculateGroupCheckboxes(HWND hwnd,struct ClcData *dat);
+void SetGroupChildCheckboxes(struct ClcGroup *group,int checked);
+void InvalidateItem(HWND hwnd,struct ClcData *dat,int iItem);
+
+int fnGetRowBottomY(struct ClcData *dat, int item);
+int fnGetRowHeight(struct ClcData *dat, int item);
+int fnGetRowTopY(struct ClcData *dat, int item);
+int fnGetRowTotalHeight(struct ClcData *dat);
+int fnRowHitTest(struct ClcData *dat, int y);
+
+//clcpaint.c
+void PaintClc(HWND hwnd,struct ClcData *dat,HDC hdc,RECT *rcPaint);
+
+//clcopts.c
+int ClcOptInit(WPARAM wParam,LPARAM lParam);
+DWORD GetDefaultExStyle(void);
+void GetFontSetting(int i,LOGFONTA *lf,COLORREF *colour);
+
+//clistsettings.c
+TCHAR* GetContactDisplayNameW( HANDLE hContact, int mode );
+char* u2a( wchar_t* src );
+wchar_t* a2u( char* src );
+
+//clcfiledrop.c
+void InitFileDropping(void);
+void FreeFileDropping(void);
+void RegisterFileDropping(HWND hwnd);
+void UnregisterFileDropping(HWND hwnd);
diff --git a/miranda-wine/src/modules/clist/clcfiledrop.c b/miranda-wine/src/modules/clist/clcfiledrop.c new file mode 100644 index 0000000..bc8701d --- /dev/null +++ b/miranda-wine/src/modules/clist/clcfiledrop.c @@ -0,0 +1,295 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+#include <shlobj.h>
+
+static IDropTargetVtbl dropTargetVtbl;
+
+struct CDropTarget
+{
+ IDropTargetVtbl *lpVtbl;
+ unsigned refCount;
+ IDropTargetHelper *pDropTargetHelper;
+}
+static dropTarget;
+
+static HWND hwndCurrentDrag = NULL;
+static int originalSelection;
+
+static STDMETHODIMP_(ULONG) CDropTarget_QueryInterface(struct CDropTarget *lpThis, REFIID riid, LPVOID * ppvObj)
+{
+ if (IsEqualIID(riid, &IID_IDropTarget)) {
+ *ppvObj = lpThis;
+ lpThis->lpVtbl->AddRef((IDropTarget *) lpThis);
+ return S_OK;
+ }
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+static STDMETHODIMP_(ULONG) CDropTarget_AddRef(struct CDropTarget *lpThis)
+{
+ return ++lpThis->refCount;
+}
+
+static STDMETHODIMP_(ULONG) CDropTarget_Release(struct CDropTarget *lpThis)
+{
+ if (lpThis->refCount == 1) {
+ if (lpThis->pDropTargetHelper)
+ lpThis->pDropTargetHelper->lpVtbl->Release(lpThis->pDropTargetHelper);
+ }
+ return --lpThis->refCount;
+}
+
+static HANDLE HContactFromPoint(HWND hwnd, struct ClcData *dat, int x, int y, int *hitLine)
+{
+ int hit;
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ char *szProto;
+ DWORD protoCaps;
+
+ hit = cli.pfnHitTest(hwnd, dat, x, y, &contact, NULL, &hitFlags);
+ if (hit == -1 || !(hitFlags & (CLCHT_ONITEMLABEL | CLCHT_ONITEMICON)) || contact->type != CLCIT_CONTACT)
+ return NULL;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) contact->hContact, 0);
+ if (szProto == NULL)
+ return NULL;
+ protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (!(protoCaps & PF1_FILESEND))
+ return NULL;
+ if (ID_STATUS_OFFLINE == DBGetContactSettingWord(contact->hContact, szProto, "Status", ID_STATUS_OFFLINE))
+ return NULL;
+ if (hitLine)
+ *hitLine = hit;
+ return contact->hContact;
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_DragOver(struct CDropTarget *lpThis, DWORD fKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ POINT shortPt;
+ struct ClcData *dat;
+ RECT clRect;
+ int hit;
+ HANDLE hContact;
+
+ if (lpThis->pDropTargetHelper && hwndCurrentDrag)
+ lpThis->pDropTargetHelper->lpVtbl->DragOver(lpThis->pDropTargetHelper, (POINT *) & pt, *pdwEffect);
+
+ *pdwEffect = 0;
+ if (hwndCurrentDrag == NULL) {
+ *pdwEffect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+ CallService(MS_CLIST_PAUSEAUTOHIDE, 0, 0);
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ ScreenToClient(hwndCurrentDrag, &shortPt);
+ GetClientRect(hwndCurrentDrag, &clRect);
+
+ if (shortPt.y < dat->dragAutoScrollHeight || shortPt.y >= clRect.bottom - dat->dragAutoScrollHeight) {
+ *pdwEffect |= DROPEFFECT_SCROLL;
+ cli.pfnScrollTo(hwndCurrentDrag, dat, dat->yScroll + (shortPt.y < dat->dragAutoScrollHeight ? -1 : 1) * dat->rowHeight * 2, 0);
+ }
+ hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, &hit);
+ if (hContact == NULL) {
+ hit = -1;
+ *pdwEffect |= DROPEFFECT_NONE;
+ }
+ else
+ *pdwEffect |= DROPEFFECT_COPY;
+
+ if (dat->selection != hit) {
+ dat->selection = hit;
+ cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE);
+ lpThis->pDropTargetHelper->lpVtbl->Show(lpThis->pDropTargetHelper, FALSE);
+ UpdateWindow(hwndCurrentDrag);
+ lpThis->pDropTargetHelper->lpVtbl->Show(lpThis->pDropTargetHelper, TRUE);
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_DragEnter(struct CDropTarget *lpThis, IDataObject * pData, DWORD fKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ HWND hwnd;
+ TCHAR szWindowClass[64];
+ POINT shortPt;
+
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ hwnd = WindowFromPoint(shortPt);
+ GetClassName(hwnd, szWindowClass, SIZEOF(szWindowClass));
+ if (!lstrcmp(szWindowClass, CLISTCONTROL_CLASS)) {
+ struct ClcData *dat;
+ hwndCurrentDrag = hwnd;
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+ originalSelection = dat->selection;
+ dat->showSelAlways = 1;
+ }
+ if (lpThis->pDropTargetHelper && hwndCurrentDrag)
+ lpThis->pDropTargetHelper->lpVtbl->DragEnter(lpThis->pDropTargetHelper, hwndCurrentDrag, pData, (POINT *) & pt, *pdwEffect);
+ return CDropTarget_DragOver(lpThis, fKeyState, pt, pdwEffect);
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_DragLeave(struct CDropTarget *lpThis)
+{
+ if (hwndCurrentDrag) {
+ struct ClcData *dat;
+ if (lpThis->pDropTargetHelper)
+ lpThis->pDropTargetHelper->lpVtbl->DragLeave(lpThis->pDropTargetHelper);
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+ dat->showSelAlways = 0;
+ dat->selection = originalSelection;
+ cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE);
+ }
+ hwndCurrentDrag = NULL;
+ return S_OK;
+}
+
+static void AddToFileList(char ***pppFiles, int *totalCount, const char *szFilename)
+{
+ *pppFiles = (char **) mir_realloc(*pppFiles, (++*totalCount + 1) * sizeof(char *));
+ (*pppFiles)[*totalCount] = NULL;
+ (*pppFiles)[*totalCount - 1] = mir_strdup(szFilename);
+ if (GetFileAttributesA(szFilename) & FILE_ATTRIBUTE_DIRECTORY) {
+ WIN32_FIND_DATAA fd;
+ HANDLE hFind;
+ char szPath[MAX_PATH];
+ lstrcpyA(szPath, szFilename);
+ lstrcatA(szPath, "\\*");
+ if (hFind = FindFirstFileA(szPath, &fd)) {
+ do {
+ if (!lstrcmpA(fd.cFileName, ".") || !lstrcmpA(fd.cFileName, ".."))
+ continue;
+ lstrcpyA(szPath, szFilename);
+ lstrcatA(szPath, "\\");
+ lstrcatA(szPath, fd.cFileName);
+ AddToFileList(pppFiles, totalCount, szPath);
+ } while (FindNextFileA(hFind, &fd));
+ FindClose(hFind);
+ }
+ }
+}
+
+static STDMETHODIMP_(HRESULT) CDropTarget_Drop(struct CDropTarget *lpThis, IDataObject * pData, DWORD fKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ STGMEDIUM stg;
+ HDROP hDrop;
+ POINT shortPt;
+ struct ClcData *dat;
+ HANDLE hContact;
+
+ if (lpThis->pDropTargetHelper && hwndCurrentDrag)
+ lpThis->pDropTargetHelper->lpVtbl->Drop(lpThis->pDropTargetHelper, pData, (POINT *) & pt, *pdwEffect);
+
+ *pdwEffect = DROPEFFECT_NONE;
+ if (hwndCurrentDrag == NULL || S_OK != pData->lpVtbl->GetData(pData, &fe, &stg))
+ return S_OK;
+ hDrop = (HDROP) stg.hGlobal;
+ dat = (struct ClcData *) GetWindowLong(hwndCurrentDrag, 0);
+
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ ScreenToClient(hwndCurrentDrag, &shortPt);
+ hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, NULL);
+ if (hContact != NULL) {
+ char **ppFiles = NULL;
+ char szFilename[MAX_PATH];
+ int fileCount, totalCount = 0, i;
+
+ fileCount = DragQueryFile(hDrop, -1, NULL, 0);
+ ppFiles = NULL;
+ for (i = 0; i < fileCount; i++) {
+ DragQueryFileA(hDrop, i, szFilename, SIZEOF(szFilename));
+ AddToFileList(&ppFiles, &totalCount, szFilename);
+ }
+
+ if (!CallService(MS_CLIST_CONTACTFILESDROPPED, (WPARAM) hContact, (LPARAM) ppFiles))
+ *pdwEffect = DROPEFFECT_COPY;
+
+ for (i = 0; ppFiles[i]; i++)
+ mir_free(ppFiles[i]);
+ mir_free(ppFiles);
+ }
+
+ if (stg.pUnkForRelease)
+ stg.pUnkForRelease->lpVtbl->Release(stg.pUnkForRelease);
+ else
+ GlobalFree(stg.hGlobal);
+
+ CDropTarget_DragLeave(lpThis);
+ return S_OK;
+}
+
+static VOID CALLBACK CreateDropTargetHelperTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+ /* macro defines needed CLSID and IID declarations since
+ they have to be referenced */
+#ifndef CLSID_DragDropHelper
+#define MDEF_CLSID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ const CLSID name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+
+ MDEF_CLSID(IID_IDropTargetHelper, 0x4657278b, 0x411b, 0x11d2, 0x83, 0x9a, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
+ MDEF_CLSID(CLSID_DragDropHelper, 0x4657278a, 0x411b, 0x11d2, 0x83, 0x9a, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0);
+#endif
+ KillTimer(hwnd, idEvent);
+ //This is a ludicrously slow function (~200ms) so we delay load it a bit.
+ if (S_OK != CoCreateInstance(&CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, &IID_IDropTargetHelper, &dropTarget.pDropTargetHelper))
+ dropTarget.pDropTargetHelper = NULL;
+}
+
+void InitFileDropping(void)
+{
+ OleInitialize(NULL);
+ dropTarget.lpVtbl = &dropTargetVtbl;
+ dropTarget.lpVtbl->AddRef = (ULONG(__stdcall *) (IDropTarget *)) CDropTarget_AddRef;
+ dropTarget.lpVtbl->Release = (ULONG(__stdcall *) (IDropTarget *)) CDropTarget_Release;
+ dropTarget.lpVtbl->QueryInterface = (ULONG(__stdcall *) (IDropTarget *, REFIID, PVOID *)) CDropTarget_QueryInterface;
+ dropTarget.lpVtbl->DragEnter = (HRESULT(__stdcall *) (IDropTarget *, IDataObject *, DWORD, POINTL, PDWORD)) CDropTarget_DragEnter;
+ dropTarget.lpVtbl->DragOver = (HRESULT(__stdcall *) (IDropTarget *, DWORD, POINTL, PDWORD)) CDropTarget_DragOver;
+ dropTarget.lpVtbl->DragLeave = (HRESULT(__stdcall *) (IDropTarget *)) CDropTarget_DragLeave;
+ dropTarget.lpVtbl->Drop = (HRESULT(__stdcall *) (IDropTarget *, IDataObject *, DWORD, POINTL, PDWORD)) CDropTarget_Drop;
+ dropTarget.refCount = 0;
+ dropTarget.pDropTargetHelper = NULL;
+ SetTimer(NULL, 1, 1000, CreateDropTargetHelperTimerProc);
+}
+
+void FreeFileDropping(void)
+{
+ OleUninitialize();
+}
+
+void fnRegisterFileDropping(HWND hwnd)
+{
+ RegisterDragDrop(hwnd, (IDropTarget *) & dropTarget);
+}
+
+void fnUnregisterFileDropping(HWND hwnd)
+{
+ RevokeDragDrop(hwnd);
+}
diff --git a/miranda-wine/src/modules/clist/clcidents.c b/miranda-wine/src/modules/clist/clcidents.c new file mode 100644 index 0000000..66baeed --- /dev/null +++ b/miranda-wine/src/modules/clist/clcidents.c @@ -0,0 +1,201 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+/* the CLC uses 3 different ways to identify elements in its list, this file
+contains routines to convert between them.
+
+1) struct ClcContact/struct ClcGroup pair. Only ever used within the duration
+ of a single operation, but used at some point in nearly everything
+2) index integer. The 0-based number of the item from the top. Only visible
+ items are counted (ie not closed groups). Used for saving selection and drag
+ highlight
+3) hItem handle. Either the hContact or (hGroup|HCONTACT_ISGROUP). Used
+ exclusively externally
+
+1->2: GetRowsPriorTo()
+1->3: ContactToHItem()
+3->1: FindItem()
+2->1: GetRowByIndex()
+*/
+
+int fnGetRowsPriorTo(struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex)
+{
+ int count = 0;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group == subgroup && contactIndex == group->scanIndex)
+ return count;
+ count++;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group == subgroup && contactIndex == -1)
+ return count - 1;
+ if (group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+int fnFindItem(HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible)
+{
+ int index = 0;
+ int nowVisible = 1;
+ struct ClcGroup *group = &dat->list;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ struct ClcGroup *tgroup;
+ group = group->parent;
+ if (group == NULL)
+ break;
+ nowVisible = 1;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ if (!group->expanded) {
+ nowVisible = 0;
+ break;
+ }
+ group->scanIndex++;
+ continue;
+ }
+ if (nowVisible)
+ index++;
+ if ((IsHContactGroup(hItem) && group->cl.items[group->scanIndex]->type == CLCIT_GROUP
+ && ((unsigned) hItem & ~HCONTACT_ISGROUP) == group->cl.items[group->scanIndex]->groupId) || (IsHContactContact(hItem)
+ && group->cl.items[group->scanIndex]->type == CLCIT_CONTACT
+ && group->cl.items[group->scanIndex]->hContact == hItem) || (IsHContactInfo(hItem)
+ && group->cl.items[group->scanIndex]->type == CLCIT_INFO
+ && group->cl.items[group->scanIndex]->hContact == (HANDLE) ((unsigned)hItem & ~HCONTACT_ISINFO)))
+ {
+ if (isVisible) {
+ if (!nowVisible)
+ *isVisible = 0;
+ else {
+ int posY = cli.pfnGetRowTopY(dat, index+1);
+ if (posY < dat->yScroll)
+ *isVisible = 0;
+ else {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ if (posY >= dat->yScroll + clRect.bottom)
+ *isVisible = 0;
+ else
+ *isVisible = 1;
+ }
+ }
+ }
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return 1;
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ nowVisible &= group->expanded;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return 0;
+}
+
+int fnGetRowByIndex(struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup)
+{
+ int index = 0;
+ struct ClcGroup *group = &dat->list;
+
+ if (testindex<0)
+ return (-1);
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (testindex == index) {
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return index;
+ }
+ index++;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+HANDLE fnContactToHItem(struct ClcContact * contact)
+{
+ switch (contact->type) {
+ case CLCIT_CONTACT:
+ return contact->hContact;
+ case CLCIT_GROUP:
+ return (HANDLE) (contact->groupId | HCONTACT_ISGROUP);
+ case CLCIT_INFO:
+ return (HANDLE) ((DWORD) contact->hContact | HCONTACT_ISINFO);
+ }
+ return NULL;
+}
+
+HANDLE fnContactToItemHandle(struct ClcContact * contact, DWORD * nmFlags)
+{
+ switch (contact->type) {
+ case CLCIT_CONTACT:
+ return contact->hContact;
+ case CLCIT_GROUP:
+ if (nmFlags)
+ *nmFlags |= CLNF_ISGROUP;
+ return (HANDLE) contact->groupId;
+ case CLCIT_INFO:
+ if (nmFlags)
+ *nmFlags |= CLNF_ISINFO;
+ return (HANDLE) ((DWORD) contact->hContact | HCONTACT_ISINFO);
+ }
+ return NULL;
+}
diff --git a/miranda-wine/src/modules/clist/clcitems.c b/miranda-wine/src/modules/clist/clcitems.c new file mode 100644 index 0000000..b25df7f --- /dev/null +++ b/miranda-wine/src/modules/clist/clcitems.c @@ -0,0 +1,721 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+//routines for managing adding/removal of items in the list, including sorting
+
+int fnAddItemToGroup(struct ClcGroup *group, int iAboveItem)
+{
+ struct ClcContact* newItem = cli.pfnCreateClcContact();
+ newItem->type = CLCIT_DIVIDER;
+ newItem->flags = 0;
+ newItem->szText[0] = '\0';
+ memset( newItem->iExtraImage, 0xFF, SIZEOF(newItem->iExtraImage));
+
+ List_Insert(( SortedList* )&group->cl, newItem, iAboveItem );
+ return iAboveItem;
+}
+
+struct ClcGroup* fnAddGroup(HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
+{
+ TCHAR *pBackslash, *pNextField, szThisField[ SIZEOF(dat->list.cl.items[0]->szText) ];
+ struct ClcGroup *group = &dat->list;
+ int i, compareResult;
+
+ dat->needsResort = 1;
+ if (!(GetWindowLong(hwnd, GWL_STYLE) & CLS_USEGROUPS))
+ return &dat->list;
+
+ pNextField = ( TCHAR* )szName;
+ do {
+ pBackslash = _tcschr(pNextField, '\\');
+ if (pBackslash == NULL) {
+ lstrcpyn(szThisField, pNextField, SIZEOF(szThisField));
+ pNextField = NULL;
+ }
+ else {
+ lstrcpyn(szThisField, pNextField, min( SIZEOF(szThisField), pBackslash - pNextField + 1 ));
+ pNextField = pBackslash + 1;
+ }
+ compareResult = 1;
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (group->cl.items[i]->type != CLCIT_GROUP)
+ continue;
+ compareResult = lstrcmp(szThisField, group->cl.items[i]->szText);
+ if (compareResult == 0) {
+ if (pNextField == NULL && flags != (DWORD) - 1) {
+ group->cl.items[i]->groupId = (WORD) groupId;
+ group = group->cl.items[i]->group;
+ group->expanded = (flags & GROUPF_EXPANDED) != 0;
+ group->hideOffline = (flags & GROUPF_HIDEOFFLINE) != 0;
+ group->groupId = groupId;
+ }
+ else
+ group = group->cl.items[i]->group;
+ break;
+ }
+ if (pNextField == NULL && group->cl.items[i]->groupId == 0)
+ break;
+ if (groupId && group->cl.items[i]->groupId > groupId)
+ break;
+ }
+ if (compareResult) {
+ if (groupId == 0)
+ return NULL;
+ i = cli.pfnAddItemToGroup(group, i);
+ group->cl.items[i]->type = CLCIT_GROUP;
+ lstrcpyn(group->cl.items[i]->szText, szThisField, SIZEOF( group->cl.items[i]->szText ));
+ group->cl.items[i]->groupId = (WORD) (pNextField ? 0 : groupId);
+ group->cl.items[i]->group = (struct ClcGroup *) mir_alloc(sizeof(struct ClcGroup));
+ group->cl.items[i]->group->parent = group;
+ group = group->cl.items[i]->group;
+ memset( &group->cl, 0, sizeof( group->cl ));
+ group->cl.increment = 10;
+ if (flags == (DWORD) - 1 || pNextField != NULL) {
+ group->expanded = 0;
+ group->hideOffline = 0;
+ }
+ else {
+ group->expanded = (flags & GROUPF_EXPANDED) != 0;
+ group->hideOffline = (flags & GROUPF_HIDEOFFLINE) != 0;
+ }
+ group->groupId = pNextField ? 0 : groupId;
+ group->totalMembers = 0;
+ if (flags != (DWORD) - 1 && pNextField == NULL && calcTotalMembers) {
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ ClcCacheEntryBase* cache = cli.pfnGetCacheEntry( hContact );
+ if ( !lstrcmp( cache->group, szName) && (style & CLS_SHOWHIDDEN || !cache->isHidden ))
+ group->totalMembers++;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ }
+ }
+ } while (pNextField);
+ return group;
+}
+
+void fnFreeContact(struct ClcContact* p)
+{
+ if (p->type == CLCIT_GROUP) {
+ cli.pfnFreeGroup(p->group);
+ mir_free(p->group);
+} }
+
+void fnFreeGroup(struct ClcGroup *group)
+{
+ int i;
+ for (i = 0; i < group->cl.count; i++) {
+ cli.pfnFreeContact(group->cl.items[i]);
+ mir_free(group->cl.items[i]);
+ }
+ if (group->cl.items)
+ mir_free(group->cl.items);
+ group->cl.limit = group->cl.count = 0;
+ group->cl.items = NULL;
+}
+
+static int iInfoItemUniqueHandle = 0;
+int fnAddInfoItemToGroup(struct ClcGroup *group, int flags, const TCHAR *pszText)
+{
+ int i = 0;
+
+ if (flags & CLCIIF_BELOWCONTACTS)
+ i = group->cl.count;
+ else if (flags & CLCIIF_BELOWGROUPS) {
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ }
+ else
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type != CLCIT_INFO)
+ break;
+ i = cli.pfnAddItemToGroup(group, i);
+ iInfoItemUniqueHandle = (iInfoItemUniqueHandle + 1) & 0xFFFF;
+ if (iInfoItemUniqueHandle == 0)
+ ++iInfoItemUniqueHandle;
+ group->cl.items[i]->type = CLCIT_INFO;
+ group->cl.items[i]->flags = (BYTE) flags;
+ group->cl.items[i]->hContact = (HANDLE)++ iInfoItemUniqueHandle;
+ lstrcpyn(group->cl.items[i]->szText, pszText, SIZEOF( group->cl.items[i]->szText ));
+ return i;
+}
+
+int fnAddContactToGroup(struct ClcData *dat, struct ClcGroup *group, HANDLE hContact)
+{
+ char *szProto;
+ WORD apparentMode;
+ DWORD idleMode;
+
+ int i, index = -1;
+
+ dat->needsResort = 1;
+ for (i = group->cl.count - 1; i >= 0; i--) {
+ if (group->cl.items[i]->hContact == hContact )
+ return i;
+
+ if ( index == -1 )
+ if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags & CLCIIF_BELOWCONTACTS))
+ index = i;
+ }
+
+ i = cli.pfnAddItemToGroup(group, index + 1);
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ group->cl.items[i]->type = CLCIT_CONTACT;
+ group->cl.items[i]->iImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) hContact, 0);
+ group->cl.items[i]->hContact = hContact;
+ group->cl.items[i]->proto = szProto;
+ if (szProto != NULL && !cli.pfnIsHiddenMode(dat, DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ group->cl.items[i]->flags |= CONTACTF_ONLINE;
+ apparentMode = szProto != NULL ? DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) : 0;
+ if (apparentMode == ID_STATUS_OFFLINE)
+ group->cl.items[i]->flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE)
+ group->cl.items[i]->flags |= CONTACTF_VISTO;
+ else if (apparentMode)
+ group->cl.items[i]->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ group->cl.items[i]->flags |= CONTACTF_NOTONLIST;
+ idleMode = szProto != NULL ? DBGetContactSettingDword(hContact, szProto, "IdleTS", 0) : 0;
+ if (idleMode)
+ group->cl.items[i]->flags |= CONTACTF_IDLE;
+ lstrcpyn(group->cl.items[i]->szText, cli.pfnGetContactDisplayName(hContact,0), SIZEOF(group->cl.items[i]->szText));
+
+ { ClcCacheEntryBase* p = cli.pfnGetCacheEntry(hContact);
+ if ( p != NULL ) {
+ if ( p->group ) mir_free( p->group );
+ p->group = NULL;
+ } }
+
+ return i;
+}
+
+void fnAddContactToTree(HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline)
+{
+ struct ClcGroup *group;
+ DBVARIANT dbv;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ WORD status;
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ dat->needsResort = 1;
+ if (style & CLS_NOHIDEOFFLINE)
+ checkHideOffline = 0;
+ if (checkHideOffline) {
+ if (szProto == NULL)
+ status = ID_STATUS_OFFLINE;
+ else
+ status = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ }
+
+ if ( DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ if (group == NULL) {
+ int i, len;
+ DWORD groupFlags;
+ TCHAR *szGroupName;
+ if (!(style & CLS_HIDEEMPTYGROUPS)) {
+ mir_free(dbv.pszVal);
+ return;
+ }
+ if (checkHideOffline && cli.pfnIsHiddenMode(dat, status)) {
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) {
+ mir_free(dbv.pszVal);
+ return;
+ } //never happens
+ if (!lstrcmp(szGroupName, dbv.ptszVal))
+ break;
+ }
+ if (groupFlags & GROUPF_HIDEOFFLINE) {
+ mir_free(dbv.pszVal);
+ return;
+ }
+ }
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) {
+ mir_free(dbv.pszVal);
+ return;
+ } //never happens
+ if (!lstrcmp(szGroupName, dbv.ptszVal))
+ break;
+ len = lstrlen(szGroupName);
+ if (!_tcsncmp(szGroupName, dbv.ptszVal, len) && dbv.ptszVal[len] == '\\')
+ cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 1);
+ }
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, groupFlags, i, 1);
+ }
+ mir_free(dbv.pszVal);
+ }
+ if (checkHideOffline) {
+ if (cli.pfnIsHiddenMode(dat, status) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ if (updateTotalCount)
+ group->totalMembers++;
+ return;
+ }
+ }
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ if (updateTotalCount)
+ group->totalMembers++;
+}
+
+struct ClcGroup* fnRemoveItemFromGroup(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount)
+{
+ int iContact;
+ if (( iContact = List_IndexOf(( SortedList* )&group->cl, contact )) == -1 )
+ return group;
+
+ if (updateTotalCount && contact->type == CLCIT_CONTACT)
+ group->totalMembers--;
+
+ { ClcCacheEntryBase* p = cli.pfnGetCacheEntry(contact->hContact);
+ if ( p != NULL ) {
+ if ( p->group ) mir_free( p->group );
+ p->group = NULL;
+ } }
+
+ cli.pfnFreeContact( group->cl.items[iContact] );
+ mir_free( group->cl.items[iContact] );
+ List_Remove(( SortedList* )&group->cl, iContact );
+
+ if ((GetWindowLong(hwnd, GWL_STYLE) & CLS_HIDEEMPTYGROUPS) && group->cl.count == 0) {
+ int i;
+ if (group->parent == NULL)
+ return group;
+ for (i = 0; i < group->parent->cl.count; i++)
+ if (group->parent->cl.items[i]->type == CLCIT_GROUP && group->parent->cl.items[i]->groupId == group->groupId)
+ break;
+ if (i == group->parent->cl.count)
+ return group; //never happens
+ return cli.pfnRemoveItemFromGroup(hwnd, group->parent, group->parent->cl.items[i], 0);
+ }
+ return group;
+}
+
+void fnDeleteItemFromTree(HWND hwnd, HANDLE hItem)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ struct ClcData *dat = (struct ClcData *) GetWindowLong(hwnd, 0);
+
+ dat->needsResort = 1;
+ if (!cli.pfnFindItem(hwnd, dat, hItem, &contact, &group, NULL)) {
+ DBVARIANT dbv;
+ int i, nameOffset;
+ if (!IsHContactContact(hItem))
+ return;
+ if (DBGetContactSettingTString(hItem, "CList", "Group", &dbv))
+ return;
+
+ //decrease member counts of all parent groups too
+ group = &dat->list;
+ nameOffset = 0;
+ for (i = 0;; i++) {
+ if (group->scanIndex == group->cl.count)
+ break;
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ int len = lstrlen(group->cl.items[i]->szText);
+ if (!_tcsncmp(group->cl.items[i]->szText, dbv.ptszVal + nameOffset, len) &&
+ (dbv.ptszVal[nameOffset + len] == '\\' || dbv.ptszVal[nameOffset + len] == '\0')) {
+ group->totalMembers--;
+ if (dbv.ptszVal[nameOffset + len] == '\0')
+ break;
+ }
+ }
+ }
+ mir_free(dbv.ptszVal);
+ }
+ else
+ cli.pfnRemoveItemFromGroup(hwnd, group, contact, 1);
+}
+
+void fnRebuildEntireList(HWND hwnd, struct ClcData *dat)
+{
+ char *szProto;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ HANDLE hContact;
+ struct ClcGroup *group;
+ DBVARIANT dbv;
+
+ dat->list.expanded = 1;
+ dat->list.hideOffline = DBGetContactSettingByte(NULL, "CLC", "HideOfflineRoot", 0);
+ dat->list.cl.count = dat->list.cl.limit = 0;
+ dat->selection = -1;
+ {
+ int i;
+ TCHAR *szGroupName;
+ DWORD groupFlags;
+
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL)
+ break;
+ cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
+ }
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ if (style & CLS_SHOWHIDDEN || !DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) {
+ if (DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ mir_free(dbv.ptszVal);
+ }
+
+ if (group != NULL) {
+ group->totalMembers++;
+ if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL) {
+ if (!cli.pfnIsHiddenMode(dat, ID_STATUS_OFFLINE))
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ else if (!cli.pfnIsHiddenMode(dat, DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ else cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+ if (style & CLS_HIDEEMPTYGROUPS) {
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group->cl.count == 0) {
+ group = cli.pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
+ }
+ else {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ }
+ continue;
+ }
+ group->scanIndex++;
+ }
+ }
+
+ cli.pfnSortCLC(hwnd, dat, 0);
+}
+
+int fnGetGroupContentsCount(struct ClcGroup *group, int visibleOnly)
+{
+ int count = group->cl.count;
+ struct ClcGroup *topgroup = group;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!visibleOnly || group->cl.items[group->scanIndex]->group->expanded)) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ count += group->cl.count;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return count;
+}
+
+static int __cdecl GroupSortProc(const struct ClcContact **contact1, const struct ClcContact **contact2)
+{
+ return lstrcmpi(contact1[0]->szText, contact2[0]->szText);
+}
+
+static int __cdecl ContactSortProc(const struct ClcContact **contact1, const struct ClcContact **contact2)
+{
+ int result = cli.pfnCompareContacts( contact1[0], contact2[0] );
+ if (result)
+ return result;
+ //nothing to distinguish them, so make sure they stay in the same order
+ return (int) contact2[0]->hContact - (int) contact1[0]->hContact;
+}
+
+static void InsertionSort(struct ClcContact **pContactArray, int nArray, int (*CompareProc) (const void *, const void *))
+{
+ int i, j;
+ struct ClcContact* testElement;
+
+ for (i = 1; i < nArray; i++) {
+ if (CompareProc(&pContactArray[i - 1], &pContactArray[i]) > 0) {
+ testElement = pContactArray[i];
+ for (j = i - 2; j >= 0; j--)
+ if (CompareProc(&pContactArray[j], &testElement) <= 0)
+ break;
+ j++;
+ memmove(&pContactArray[j + 1], &pContactArray[j], sizeof(void*) * (i - j));
+ pContactArray[j] = testElement;
+} } }
+
+static void SortGroup(struct ClcData *dat, struct ClcGroup *group, int useInsertionSort)
+{
+ int i, sortCount;
+
+ for (i = group->cl.count - 1; i >= 0; i--) {
+ if (group->cl.items[i]->type == CLCIT_DIVIDER) {
+ mir_free( group->cl.items[i] );
+ List_Remove(( SortedList* )&group->cl, i );
+ } }
+
+ for (i = 0; i < group->cl.count; i++)
+ if (group->cl.items[i]->type != CLCIT_INFO)
+ break;
+ if (i > group->cl.count - 2)
+ return;
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ if (dat->exStyle & CLS_EX_SORTGROUPSALPHA) {
+ for (sortCount = 0; i + sortCount < group->cl.count; sortCount++)
+ if (group->cl.items[i + sortCount]->type != CLCIT_GROUP)
+ break;
+ qsort(group->cl.items + i, sortCount, sizeof(void*), GroupSortProc);
+ i = i + sortCount;
+ }
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (group->cl.count - i < 2)
+ return;
+ }
+ for (sortCount = 0; i + sortCount < group->cl.count; sortCount++)
+ if (group->cl.items[i + sortCount]->type != CLCIT_CONTACT)
+ break;
+ if (useInsertionSort)
+ InsertionSort(group->cl.items + i, sortCount, ContactSortProc);
+ else
+ qsort(group->cl.items + i, sortCount, sizeof(void*), ContactSortProc);
+ if (dat->exStyle & CLS_EX_DIVIDERONOFF) {
+ int prevContactOnline = 0;
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type != CLCIT_CONTACT)
+ continue;
+ if (group->cl.items[i]->flags & CONTACTF_ONLINE)
+ prevContactOnline = 1;
+ else {
+ if (prevContactOnline) {
+ i = cli.pfnAddItemToGroup(group, i);
+ group->cl.items[i]->type = CLCIT_DIVIDER;
+ lstrcpy(group->cl.items[i]->szText, TranslateT("Offline"));
+ }
+ break;
+} } } }
+
+void fnSortCLC(HWND hwnd, struct ClcData *dat, int useInsertionSort)
+{
+ struct ClcContact *selcontact;
+ struct ClcGroup *group = &dat->list, *selgroup;
+ int dividers = dat->exStyle & CLS_EX_DIVIDERONOFF;
+ HANDLE hSelItem;
+
+ if ( dat->needsResort ) {
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
+ hSelItem = NULL;
+ else
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ group->scanIndex = 0;
+ SortGroup(dat, group, useInsertionSort);
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ SortGroup(dat, group, useInsertionSort);
+ continue;
+ }
+ group->scanIndex++;
+ }
+ if (hSelItem)
+ if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl,selcontact));
+
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ }
+ dat->needsResort = 0;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+}
+
+struct SavedContactState_t
+{
+ HANDLE hContact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ int checked;
+};
+
+struct SavedGroupState_t
+{
+ int groupId, expanded;
+};
+
+struct SavedInfoState_t
+{
+ int parentId;
+ struct ClcContact contact;
+};
+
+void fnSaveStateAndRebuildList(HWND hwnd, struct ClcData *dat)
+{
+ NMCLISTCONTROL nm;
+ int i, j;
+ struct SavedGroupState_t *savedGroup = NULL;
+ int savedGroupCount = 0, savedGroupAlloced = 0;
+ struct SavedContactState_t *savedContact = NULL;
+ int savedContactCount = 0, savedContactAlloced = 0;
+ struct SavedInfoState_t *savedInfo = NULL;
+ int savedInfoCount = 0, savedInfoAlloced = 0;
+ struct ClcGroup *group;
+ struct ClcContact *contact;
+
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnEndRename(hwnd, dat, 1);
+
+ dat->needsResort = 1;
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ if (++savedGroupCount > savedGroupAlloced) {
+ savedGroupAlloced += 8;
+ savedGroup = (struct SavedGroupState_t *) mir_realloc(savedGroup, sizeof(struct SavedGroupState_t) * savedGroupAlloced);
+ }
+ savedGroup[savedGroupCount - 1].groupId = group->groupId;
+ savedGroup[savedGroupCount - 1].expanded = group->expanded;
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ if (++savedContactCount > savedContactAlloced) {
+ savedContactAlloced += 16;
+ savedContact = (struct SavedContactState_t *) mir_realloc(savedContact, sizeof(struct SavedContactState_t) * savedContactAlloced);
+ }
+ savedContact[savedContactCount - 1].hContact = group->cl.items[group->scanIndex]->hContact;
+ CopyMemory(savedContact[savedContactCount - 1].iExtraImage, group->cl.items[group->scanIndex]->iExtraImage,
+ sizeof(group->cl.items[group->scanIndex]->iExtraImage));
+ savedContact[savedContactCount - 1].checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
+ if (++savedInfoCount > savedInfoAlloced) {
+ savedInfoAlloced += 4;
+ savedInfo = (struct SavedInfoState_t *) mir_realloc(savedInfo, sizeof(struct SavedInfoState_t) * savedInfoAlloced);
+ }
+ if (group->parent == NULL)
+ savedInfo[savedInfoCount - 1].parentId = -1;
+ else
+ savedInfo[savedInfoCount - 1].parentId = group->groupId;
+ savedInfo[savedInfoCount - 1].contact = *group->cl.items[group->scanIndex];
+ }
+ group->scanIndex++;
+ }
+
+ cli.pfnFreeGroup(&dat->list);
+ cli.pfnRebuildEntireList(hwnd, dat);
+
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ for (i = 0; i < savedGroupCount; i++)
+ if (savedGroup[i].groupId == group->groupId) {
+ group->expanded = savedGroup[i].expanded;
+ break;
+ }
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ for (i = 0; i < savedContactCount; i++)
+ if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) {
+ CopyMemory(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage,
+ SIZEOF(group->cl.items[group->scanIndex]->iExtraImage));
+ if (savedContact[i].checked)
+ group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED;
+ break;
+ }
+ }
+ group->scanIndex++;
+ }
+ if (savedGroup)
+ mir_free(savedGroup);
+ if (savedContact)
+ mir_free(savedContact);
+ for (i = 0; i < savedInfoCount; i++) {
+ if (savedInfo[i].parentId == -1)
+ group = &dat->list;
+ else {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) (savedInfo[i].parentId | HCONTACT_ISGROUP), &contact, NULL, NULL))
+ continue;
+ group = contact->group;
+ }
+ j = cli.pfnAddInfoItemToGroup(group, savedInfo[i].contact.flags, _T(""));
+ *group->cl.items[j] = savedInfo[i].contact;
+ }
+ if (savedInfo)
+ mir_free(savedInfo);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
diff --git a/miranda-wine/src/modules/clist/clcmsgs.c b/miranda-wine/src/modules/clist/clcmsgs.c new file mode 100644 index 0000000..c481715 --- /dev/null +++ b/miranda-wine/src/modules/clist/clcmsgs.c @@ -0,0 +1,462 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+//processing of all the CLM_ messages incoming
+
+LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case CLM_ADDCONTACT:
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 0);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ cli.pfnSortCLC(hwnd, dat, 1);
+ break;
+
+ case CLM_ADDGROUP:
+ {
+ DWORD groupFlags;
+ TCHAR *szName = cli.pfnGetGroupName(wParam, &groupFlags);
+ if (szName == NULL)
+ break;
+ cli.pfnAddGroup(hwnd, dat, szName, groupFlags, wParam, 0);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ break;
+ }
+
+ case CLM_ADDINFOITEMA:
+ case CLM_ADDINFOITEMW:
+ {
+ int i;
+ struct ClcContact *groupContact;
+ struct ClcGroup *group;
+ CLCINFOITEM *cii = (CLCINFOITEM *) lParam;
+ if (cii==NULL || cii->cbSize != sizeof(CLCINFOITEM))
+ return (LRESULT) (HANDLE) NULL;
+ if (cii->hParentGroup == NULL)
+ group = &dat->list;
+ else {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) ((DWORD) cii->hParentGroup | HCONTACT_ISGROUP), &groupContact, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ group = groupContact->group;
+ }
+#if defined( _UNICODE )
+ if ( msg == CLM_ADDINFOITEMA )
+ { WCHAR* wszText = a2u(( char* )cii->pszText );
+ i = cli.pfnAddInfoItemToGroup(group, cii->flags, wszText);
+ mir_free( wszText );
+ }
+ else i = cli.pfnAddInfoItemToGroup(group, cii->flags, cii->pszText);
+#else
+ i = cli.pfnAddInfoItemToGroup(group, cii->flags, cii->pszText);
+#endif
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ return (LRESULT) group->cl.items[i]->hContact | HCONTACT_ISINFO;
+ }
+
+ case CLM_AUTOREBUILD:
+ KillTimer(hwnd,TIMERID_REBUILDAFTER);
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+
+ case CLM_DELETEITEM:
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ cli.pfnSortCLC(hwnd, dat, 1);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ break;
+
+ case CLM_EDITLABEL:
+ SendMessage(hwnd, CLM_SELECTITEM, wParam, 0);
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+
+ case CLM_ENDEDITLABELNOW:
+ cli.pfnEndRename(hwnd, dat, wParam);
+ break;
+
+ case CLM_ENSUREVISIBLE:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group, *tgroup;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, tgroup, 1);
+ cli.pfnEnsureVisible(hwnd, dat, cli.pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*)&group->cl,contact)), 0);
+ break;
+ }
+
+ case CLM_EXPAND:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (contact->type != CLCIT_GROUP)
+ break;
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, lParam);
+ break;
+ }
+
+ case CLM_FINDCONTACT:
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, NULL, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ return wParam;
+
+ case CLM_FINDGROUP:
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) (wParam | HCONTACT_ISGROUP), NULL, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ return wParam | HCONTACT_ISGROUP;
+
+ case CLM_GETBKCOLOR:
+ return dat->bkColour;
+
+ case CLM_GETCHECKMARK:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ return (contact->flags & CONTACTF_CHECKED) != 0;
+ }
+
+ case CLM_GETCOUNT:
+ return cli.pfnGetGroupContentsCount(&dat->list, 0);
+
+ case CLM_GETEDITCONTROL:
+ return (LRESULT) dat->hwndRenameEdit;
+
+ case CLM_GETEXPAND:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return CLE_INVALID;
+ if (contact->type != CLCIT_GROUP)
+ return CLE_INVALID;
+ return contact->group->expanded;
+ }
+
+ case CLM_GETEXTRACOLUMNS:
+ return dat->extraColumnsCount;
+
+ case CLM_GETEXTRAIMAGE:
+ {
+ struct ClcContact *contact;
+ if (LOWORD(lParam) >= dat->extraColumnsCount)
+ return 0xFF;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0xFF;
+ return contact->iExtraImage[LOWORD(lParam)];
+ }
+
+ case CLM_GETEXTRAIMAGELIST:
+ return (LRESULT) dat->himlExtraColumns;
+
+ case CLM_GETFONT:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ return 0;
+ return (LRESULT) dat->fontInfo[wParam].hFont;
+
+ case CLM_GETHIDEOFFLINEROOT:
+ return DBGetContactSettingByte(NULL, "CLC", "HideOfflineRoot", 0);
+
+ case CLM_GETINDENT:
+ return dat->groupIndent;
+
+ case CLM_GETISEARCHSTRING:
+ lstrcpy(( TCHAR* ) lParam, dat->szQuickSearch);
+ return lstrlen(dat->szQuickSearch);
+
+ case CLM_GETITEMTEXT:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ lstrcpy(( TCHAR* ) lParam, contact->szText);
+ return lstrlen(contact->szText);
+ }
+
+ case CLM_GETITEMTYPE:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return CLCIT_INVALID;
+ return contact->type;
+ }
+
+ case CLM_GETLEFTMARGIN:
+ return dat->leftMargin;
+
+ case CLM_GETNEXTITEM:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ int i;
+
+ if (wParam != CLGN_ROOT) {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) lParam, &contact, &group, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ i = List_IndexOf((SortedList*)&group->cl,contact);
+ }
+ switch (wParam) {
+ case CLGN_ROOT:
+ if (dat->list.cl.count)
+ return (LRESULT) cli.pfnContactToHItem(dat->list.cl.items[0]);
+ else
+ return (LRESULT) (HANDLE) NULL;
+ case CLGN_CHILD:
+ if (contact->type != CLCIT_GROUP)
+ return (LRESULT) (HANDLE) NULL;
+ group = contact->group;
+ if (group->cl.count == 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[0]);
+ case CLGN_PARENT:
+ return group->groupId | HCONTACT_ISGROUP;
+ case CLGN_NEXT:
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i + 1]);
+ case CLGN_PREVIOUS:
+ if (i <= 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i - 1]);
+ case CLGN_NEXTCONTACT:
+ for (i++; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ case CLGN_PREVIOUSCONTACT:
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ for (i--; i >= 0; i--)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (i < 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ case CLGN_NEXTGROUP:
+ for (i++; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_GROUP)
+ break;
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ case CLGN_PREVIOUSGROUP:
+ if (i >= group->cl.count)
+ return (LRESULT) (HANDLE) NULL;
+ for (i--; i >= 0; i--)
+ if (group->cl.items[i]->type == CLCIT_GROUP)
+ break;
+ if (i < 0)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ }
+ return (LRESULT) (HANDLE) NULL;
+ }
+
+ case CLM_GETSCROLLTIME:
+ return dat->scrollTime;
+
+ case CLM_GETSELECTION:
+ {
+ struct ClcContact *contact;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(contact);
+ }
+
+ case CLM_GETTEXTCOLOR:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ return 0;
+ return (LRESULT) dat->fontInfo[wParam].colour;
+
+ case CLM_HITTEST:
+ {
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ int hit;
+ hit = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ if (wParam)
+ *(PDWORD) wParam = hitFlags;
+ if (hit == -1)
+ return (LRESULT) (HANDLE) NULL;
+ return (LRESULT) cli.pfnContactToHItem(contact);
+ }
+
+ case CLM_SELECTITEM:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group, *tgroup;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, tgroup, 1);
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*)&group->cl,contact));
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ break;
+ }
+
+ case CLM_SETBKBITMAP:
+ if (!dat->bkChanged && dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ dat->hBmpBackground = (HBITMAP) lParam;
+ dat->backgroundBmpUse = wParam;
+ dat->bkChanged = 1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETBKCOLOR:
+ if (!dat->bkChanged && dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ dat->bkColour = wParam;
+ dat->bkChanged = 1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETCHECKMARK:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ if (lParam)
+ contact->flags |= CONTACTF_CHECKED;
+ else
+ contact->flags &= ~CONTACTF_CHECKED;
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETEXTRACOLUMNS:
+ if (wParam > MAXEXTRACOLUMNS)
+ return 0;
+ dat->extraColumnsCount = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETEXTRAIMAGE:
+ {
+ struct ClcContact *contact;
+ if (LOWORD(lParam) >= dat->extraColumnsCount)
+ return 0;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ contact->iExtraImage[LOWORD(lParam)] = (BYTE) HIWORD(lParam);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETEXTRAIMAGELIST:
+ dat->himlExtraColumns = (HIMAGELIST) lParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETFONT:
+ if (HIWORD(lParam) < 0 || HIWORD(lParam) > FONTID_MAX)
+ return 0;
+ dat->fontInfo[HIWORD(lParam)].hFont = (HFONT) wParam;
+ dat->fontInfo[HIWORD(lParam)].changed = 1;
+ {
+ SIZE fontSize;
+ HDC hdc = GetDC(hwnd);
+ SelectObject(hdc, (HFONT) wParam);
+ GetTextExtentPoint32A(hdc, "x", 1, &fontSize);
+ dat->fontInfo[HIWORD(lParam)].fontHeight = fontSize.cy;
+ if (dat->rowHeight < fontSize.cy + 2)
+ dat->rowHeight = fontSize.cy + 2;
+ ReleaseDC(hwnd, hdc);
+ }
+ if (LOWORD(lParam))
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETGREYOUTFLAGS:
+ dat->greyoutFlags = wParam;
+ break;
+
+ case CLM_SETHIDEEMPTYGROUPS:
+ if (wParam)
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | CLS_HIDEEMPTYGROUPS);
+ else
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETHIDEOFFLINEROOT:
+ DBWriteContactSettingByte(NULL, "CLC", "HideOfflineRoot", (BYTE) wParam);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETINDENT:
+ dat->groupIndent = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETITEMTEXT:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ lstrcpyn(contact->szText, ( TCHAR* )lParam, SIZEOF( contact->szText ));
+ cli.pfnSortCLC(hwnd, dat, 1);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETLEFTMARGIN:
+ dat->leftMargin = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETOFFLINEMODES:
+ dat->offlineModes = wParam;
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETSCROLLTIME:
+ dat->scrollTime = wParam;
+ break;
+
+ case CLM_SETTEXTCOLOR:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ break;
+ dat->fontInfo[wParam].colour = lParam;
+ break;
+
+ case CLM_SETUSEGROUPS:
+ if (wParam)
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | CLS_USEGROUPS);
+ else
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~CLS_USEGROUPS);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/clcutils.c b/miranda-wine/src/modules/clist/clcutils.c new file mode 100644 index 0000000..b296e8b --- /dev/null +++ b/miranda-wine/src/modules/clist/clcutils.c @@ -0,0 +1,865 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+//loads of stuff that didn't really fit anywhere else
+
+extern HANDLE hHideInfoTipEvent;
+
+char* fnGetGroupCountsText(struct ClcData *dat, struct ClcContact *contact)
+{
+ static char szName[32];
+ int onlineCount, totalCount;
+ struct ClcGroup *group, *topgroup;
+
+ if (contact->type != CLCIT_GROUP || !(dat->exStyle & CLS_EX_SHOWGROUPCOUNTS))
+ return "";
+
+ group = topgroup = contact->group;
+ onlineCount = 0;
+ totalCount = group->totalMembers;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ totalCount += group->totalMembers;
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT)
+ if (group->cl.items[group->scanIndex]->flags & CONTACTF_ONLINE)
+ onlineCount++;
+ group->scanIndex++;
+ }
+ if (onlineCount == 0 && dat->exStyle & CLS_EX_HIDECOUNTSWHENEMPTY)
+ return "";
+ mir_snprintf(szName, SIZEOF(szName), "(%u/%u)", onlineCount, totalCount);
+ return szName;
+}
+
+int fnHitTest(HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags)
+{
+ struct ClcContact *hitcontact;
+ struct ClcGroup *hitgroup;
+ int hit, indent, width, i;
+ int checkboxWidth;
+ SIZE textSize;
+ HDC hdc;
+ RECT clRect;
+ HFONT hFont;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+
+ if (flags)
+ *flags = 0;
+ GetClientRect(hwnd, &clRect);
+ if (testx < 0 || testy < 0 || testy >= clRect.bottom || testx >= clRect.right) {
+ if (flags) {
+ if (testx < 0)
+ *flags |= CLCHT_TOLEFT;
+ else if (testx >= clRect.right)
+ *flags |= CLCHT_TORIGHT;
+ if (testy < 0)
+ *flags |= CLCHT_ABOVE;
+ else if (testy >= clRect.bottom)
+ *flags |= CLCHT_BELOW;
+ }
+ return -1;
+ }
+ if (testx < dat->leftMargin) {
+ if (flags)
+ *flags |= CLCHT_INLEFTMARGIN | CLCHT_NOWHERE;
+ return -1;
+ }
+ hit = cli.pfnRowHitTest(dat, dat->yScroll + testy);
+ if ( hit != -1 )
+ hit = cli.pfnGetRowByIndex(dat, hit, &hitcontact, &hitgroup);
+ if (hit == -1) {
+ if (flags)
+ *flags |= CLCHT_NOWHERE | CLCHT_BELOWITEMS;
+ return -1;
+ }
+ if (contact)
+ *contact = hitcontact;
+ if (group)
+ *group = hitgroup;
+ for (indent = 0; hitgroup->parent; indent++, hitgroup = hitgroup->parent);
+ if (testx < dat->leftMargin + indent * dat->groupIndent) {
+ if (flags)
+ *flags |= CLCHT_ONITEMINDENT;
+ return hit;
+ }
+ checkboxWidth = 0;
+ if (style & CLS_CHECKBOXES && hitcontact->type == CLCIT_CONTACT)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (style & CLS_GROUPCHECKBOXES && hitcontact->type == CLCIT_GROUP)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (hitcontact->type == CLCIT_INFO && hitcontact->flags & CLCIIF_CHECKBOX)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth) {
+ if (flags)
+ *flags |= CLCHT_ONITEMCHECK;
+ return hit;
+ }
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace) {
+ if (flags)
+ *flags |= CLCHT_ONITEMICON;
+ return hit;
+ }
+
+ for (i = 0; i < dat->extraColumnsCount; i++) {
+ if (hitcontact->iExtraImage[i] == 0xFF)
+ continue;
+ if (testx >= clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - i) &&
+ testx < clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - i) + g_IconWidth ) {
+ if (flags)
+ *flags |= CLCHT_ONITEMEXTRA | (i << 24);
+ return hit;
+ }
+ }
+ hdc = GetDC(hwnd);
+ if (hitcontact->type == CLCIT_GROUP)
+ hFont = SelectObject(hdc, dat->fontInfo[FONTID_GROUPS].hFont);
+ else
+ hFont = SelectObject(hdc, dat->fontInfo[FONTID_CONTACTS].hFont);
+ GetTextExtentPoint32(hdc, hitcontact->szText, lstrlen(hitcontact->szText), &textSize);
+ width = textSize.cx;
+ if (hitcontact->type == CLCIT_GROUP) {
+ char *szCounts;
+ szCounts = cli.pfnGetGroupCountsText(dat, hitcontact);
+ if (szCounts[0]) {
+ GetTextExtentPoint32A(hdc, " ", 1, &textSize);
+ width += textSize.cx;
+ SelectObject(hdc, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
+ GetTextExtentPoint32A(hdc, szCounts, lstrlenA(szCounts), &textSize);
+ width += textSize.cx;
+ }
+ }
+ SelectObject(hdc, hFont);
+ ReleaseDC(hwnd, hdc);
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4) {
+ if (flags)
+ *flags |= CLCHT_ONITEMLABEL;
+ return hit;
+ }
+ if (flags)
+ *flags |= CLCHT_NOWHERE;
+ return -1;
+}
+
+void fnScrollTo(HWND hwnd, struct ClcData *dat, int desty, int noSmooth)
+{
+ DWORD startTick, nowTick;
+ int oldy = dat->yScroll;
+ RECT clRect, rcInvalidate;
+ int maxy, previousy;
+
+ if (dat->iHotTrack != -1 && dat->yScroll != desty) {
+ cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ dat->iHotTrack = -1;
+ ReleaseCapture();
+ }
+ GetClientRect(hwnd, &clRect);
+ rcInvalidate = clRect;
+ maxy = cli.pfnGetRowTotalHeight(dat) - clRect.bottom;
+ if (desty > maxy)
+ desty = maxy;
+ if (desty < 0)
+ desty = 0;
+ if (abs(desty - dat->yScroll) < 4)
+ noSmooth = 1;
+ if (!noSmooth && dat->exStyle & CLS_EX_NOSMOOTHSCROLLING)
+ noSmooth = 1;
+ previousy = dat->yScroll;
+ if (!noSmooth) {
+ startTick = GetTickCount();
+ for (;;) {
+ nowTick = GetTickCount();
+ if (nowTick >= startTick + dat->scrollTime)
+ break;
+ dat->yScroll = oldy + (desty - oldy) * (int) (nowTick - startTick) / dat->scrollTime;
+ if (dat->backgroundBmpUse & CLBF_SCROLL || dat->hBmpBackground == NULL)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ previousy = dat->yScroll;
+ SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+ UpdateWindow(hwnd);
+ }
+ }
+ dat->yScroll = desty;
+ if (dat->backgroundBmpUse & CLBF_SCROLL || dat->hBmpBackground == NULL)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+}
+
+void fnEnsureVisible(HWND hwnd, struct ClcData *dat, int iItem, int partialOk)
+{
+ int itemy, itemh = cli.pfnGetRowHeight(dat, iItem), newY;
+ int moved = 0;
+ RECT clRect;
+
+ GetClientRect(hwnd, &clRect);
+ itemy = cli.pfnGetRowTopY(dat, iItem);
+ if (partialOk) {
+ if (itemy + itemh - 1 < dat->yScroll) {
+ newY = itemy;
+ moved = 1;
+ }
+ else if (itemy >= dat->yScroll + clRect.bottom) {
+ newY = itemy - clRect.bottom + itemh;
+ moved = 1;
+ }
+ }
+ else {
+ if (itemy < dat->yScroll) {
+ newY = itemy;
+ moved = 1;
+ }
+ else if (itemy >= dat->yScroll + clRect.bottom - itemh) {
+ newY = itemy - clRect.bottom + itemh;
+ moved = 1;
+ }
+ }
+ if (moved)
+ cli.pfnScrollTo(hwnd, dat, newY, 0);
+}
+
+void fnRecalcScrollBar(HWND hwnd, struct ClcData *dat)
+{
+ SCROLLINFO si = { 0 };
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ GetClientRect(hwnd, &clRect);
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = cli.pfnGetRowTotalHeight(dat)-1;
+ si.nPage = clRect.bottom;
+ si.nPos = dat->yScroll;
+
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar == 0)
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+ else SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll, 1);
+ nm.hdr.code = CLN_LISTSIZECHANGE;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.pt.y = si.nMax;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+void fnSetGroupExpand(HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState)
+{
+ int contentCount;
+ int groupy;
+ int newY, posY;
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ if (newState == -1)
+ group->expanded ^= 1;
+ else {
+ if (group->expanded == (newState != 0))
+ return;
+ group->expanded = newState != 0;
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ contentCount = cli.pfnGetGroupContentsCount(group, 1);
+ groupy = cli.pfnGetRowsPriorTo(&dat->list, group, -1);
+ if (dat->selection > groupy && dat->selection < groupy + contentCount)
+ dat->selection = groupy;
+ GetClientRect(hwnd, &clRect);
+ newY = dat->yScroll;
+ posY = cli.pfnGetRowBottomY(dat, groupy + contentCount);
+ if (posY >= newY + clRect.bottom)
+ newY = posY - clRect.bottom;
+ posY = cli.pfnGetRowTopY(dat, groupy);
+ if (newY > posY)
+ newY = posY;
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ cli.pfnScrollTo(hwnd, dat, newY, 0);
+ nm.hdr.code = CLN_EXPANDED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.hItem = (HANDLE) group->groupId;
+ nm.action = group->expanded;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+void fnDoSelectionDefaultAction(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+
+ if (dat->selection == -1)
+ return;
+ dat->szQuickSearch[0] = 0;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (contact->type == CLCIT_CONTACT)
+ CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM) contact->hContact, 0);
+}
+
+int fnFindRowByText(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk)
+{
+ struct ClcGroup *group = &dat->list;
+ int testlen = lstrlen(text);
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
+ if ((prefixOk && !_tcsnicmp(text, group->cl.items[group->scanIndex]->szText, testlen)) ||
+ (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText))) {
+ struct ClcGroup *contactGroup = group;
+ int contactScanIndex = group->scanIndex;
+ for (; group; group = group->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, group, 1);
+ return cli.pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex);
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+void fnEndRename(HWND hwnd, struct ClcData *dat, int save)
+{
+ HWND hwndEdit = dat->hwndRenameEdit;
+
+ if (dat->hwndRenameEdit == NULL)
+ return;
+ dat->hwndRenameEdit = NULL;
+ if (save) {
+ TCHAR text[120];
+ struct ClcContact *contact;
+ GetWindowText(hwndEdit, text, SIZEOF(text));
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) != -1) {
+ if (lstrcmp(contact->szText, text)) {
+ if (contact->type == CLCIT_GROUP && !_tcsstr(text, _T("\\"))) {
+ TCHAR szFullName[256];
+ if (contact->group->parent && contact->group->parent->parent)
+ mir_sntprintf( szFullName, SIZEOF(szFullName), _T("%s\\%s"),
+ cli.pfnGetGroupName(contact->group->parent->groupId, NULL), text);
+ else
+ lstrcpyn( szFullName, text, SIZEOF( szFullName ));
+ cli.pfnRenameGroup( contact->groupId, szFullName );
+ }
+ else if (contact->type == CLCIT_CONTACT) {
+ TCHAR* otherName = cli.pfnGetContactDisplayName(contact->hContact, GCDNF_NOMYHANDLE);
+ cli.pfnInvalidateDisplayNameCacheEntry(contact->hContact);
+ if (text[0] == '\0') {
+ DBDeleteContactSetting(contact->hContact, "CList", "MyHandle");
+ }
+ else {
+ if (!lstrcmp(otherName, text))
+ DBDeleteContactSetting(contact->hContact, "CList", "MyHandle");
+ else
+ DBWriteContactSettingTString(contact->hContact, "CList", "MyHandle", text);
+ }
+ if (otherName)
+ mir_free(otherName);
+ }
+ }
+ }
+ }
+ DestroyWindow(hwndEdit);
+}
+
+void fnDeleteFromContactList(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+ if (dat->selection == -1)
+ return;
+ dat->szQuickSearch[0] = 0;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return;
+ switch (contact->type) {
+ case CLCIT_GROUP:
+ CallService(MS_CLIST_GROUPDELETE, (WPARAM) (HANDLE) contact->groupId, 0);
+ break;
+ case CLCIT_CONTACT:
+ CallService("CList/DeleteContactCommand", (WPARAM) (HANDLE)
+ contact->hContact, (LPARAM) hwnd);
+ break;
+ }
+}
+
+static WNDPROC OldRenameEditWndProc;
+static LRESULT CALLBACK RenameEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_RETURN:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLong(GetParent(hwnd), 0), 1);
+ return 0;
+ case VK_ESCAPE:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLong(GetParent(hwnd), 0), 0);
+ return 0;
+ }
+ break;
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN && msg->wParam == VK_TAB)
+ return 0;
+ if (msg->message == WM_CHAR && msg->wParam == '\t')
+ return 0;
+ }
+ return DLGC_WANTMESSAGE;
+ case WM_KILLFOCUS:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLong(GetParent(hwnd), 0), 1);
+ return 0;
+ }
+ return CallWindowProc(OldRenameEditWndProc, hwnd, msg, wParam, lParam);
+}
+
+void fnBeginRenameSelection(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ RECT clRect;
+ POINT pt;
+ int h;
+
+ KillTimer(hwnd, TIMERID_RENAME);
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (dat->selection == -1)
+ return;
+ if (contact->type != CLCIT_CONTACT && contact->type != CLCIT_GROUP)
+ return;
+ GetClientRect(hwnd, &clRect);
+ cli.pfnCalcEipPosition( dat, contact, group, &pt );
+ h = cli.pfnGetRowHeight(dat, dat->selection);
+ dat->hwndRenameEdit = CreateWindow( _T("EDIT"), contact->szText, WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, pt.x, pt.y, clRect.right - pt.x, h, hwnd, NULL, cli.hInst, NULL);
+ OldRenameEditWndProc = (WNDPROC) SetWindowLong(dat->hwndRenameEdit, GWL_WNDPROC, (LONG) RenameEditSubclassProc);
+ SendMessage(dat->hwndRenameEdit, WM_SETFONT, (WPARAM) (contact->type == CLCIT_GROUP ? dat->fontInfo[FONTID_GROUPS].hFont : dat->fontInfo[FONTID_CONTACTS].hFont), 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN | EC_USEFONTINFO, 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETSEL, 0, (LPARAM) (-1));
+ ShowWindow(dat->hwndRenameEdit, SW_SHOW);
+ SetFocus(dat->hwndRenameEdit);
+}
+
+void fnCalcEipPosition( struct ClcData *dat, struct ClcContact *contact, struct ClcGroup *group, POINT *result)
+{
+ int indent;
+ for (indent = 0; group->parent; indent++, group = group->parent);
+ result->x = indent * dat->groupIndent + dat->iconXSpace - 2;
+ result->y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll;
+}
+
+int fnGetDropTargetInformation(HWND hwnd, struct ClcData *dat, POINT pt)
+{
+ RECT clRect;
+ int hit;
+ struct ClcContact *contact, *movecontact;
+ struct ClcGroup *group, *movegroup;
+ DWORD hitFlags;
+
+ GetClientRect(hwnd, &clRect);
+ dat->selection = dat->iDragItem;
+ dat->iInsertionMark = -1;
+ if (!PtInRect(&clRect, pt))
+ return DROPTARGET_OUTSIDE;
+
+ hit = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, &group, &hitFlags);
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &movecontact, &movegroup);
+ if (hit == dat->iDragItem)
+ return DROPTARGET_ONSELF;
+ if (hit == -1 || hitFlags & CLCHT_ONITEMEXTRA)
+ return DROPTARGET_ONNOTHING;
+
+ if (movecontact->type == CLCIT_GROUP) {
+ struct ClcContact *bottomcontact = NULL, *topcontact = NULL;
+ struct ClcGroup *topgroup = NULL;
+ int topItem = -1, bottomItem;
+ int ok = 0;
+ if (pt.y + dat->yScroll < cli.pfnGetRowTopY(dat, hit) + dat->insertionMarkHitHeight) {
+ //could be insertion mark (above)
+ topItem = hit - 1;
+ bottomItem = hit;
+ bottomcontact = contact;
+ topItem = cli.pfnGetRowByIndex(dat, topItem, &topcontact, &topgroup);
+ ok = 1;
+ }
+ if (pt.y + dat->yScroll >= cli.pfnGetRowBottomY(dat, hit+1) - dat->insertionMarkHitHeight) {
+ //could be insertion mark (below)
+ topItem = hit;
+ bottomItem = hit + 1;
+ topcontact = contact;
+ topgroup = group;
+ bottomItem = cli.pfnGetRowByIndex(dat, bottomItem, &bottomcontact, NULL);
+ ok = 1;
+ }
+ if (ok) {
+ ok = 0;
+ if (bottomItem == -1 || bottomcontact->type != CLCIT_GROUP) { //need to special-case moving to end
+ if (topItem != dat->iDragItem) {
+ for (; topgroup; topgroup = topgroup->parent) {
+ if (topgroup == movecontact->group)
+ break;
+ if (topgroup == movecontact->group->parent) {
+ ok = 1;
+ break;
+ }
+ }
+ if (ok)
+ bottomItem = topItem + 1;
+ }
+ }
+ else if (bottomItem != dat->iDragItem && bottomcontact->type == CLCIT_GROUP && bottomcontact->group->parent == movecontact->group->parent) {
+ if (bottomcontact != movecontact + 1)
+ ok = 1;
+ }
+ if (ok) {
+ dat->iInsertionMark = bottomItem;
+ dat->selection = -1;
+ return DROPTARGET_INSERTION;
+ }
+ }
+ }
+ if (contact->type == CLCIT_GROUP) {
+ if (dat->iInsertionMark == -1) {
+ if (movecontact->type == CLCIT_GROUP) { //check not moving onto its own subgroup
+ for (; group; group = group->parent)
+ if (group == movecontact->group)
+ return DROPTARGET_ONSELF;
+ }
+ dat->selection = hit;
+ return DROPTARGET_ONGROUP;
+ }
+ }
+ return DROPTARGET_ONCONTACT;
+}
+
+int fnClcStatusToPf2(int status)
+{
+ switch(status) {
+ case ID_STATUS_ONLINE: return PF2_ONLINE;
+ case ID_STATUS_AWAY: return PF2_SHORTAWAY;
+ case ID_STATUS_DND: return PF2_HEAVYDND;
+ case ID_STATUS_NA: return PF2_LONGAWAY;
+ case ID_STATUS_OCCUPIED: return PF2_LIGHTDND;
+ case ID_STATUS_FREECHAT: return PF2_FREECHAT;
+ case ID_STATUS_INVISIBLE: return PF2_INVISIBLE;
+ case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE;
+ case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH;
+ case ID_STATUS_OFFLINE: return MODEF_OFFLINE;
+ }
+ return 0;
+}
+
+int fnIsHiddenMode(struct ClcData *dat, int status)
+{
+ return dat->offlineModes & cli.pfnClcStatusToPf2(status);
+}
+
+void fnHideInfoTip(HWND hwnd, struct ClcData *dat)
+{
+ CLCINFOTIP it = { 0 };
+
+ if (dat->hInfoTipItem == NULL)
+ return;
+ it.isGroup = IsHContactGroup(dat->hInfoTipItem);
+ it.hItem = (HANDLE) ((unsigned) dat->hInfoTipItem & ~HCONTACT_ISGROUP);
+ it.cbSize = sizeof(it);
+ dat->hInfoTipItem = NULL;
+ NotifyEventHooks(hHideInfoTipEvent, 0, (LPARAM) & it);
+}
+
+void fnNotifyNewContact(HWND hwnd, HANDLE hContact)
+{
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_NEWCONTACT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = hContact;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+DWORD fnGetDefaultExStyle(void)
+{
+ BOOL param;
+ DWORD ret = CLCDEFAULT_EXSTYLE;
+ if (SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, ¶m, FALSE) && !param)
+ ret |= CLS_EX_NOSMOOTHSCROLLING;
+ if (SystemParametersInfo(SPI_GETHOTTRACKING, 0, ¶m, FALSE) && !param)
+ ret &= ~CLS_EX_TRACKSELECT;
+ return ret;
+}
+
+#define DBFONTF_BOLD 1
+#define DBFONTF_ITALIC 2
+#define DBFONTF_UNDERLINE 4
+
+void fnGetDefaultFontSetting(int i, LOGFONT* lf, COLORREF* colour)
+{
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), lf, FALSE);
+ *colour = GetSysColor(COLOR_WINDOWTEXT);
+ lf->lfHeight = 8;
+ switch (i) {
+ case FONTID_GROUPS:
+ lf->lfWeight = FW_BOLD;
+ break;
+ case FONTID_GROUPCOUNTS:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+ case FONTID_OFFINVIS:
+ case FONTID_INVIS:
+ lf->lfItalic = !lf->lfItalic;
+ break;
+ case FONTID_DIVIDERS:
+ break;
+ case FONTID_NOTONLIST:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+} }
+
+void fnGetFontSetting(int i, LOGFONT* lf, COLORREF* colour)
+{
+ DBVARIANT dbv;
+ char idstr[10];
+ BYTE style;
+
+ cli.pfnGetDefaultFontSetting(i, lf, colour);
+ wsprintfA(idstr, "Font%dName", i);
+ if ( !DBGetContactSettingTString(NULL, "CLC", idstr, &dbv )) {
+ lstrcpy(lf->lfFaceName, dbv.ptszVal);
+ mir_free(dbv.pszVal);
+ }
+ wsprintfA(idstr, "Font%dCol", i);
+ *colour = DBGetContactSettingDword(NULL, "CLC", idstr, *colour);
+ wsprintfA(idstr, "Font%dSize", i);
+ lf->lfHeight = (char) DBGetContactSettingByte(NULL, "CLC", idstr, lf->lfHeight);
+ wsprintfA(idstr, "Font%dSty", i);
+ style = (BYTE) DBGetContactSettingByte(NULL, "CLC", idstr, (lf->lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) | (lf->lfItalic ? DBFONTF_ITALIC : 0) | (lf->lfUnderline ? DBFONTF_UNDERLINE : 0));
+ lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
+ lf->lfWeight = style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = (style & DBFONTF_ITALIC) != 0;
+ lf->lfUnderline = (style & DBFONTF_UNDERLINE) != 0;
+ lf->lfStrikeOut = 0;
+ wsprintfA(idstr, "Font%dSet", i);
+ lf->lfCharSet = DBGetContactSettingByte(NULL, "CLC", idstr, lf->lfCharSet);
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+}
+
+void fnLoadClcOptions(HWND hwnd, struct ClcData *dat)
+{
+ dat->rowHeight = DBGetContactSettingByte(NULL, "CLC", "RowHeight", CLCDEFAULT_ROWHEIGHT);
+ {
+ int i;
+ LOGFONT lf;
+ SIZE fontSize;
+ HDC hdc = GetDC(hwnd);
+ HFONT hFont = GetCurrentObject(hdc, OBJ_FONT);
+ HFONT holdfont;
+
+ for (i = 0; i <= FONTID_MAX; i++) {
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+ cli.pfnGetFontSetting(i, &lf, &dat->fontInfo[i].colour);
+ {
+ LONG height;
+ HDC hdc = GetDC(NULL);
+ height = lf.lfHeight;
+ lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(NULL, hdc);
+ dat->fontInfo[i].hFont = CreateFontIndirect(&lf);
+ lf.lfHeight = height;
+ }
+ dat->fontInfo[i].changed = 0;
+ holdfont = SelectObject(hdc,dat->fontInfo[i].hFont);
+ GetTextExtentPoint32(hdc, _T("x"), 1, &fontSize);
+ dat->fontInfo[i].fontHeight = fontSize.cy;
+ if (holdfont) SelectObject(hdc, holdfont);
+ }
+ SelectObject(hdc,hFont);
+ ReleaseDC(hwnd, hdc);
+ }
+ dat->leftMargin = DBGetContactSettingByte(NULL, "CLC", "LeftMargin", CLCDEFAULT_LEFTMARGIN);
+ dat->exStyle = DBGetContactSettingDword(NULL, "CLC", "ExStyle", cli.pfnGetDefaultExStyle());
+ dat->scrollTime = DBGetContactSettingWord(NULL, "CLC", "ScrollTime", CLCDEFAULT_SCROLLTIME);
+ dat->groupIndent = DBGetContactSettingByte(NULL, "CLC", "GroupIndent", CLCDEFAULT_GROUPINDENT);
+ dat->gammaCorrection = DBGetContactSettingByte(NULL, "CLC", "GammaCorrect", CLCDEFAULT_GAMMACORRECT);
+ dat->showIdle = DBGetContactSettingByte(NULL, "CLC", "ShowIdle", CLCDEFAULT_SHOWIDLE);
+ dat->noVScrollbar = DBGetContactSettingByte(NULL, "CLC", "NoVScrollBar", 0);
+ SendMessage(hwnd, INTM_SCROLLBARCHANGED, 0, 0);
+ if (!dat->bkChanged) {
+ DBVARIANT dbv;
+ dat->bkColour = DBGetContactSettingDword(NULL, "CLC", "BkColour", CLCDEFAULT_BKCOLOUR);
+ if (dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ if (DBGetContactSettingByte(NULL, "CLC", "UseBitmap", CLCDEFAULT_USEBITMAP)) {
+ if (!DBGetContactSetting(NULL, "CLC", "BkBitmap", &dbv)) {
+ dat->hBmpBackground = (HBITMAP) CallService(MS_UTILS_LOADBITMAP, 0, (LPARAM) dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ }
+ dat->backgroundBmpUse = DBGetContactSettingWord(NULL, "CLC", "BkBmpUse", CLCDEFAULT_BKBMPUSE);
+ }
+ dat->greyoutFlags = DBGetContactSettingDword(NULL, "CLC", "GreyoutFlags", CLCDEFAULT_GREYOUTFLAGS);
+ dat->offlineModes = DBGetContactSettingDword(NULL, "CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES);
+ dat->selBkColour = DBGetContactSettingDword(NULL, "CLC", "SelBkColour", CLCDEFAULT_SELBKCOLOUR);
+ dat->selTextColour = DBGetContactSettingDword(NULL, "CLC", "SelTextColour", CLCDEFAULT_SELTEXTCOLOUR);
+ dat->hotTextColour = DBGetContactSettingDword(NULL, "CLC", "HotTextColour", CLCDEFAULT_HOTTEXTCOLOUR);
+ dat->quickSearchColour = DBGetContactSettingDword(NULL, "CLC", "QuickSearchColour", CLCDEFAULT_QUICKSEARCHCOLOUR);
+ dat->useWindowsColours = DBGetContactSettingByte(NULL, "CLC", "UseWinColours", CLCDEFAULT_USEWINDOWSCOLOURS);
+ {
+ NMHDR hdr;
+ hdr.code = CLN_OPTIONSCHANGED;
+ hdr.hwndFrom = hwnd;
+ hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & hdr);
+ }
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+}
+
+#define GSIF_HASMEMBERS 0x80000000
+#define GSIF_ALLCHECKED 0x40000000
+#define GSIF_INDEXMASK 0x3FFFFFFF
+void fnRecalculateGroupCheckboxes(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcGroup *group;
+ int check;
+
+ group = &dat->list;
+ group->scanIndex = GSIF_ALLCHECKED;
+ for (;;) {
+ if ((group->scanIndex & GSIF_INDEXMASK) == group->cl.count) {
+ check = (group->scanIndex & (GSIF_HASMEMBERS | GSIF_ALLCHECKED)) == (GSIF_HASMEMBERS | GSIF_ALLCHECKED);
+ group = group->parent;
+ if (group == NULL)
+ break;
+ if (check)
+ group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags |= CONTACTF_CHECKED;
+ else {
+ group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags &= ~CONTACTF_CHECKED;
+ group->scanIndex &= ~GSIF_ALLCHECKED;
+ }
+ }
+ else if (group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->type == CLCIT_GROUP) {
+ group = group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->group;
+ group->scanIndex = GSIF_ALLCHECKED;
+ continue;
+ }
+ else if (group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->type == CLCIT_CONTACT) {
+ group->scanIndex |= GSIF_HASMEMBERS;
+ if (!(group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags & CONTACTF_CHECKED))
+ group->scanIndex &= ~GSIF_ALLCHECKED;
+ }
+ group->scanIndex++;
+ }
+}
+
+void fnSetGroupChildCheckboxes(struct ClcGroup *group, int checked)
+{
+ int i;
+
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ cli.pfnSetGroupChildCheckboxes(group->cl.items[i]->group, checked);
+ if (checked)
+ group->cl.items[i]->flags |= CONTACTF_CHECKED;
+ else
+ group->cl.items[i]->flags &= ~CONTACTF_CHECKED;
+ }
+ else if (group->cl.items[i]->type == CLCIT_CONTACT) {
+ if (checked)
+ group->cl.items[i]->flags |= CONTACTF_CHECKED;
+ else
+ group->cl.items[i]->flags &= ~CONTACTF_CHECKED;
+ }
+ }
+}
+
+void fnInvalidateItem(HWND hwnd, struct ClcData *dat, int iItem)
+{
+ RECT rc;
+ if ( iItem == -1 )
+ return;
+
+ GetClientRect(hwnd, &rc);
+ rc.top = cli.pfnGetRowTopY(dat, iItem) - dat->yScroll;
+ rc.bottom = rc.top + cli.pfnGetRowHeight(dat, iItem);
+ cli.pfnInvalidateRect(hwnd, &rc, FALSE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// row coord functions
+
+int fnGetRowTopY(struct ClcData *dat, int item)
+{ return item * dat->rowHeight;
+}
+
+int fnGetRowBottomY(struct ClcData *dat, int item)
+{ return (item+1) * dat->rowHeight;
+}
+
+int fnGetRowTotalHeight(struct ClcData *dat)
+{ return dat->rowHeight * cli.pfnGetGroupContentsCount(&dat->list, 1);
+}
+
+int fnGetRowHeight(struct ClcData *dat, int item)
+{ return dat->rowHeight;
+}
+
+int fnRowHitTest(struct ClcData *dat, int y)
+{ if (!dat->rowHeight)
+ return y;
+ return y / dat->rowHeight;
+}
\ No newline at end of file diff --git a/miranda-wine/src/modules/clist/clistcore.c b/miranda-wine/src/modules/clist/clistcore.c new file mode 100644 index 0000000..13bce39 --- /dev/null +++ b/miranda-wine/src/modules/clist/clistcore.c @@ -0,0 +1,315 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+CLIST_INTERFACE cli = { 0 };
+
+int LoadContactListModule2( void );
+int LoadCLCModule( void );
+
+/* clc.c */
+void fnClcOptionsChanged( void );
+void fnClcBroadcast( int msg, WPARAM wParam, LPARAM lParam );
+HMENU fnBuildGroupPopupMenu( struct ClcGroup* group );
+
+LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/* clcfiledrop.c */
+void fnRegisterFileDropping ( HWND hwnd );
+void fnUnregisterFileDropping ( HWND hwnd );
+
+/* clcidents.c */
+int fnGetRowsPriorTo( struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex );
+int fnFindItem( HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible );
+int fnGetRowByIndex( struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup );
+HANDLE fnContactToHItem( struct ClcContact* contact );
+HANDLE fnContactToItemHandle( struct ClcContact * contact, DWORD * nmFlags );
+
+/* clcitems.c */
+struct ClcGroup* fnAddGroup( HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers );
+struct ClcGroup* fnRemoveItemFromGroup(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount);
+
+void fnFreeContact( struct ClcContact *p );
+void fnFreeGroup( struct ClcGroup *group );
+int fnAddInfoItemToGroup(struct ClcGroup *group, int flags, const TCHAR *pszText);
+int fnAddItemToGroup( struct ClcGroup *group,int iAboveItem );
+void fnAddContactToTree( HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline);
+int fnAddContactToGroup( struct ClcData *dat, struct ClcGroup *group, HANDLE hContact);
+void fnDeleteItemFromTree( HWND hwnd, HANDLE hItem );
+void fnRebuildEntireList( HWND hwnd, struct ClcData *dat );
+int fnGetGroupContentsCount( struct ClcGroup *group, int visibleOnly );
+void fnSortCLC( HWND hwnd, struct ClcData *dat, int useInsertionSort );
+void fnSaveStateAndRebuildList(HWND hwnd, struct ClcData *dat);
+
+/* clcmsgs.c */
+LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam );
+
+/* clcpaint.c */
+void fnPaintClc( HWND hwnd, struct ClcData *dat, HDC hdc, RECT * rcPaint ) {}
+
+/* clcutils.c */
+char* fnGetGroupCountsText(struct ClcData *dat, struct ClcContact *contact );
+int fnHitTest( HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags );
+void fnScrollTo( HWND hwnd, struct ClcData *dat, int desty, int noSmooth );
+void fnEnsureVisible(HWND hwnd, struct ClcData *dat, int iItem, int partialOk );
+void fnRecalcScrollBar( HWND hwnd, struct ClcData *dat );
+void fnSetGroupExpand( HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState );
+void fnDoSelectionDefaultAction( HWND hwnd, struct ClcData *dat );
+int fnFindRowByText(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk );
+void fnEndRename(HWND hwnd, struct ClcData *dat, int save );
+void fnDeleteFromContactList( HWND hwnd, struct ClcData *dat );
+void fnBeginRenameSelection( HWND hwnd, struct ClcData *dat );
+void fnCalcEipPosition( struct ClcData *dat, struct ClcContact *contact, struct ClcGroup *group, POINT *result);
+int fnGetDropTargetInformation( HWND hwnd, struct ClcData *dat, POINT pt );
+int fnClcStatusToPf2( int status );
+int fnIsHiddenMode( struct ClcData *dat, int status );
+void fnHideInfoTip( HWND hwnd, struct ClcData *dat );
+void fnNotifyNewContact( HWND hwnd, HANDLE hContact );
+DWORD fnGetDefaultExStyle( void );
+void fnGetSetting( int i, LOGFONT* lf, COLORREF* colour );
+void fnGetDefaultFontSetting(int i, LOGFONT* lf, COLORREF* colour);
+void fnGetFontSetting( int i, LOGFONT* lf, COLORREF* colour );
+void fnLoadClcOptions( HWND hwnd, struct ClcData *dat );
+void fnRecalculateGroupCheckboxes( HWND hwnd, struct ClcData *dat );
+void fnSetGroupChildCheckboxes( struct ClcGroup *group, int checked );
+void fnInvalidateItem( HWND hwnd, struct ClcData *dat, int iItem );
+
+/* clistevents.c */
+struct CListEvent* fnAddEvent( CLISTEVENT *cle );
+CLISTEVENT* fnGetEvent( HANDLE hContact, int idx );
+
+struct CListEvent* fnCreateEvent( void );
+void fnFreeEvent( struct CListEvent* p );
+
+int fnEventsProcessContactDoubleClick( HANDLE hContact );
+int fnEventsProcessTrayDoubleClick( void );
+int fnGetImlIconIndex(HICON hIcon);
+int fnRemoveEvent( HANDLE hContact, HANDLE dbEvent );
+
+/* clistmod.c */
+int fnIconFromStatusMode(const char *szProto, int status, HANDLE hContact);
+int fnShowHide( WPARAM wParam, LPARAM lParam );
+TCHAR* fnGetStatusModeDescription( int wParam, int lParam);
+int fnGetWindowVisibleState(HWND hWnd, int iStepX, int iStepY);
+
+/* clistsettings.c */
+TCHAR* fnGetContactDisplayName( HANDLE hContact, int mode );
+void fnGetDefaultFontSetting( int i, LOGFONT* lf, COLORREF * colour);
+void fnInvalidateDisplayNameCacheEntry( HANDLE hContact );
+
+ClcCacheEntryBase* fnGetCacheEntry( HANDLE hContact );
+ClcCacheEntryBase* fnCreateCacheItem ( HANDLE hContact );
+void fnCheckCacheItem( ClcCacheEntryBase* p );
+void fnFreeCacheItem( ClcCacheEntryBase* p );
+
+/* clisttray.c */
+int fnCListTrayNotify(MIRANDASYSTRAYNOTIFY *msn);
+void fnTrayIconUpdateWithImageList ( int iImage, const TCHAR *szNewTip, char *szPreferredProto );
+void fnTrayIconUpdateBase ( const char *szChangedProto );
+void fnTrayIconSetToBase ( char *szPreferredProto );
+void fnTrayIconIconsChanged ( void );
+int fnTrayIconPauseAutoHide ( WPARAM wParam, LPARAM lParam );
+int fnTrayIconProcessMessage ( WPARAM wParam, LPARAM lParam );
+
+/* clui.c */
+LRESULT CALLBACK fnContactListWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+void fnLoadCluiGlobalOpts( void );
+int fnCluiProtocolStatusChanged(int,const char*);
+void fnDrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, HICON eventIcon);
+
+/* contact.c */
+void fnChangeContactIcon ( HANDLE hContact, int iIcon, int add );
+void fnLoadContactTree ( void );
+int fnCompareContacts ( const struct ClcContact *contact1, const struct ClcContact *contact2);
+void fnSortContacts ( void );
+int fnSetHideOffline ( WPARAM wParam, LPARAM lParam );
+
+/* docking.c */
+int fnDocking_ProcessWindowMessage ( WPARAM wParam, LPARAM lParam );
+
+/* group.c */
+TCHAR* fnGetGroupName ( int idx, DWORD* pdwFlags );
+int fnRenameGroup ( int groupID, TCHAR* newName );
+
+/* keyboard.c */
+int fnHotKeysRegister ( HWND hwnd );
+void fnHotKeysUnregister ( HWND hwnd );
+int fnHotKeysProcess ( HWND hwnd, WPARAM wParam, LPARAM lParam );
+int fnHotkeysProcessMessage ( WPARAM wParam, LPARAM lParam );
+
+static int interfaceInited = 0;
+
+static struct ClcContact* fnCreateClcContact( void )
+{
+ return ( struct ClcContact* )mir_calloc( sizeof( struct ClcContact ));
+}
+
+static BOOL fnInvalidateRect( HWND hwnd, CONST RECT* lpRect,BOOL bErase )
+{
+ return InvalidateRect( hwnd, lpRect, bErase );
+}
+
+static void fnOnCreateClc( void )
+{
+}
+
+static int srvRetrieveInterface( WPARAM wParam, LPARAM lParam )
+{
+ int rc;
+
+ if ( interfaceInited == 0 ) {
+ cli.version = 3;
+
+ cli.pfnClcOptionsChanged = fnClcOptionsChanged;
+ cli.pfnClcBroadcast = fnClcBroadcast;
+ cli.pfnContactListControlWndProc = fnContactListControlWndProc;
+ cli.pfnBuildGroupPopupMenu = fnBuildGroupPopupMenu;
+
+ cli.pfnRegisterFileDropping = fnRegisterFileDropping;
+ cli.pfnUnregisterFileDropping = fnUnregisterFileDropping;
+
+ cli.pfnGetRowsPriorTo = fnGetRowsPriorTo;
+ cli.pfnFindItem = fnFindItem;
+ cli.pfnGetRowByIndex = fnGetRowByIndex;
+ cli.pfnContactToHItem = fnContactToHItem;
+ cli.pfnContactToItemHandle = fnContactToItemHandle;
+
+ cli.pfnAddGroup = fnAddGroup;
+ cli.pfnAddItemToGroup = fnAddItemToGroup;
+ cli.pfnCreateClcContact = fnCreateClcContact;
+ cli.pfnRemoveItemFromGroup = fnRemoveItemFromGroup;
+ cli.pfnFreeContact = fnFreeContact;
+ cli.pfnFreeGroup = fnFreeGroup;
+ cli.pfnAddInfoItemToGroup = fnAddInfoItemToGroup;
+ cli.pfnAddContactToGroup = fnAddContactToGroup;
+ cli.pfnAddContactToTree = fnAddContactToTree;
+ cli.pfnDeleteItemFromTree = fnDeleteItemFromTree;
+ cli.pfnRebuildEntireList = fnRebuildEntireList;
+ cli.pfnGetGroupContentsCount = fnGetGroupContentsCount;
+ cli.pfnSortCLC = fnSortCLC;
+ cli.pfnSaveStateAndRebuildList = fnSaveStateAndRebuildList;
+
+ cli.pfnProcessExternalMessages = fnProcessExternalMessages;
+
+ cli.pfnPaintClc = fnPaintClc;
+
+ cli.pfnGetGroupCountsText = fnGetGroupCountsText;
+ cli.pfnHitTest = fnHitTest;
+ cli.pfnScrollTo = fnScrollTo;
+ cli.pfnEnsureVisible = fnEnsureVisible;
+ cli.pfnRecalcScrollBar = fnRecalcScrollBar;
+ cli.pfnSetGroupExpand = fnSetGroupExpand;
+ cli.pfnDoSelectionDefaultAction = fnDoSelectionDefaultAction;
+ cli.pfnFindRowByText = fnFindRowByText;
+ cli.pfnEndRename = fnEndRename;
+ cli.pfnDeleteFromContactList = fnDeleteFromContactList;
+ cli.pfnBeginRenameSelection = fnBeginRenameSelection;
+ cli.pfnCalcEipPosition = fnCalcEipPosition;
+ cli.pfnGetDropTargetInformation = fnGetDropTargetInformation;
+ cli.pfnClcStatusToPf2 = fnClcStatusToPf2;
+ cli.pfnIsHiddenMode = fnIsHiddenMode;
+ cli.pfnHideInfoTip = fnHideInfoTip;
+ cli.pfnNotifyNewContact = fnNotifyNewContact;
+ cli.pfnGetDefaultExStyle = fnGetDefaultExStyle;
+ cli.pfnGetDefaultFontSetting = fnGetDefaultFontSetting;
+ cli.pfnGetFontSetting = fnGetFontSetting;
+ cli.pfnLoadClcOptions = fnLoadClcOptions;
+ cli.pfnRecalculateGroupCheckboxes = fnRecalculateGroupCheckboxes;
+ cli.pfnSetGroupChildCheckboxes = fnSetGroupChildCheckboxes;
+ cli.pfnInvalidateItem = fnInvalidateItem;
+ cli.pfnGetRowBottomY = fnGetRowBottomY;
+ cli.pfnGetRowHeight = fnGetRowHeight;
+ cli.pfnGetRowTopY = fnGetRowTopY;
+ cli.pfnGetRowTotalHeight = fnGetRowTotalHeight;
+ cli.pfnRowHitTest = fnRowHitTest;
+
+ cli.pfnAddEvent = fnAddEvent;
+ cli.pfnCreateEvent = fnCreateEvent;
+ cli.pfnEventsProcessContactDoubleClick = fnEventsProcessContactDoubleClick;
+ cli.pfnEventsProcessTrayDoubleClick = fnEventsProcessTrayDoubleClick;
+ cli.pfnFreeEvent = fnFreeEvent;
+ cli.pfnGetEvent = fnGetEvent;
+ cli.pfnGetImlIconIndex = fnGetImlIconIndex;
+ cli.pfnRemoveEvent = fnRemoveEvent;
+
+ cli.pfnGetContactDisplayName = fnGetContactDisplayName;
+ cli.pfnInvalidateDisplayNameCacheEntry = fnInvalidateDisplayNameCacheEntry;
+ cli.pfnCreateCacheItem = fnCreateCacheItem;
+ cli.pfnCheckCacheItem = fnCheckCacheItem;
+ cli.pfnFreeCacheItem = fnFreeCacheItem;
+ cli.pfnGetCacheEntry = fnGetCacheEntry;
+
+ cli.pfnTrayIconUpdateWithImageList = fnTrayIconUpdateWithImageList;
+ cli.pfnTrayIconUpdateBase = fnTrayIconUpdateBase;
+ cli.pfnTrayIconSetToBase = fnTrayIconSetToBase;
+ cli.pfnTrayIconIconsChanged = fnTrayIconIconsChanged;
+ cli.pfnTrayIconPauseAutoHide = fnTrayIconPauseAutoHide;
+ cli.pfnTrayIconProcessMessage = fnTrayIconProcessMessage;
+ cli.pfnCListTrayNotify = fnCListTrayNotify;
+
+ cli.pfnContactListWndProc = fnContactListWndProc;
+ cli.pfnLoadCluiGlobalOpts = fnLoadCluiGlobalOpts;
+ cli.pfnCluiProtocolStatusChanged = fnCluiProtocolStatusChanged;
+ cli.pfnDrawMenuItem = fnDrawMenuItem;
+ cli.pfnInvalidateRect = fnInvalidateRect;
+ cli.pfnOnCreateClc = fnOnCreateClc;
+
+ cli.pfnChangeContactIcon = fnChangeContactIcon;
+ cli.pfnLoadContactTree = fnLoadContactTree;
+ cli.pfnCompareContacts = fnCompareContacts;
+ cli.pfnSortContacts = fnSortContacts;
+ cli.pfnSetHideOffline = fnSetHideOffline;
+
+ cli.pfnDocking_ProcessWindowMessage = fnDocking_ProcessWindowMessage;
+
+ cli.pfnGetWindowVisibleState = fnGetWindowVisibleState;
+ cli.pfnIconFromStatusMode = fnIconFromStatusMode;
+ cli.pfnShowHide = fnShowHide;
+ cli.pfnGetStatusModeDescription = fnGetStatusModeDescription;
+
+ cli.pfnGetGroupName = fnGetGroupName;
+ cli.pfnRenameGroup = fnRenameGroup;
+
+ cli.pfnHotKeysRegister = fnHotKeysRegister;
+ cli.pfnHotKeysUnregister = fnHotKeysUnregister;
+ cli.pfnHotKeysProcess = fnHotKeysProcess;
+ cli.pfnHotkeysProcessMessage = fnHotkeysProcessMessage;
+
+ cli.hInst = ( HMODULE )lParam;
+
+ rc = LoadContactListModule2();
+ if (rc == 0)
+ rc = LoadCLCModule();
+ interfaceInited = 1;
+ }
+
+ return ( int )( LPARAM )&cli;
+}
+
+int LoadContactListModule()
+{
+ CreateServiceFunction( MS_CLIST_RETRIEVE_INTERFACE, srvRetrieveInterface );
+ return 0;
+}
\ No newline at end of file diff --git a/miranda-wine/src/modules/clist/clistevents.c b/miranda-wine/src/modules/clist/clistevents.c new file mode 100644 index 0000000..f455d85 --- /dev/null +++ b/miranda-wine/src/modules/clist/clistevents.c @@ -0,0 +1,308 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+struct CListEvent
+{
+ int imlIconIndex;
+ int flashesDone;
+ CLISTEVENT cle;
+};
+
+struct CListImlIcon
+{
+ int index;
+ HICON hIcon;
+};
+static struct CListImlIcon *imlIcon;
+static int imlIconCount;
+
+extern HIMAGELIST hCListImages;
+
+static UINT flashTimerId;
+static int iconsOn;
+static int disableTrayFlash;
+static int disableIconFlash;
+
+int fnGetImlIconIndex(HICON hIcon)
+{
+ int i;
+
+ for (i = 0; i < imlIconCount; i++) {
+ if (imlIcon[i].hIcon == hIcon)
+ return imlIcon[i].index;
+ }
+ imlIcon = (struct CListImlIcon *) mir_realloc(imlIcon, sizeof(struct CListImlIcon) * (imlIconCount + 1));
+ imlIconCount++;
+ imlIcon[i].hIcon = hIcon;
+ imlIcon[i].index = ImageList_AddIcon(hCListImages, hIcon);
+ return imlIcon[i].index;
+}
+
+static VOID CALLBACK IconFlashTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ int i, j;
+
+ if (cli.events.count) {
+ char *szProto;
+ if (cli.events.items[0]->cle.hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) cli.events.items[0]->cle.hContact, 0);
+ cli.pfnTrayIconUpdateWithImageList((iconsOn || disableTrayFlash) ? cli.events.items[0]->imlIconIndex : 0, cli.events.items[0]->cle.ptszTooltip, szProto);
+ }
+ for (i = 0; i < cli.events.count; i++) {
+ for (j = 0; j < i; j++)
+ if (cli.events.items[j]->cle.hContact == cli.events.items[i]->cle.hContact)
+ break;
+ if (j < i)
+ continue;
+ cli.pfnChangeContactIcon(cli.events.items[i]->cle.hContact, iconsOn || disableIconFlash ? cli.events.items[i]->imlIconIndex : 0, 0);
+ if (cli.events.items[i]->cle.flags & CLEF_ONLYAFEW) {
+ if (0 == --cli.events.items[i]->flashesDone)
+ cli.pfnRemoveEvent( cli.events.items[i]->cle.hContact, cli.events.items[i]->cle.hDbEvent);
+ } }
+
+ iconsOn = !iconsOn;
+}
+
+struct CListEvent* fnAddEvent( CLISTEVENT *cle )
+{
+ int i;
+ struct CListEvent* p;
+
+ if (cle==NULL || cle->cbSize != sizeof(CLISTEVENT))
+ return NULL;
+
+ if (cle->flags & CLEF_URGENT) {
+ for (i = 0; i < cli.events.count; i++)
+ if (!(cli.events.items[i]->cle.flags & CLEF_URGENT))
+ break;
+ }
+ else i = cli.events.count;
+
+ if (( p = ( struct CListEvent* )cli.pfnCreateEvent()) == NULL )
+ return NULL;
+
+ List_Insert(( SortedList* )&cli.events, p, i );
+ p->cle = *cle;
+ p->imlIconIndex = fnGetImlIconIndex(cli.events.items[i]->cle.hIcon);
+ p->flashesDone = 12;
+ p->cle.pszService = mir_strdup(cli.events.items[i]->cle.pszService);
+ #if defined( _UNICODE )
+ if (p->cle.flags & CLEF_UNICODE)
+ p->cle.ptszTooltip = mir_tstrdup((TCHAR*)p->cle.ptszTooltip);
+ else
+ p->cle.ptszTooltip = a2u((char*)p->cle.pszTooltip); //if no flag defined it handled as unicode
+ #else
+ p->cle.ptszTooltip = mir_tstrdup(p->cle.ptszTooltip);
+ #endif
+
+ if (cli.events.count == 1) {
+ char *szProto;
+ if (cle->hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)cle->hContact, 0);
+ iconsOn = 1;
+ flashTimerId = SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "IconFlashTime", 550), IconFlashTimer);
+ cli.pfnTrayIconUpdateWithImageList( p->imlIconIndex, p->cle.ptszTooltip, szProto);
+ }
+ cli.pfnChangeContactIcon(cle->hContact, p->imlIconIndex, 1);
+ cli.pfnSortContacts();
+ return p;
+}
+
+// Removes an event from the contact list's queue
+// Returns 0 if the event was successfully removed, or nonzero if the event was not found
+int fnRemoveEvent( HANDLE hContact, HANDLE dbEvent )
+{
+ int i;
+ char *szProto;
+
+ // Find the event that should be removed
+ for (i = 0; i < cli.events.count; i++)
+ if ((cli.events.items[i]->cle.hContact == hContact) && (cli.events.items[i]->cle.hDbEvent == dbEvent))
+ break;
+
+ // Event was not found
+ if (i == cli.events.count)
+ return 1;
+
+ // Update contact's icon
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ cli.pfnChangeContactIcon(cli.events.items[i]->cle.hContact,
+ cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(cli.events.items[i]->cle.hContact, szProto, "Status",
+ ID_STATUS_OFFLINE), cli.events.items[i]->cle.hContact), 0);
+
+ // Free any memory allocated to the event
+ cli.pfnFreeEvent( cli.events.items[i] );
+ List_Remove(( SortedList* )&cli.events, i );
+
+ if (cli.events.count == 0) {
+ KillTimer(NULL, flashTimerId);
+ cli.pfnTrayIconSetToBase( hContact == NULL ? NULL : szProto);
+ }
+ else {
+ if (cli.events.items[0]->cle.hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) cli.events.items[0]->cle.hContact, 0);
+ cli.pfnTrayIconUpdateWithImageList(iconsOn ? cli.events.items[0]->imlIconIndex : 0, cli.events.items[0]->cle.ptszTooltip, szProto);
+ }
+
+ return 0;
+}
+
+CLISTEVENT* fnGetEvent( HANDLE hContact, int idx )
+{
+ int i;
+
+ if ( hContact == INVALID_HANDLE_VALUE) {
+ if (idx >= cli.events.count)
+ return NULL;
+ return &cli.events.items[idx]->cle;
+ }
+
+ for (i = 0; i < cli.events.count; i++)
+ if (cli.events.items[i]->cle.hContact == hContact)
+ if (idx-- == 0)
+ return &cli.events.items[i]->cle;
+ return NULL;
+}
+
+int fnEventsProcessContactDoubleClick(HANDLE hContact)
+{
+ int i;
+ HANDLE hDbEvent;
+
+ for (i = 0; i < cli.events.count; i++) {
+ if (cli.events.items[i]->cle.hContact == hContact) {
+ hDbEvent = cli.events.items[i]->cle.hDbEvent;
+ CallService(cli.events.items[i]->cle.pszService, (WPARAM) (HWND) NULL, (LPARAM) & cli.events.items[i]->cle);
+ cli.pfnRemoveEvent(hContact, hDbEvent);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int fnEventsProcessTrayDoubleClick(void)
+{
+ if (cli.events.count) {
+ HANDLE hContact, hDbEvent;
+ hContact = cli.events.items[0]->cle.hContact;
+ hDbEvent = cli.events.items[0]->cle.hDbEvent;
+ CallService(cli.events.items[0]->cle.pszService, (WPARAM) NULL, (LPARAM) & cli.events.items[0]->cle);
+ cli.pfnRemoveEvent(hContact, hDbEvent);
+ return 0;
+ }
+ return 1;
+}
+
+static int RemoveEventsForContact(WPARAM wParam, LPARAM lParam)
+{
+ int j, hit;
+
+ /*
+ the for(;;) loop is used here since the cli.events.count can not be relied upon to take us
+ thru the cli.events.items[] array without suffering from shortsightedness about how many unseen
+ events remain, e.g. three events, we remove the first, we're left with 2, the event
+ loop exits at 2 and we never see the real new 2.
+ */
+
+ for (; cli.events.count > 0;) {
+ for (hit = 0, j = 0; j < cli.events.count; j++) {
+ if (cli.events.items[j]->cle.hContact == (HANDLE) wParam) {
+ cli.pfnRemoveEvent((HANDLE)wParam, cli.events.items[j]->cle.hDbEvent);
+ hit = 1;
+ }
+ }
+ if (j == cli.events.count && hit == 0)
+ return 0; /* got to the end of the array and didnt remove anything */
+ }
+
+ return 0;
+}
+
+static int CListEventSettingsChanged(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ if (hContact == NULL && cws && cws->szModule && cws->szSetting && strcmp(cws->szModule, "CList") == 0) {
+ if (strcmp(cws->szSetting, "DisableTrayFlash") == 0)
+ disableTrayFlash = (int) cws->value.bVal;
+ else if (strcmp(cws->szSetting, "NoIconBlink") == 0)
+ disableIconFlash = (int) cws->value.bVal;
+ }
+ return 0;
+}
+
+/***************************************************************************************/
+
+int AddEventStub(WPARAM wParam, LPARAM lParam) { return cli.pfnAddEvent((CLISTEVENT*)lParam ) == NULL; }
+int RemoveEventStub(WPARAM wParam, LPARAM lParam) { return cli.pfnRemoveEvent((HANDLE)wParam,(HANDLE)lParam ); }
+int GetEventStub(WPARAM wParam, LPARAM lParam) { return (int)cli.pfnGetEvent((HANDLE)wParam,lParam); }
+
+int InitCListEvents(void)
+{
+ memset( &cli.events, 0, sizeof(cli.events));
+ cli.events.increment = 10;
+
+ disableTrayFlash = DBGetContactSettingByte(NULL, "CList", "DisableTrayFlash", 0);
+ disableIconFlash = DBGetContactSettingByte(NULL, "CList", "NoIconBlink", 0);
+ CreateServiceFunction(MS_CLIST_ADDEVENT, AddEventStub);
+ CreateServiceFunction(MS_CLIST_REMOVEEVENT, RemoveEventStub);
+ CreateServiceFunction(MS_CLIST_GETEVENT, GetEventStub);
+ HookEvent(ME_DB_CONTACT_DELETED, RemoveEventsForContact);
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED, CListEventSettingsChanged);
+ return 0;
+}
+
+struct CListEvent* fnCreateEvent( void )
+{
+ return (struct CListEvent*)mir_calloc( sizeof(struct CListEvent));
+}
+
+void fnFreeEvent( struct CListEvent* p )
+{
+ if ( p->cle.pszService )
+ mir_free( p->cle.pszService );
+ if ( p->cle.pszTooltip )
+ mir_free( p->cle.pszTooltip );
+ mir_free( p );
+}
+
+void UninitCListEvents(void)
+{
+ int i;
+ for (i = 0; i < cli.events.count; i++)
+ cli.pfnFreeEvent(( struct CListEvent* )cli.events.items[i] );
+ mir_free( cli.events.items );
+
+ if ( imlIcon != NULL )
+ mir_free( imlIcon );
+}
diff --git a/miranda-wine/src/modules/clist/clistmod.c b/miranda-wine/src/modules/clist/clistmod.c new file mode 100644 index 0000000..9e4d6b0 --- /dev/null +++ b/miranda-wine/src/modules/clist/clistmod.c @@ -0,0 +1,526 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+int AddMainMenuItem(WPARAM wParam, LPARAM lParam);
+int AddContactMenuItem(WPARAM wParam, LPARAM lParam);
+int ContactChangeGroup(WPARAM wParam, LPARAM lParam);
+int InitCListEvents(void);
+void UninitCListEvents(void);
+int ContactSettingChanged(WPARAM wParam, LPARAM lParam);
+int ContactAdded(WPARAM wParam, LPARAM lParam);
+int ContactDeleted(WPARAM wParam, LPARAM lParam);
+int GetContactDisplayName(WPARAM wParam, LPARAM lParam);
+int InvalidateDisplayName(WPARAM wParam, LPARAM lParam);
+int InitGroupServices(void);
+int Docking_IsDocked(WPARAM wParam, LPARAM lParam);
+int MenuProcessCommand(WPARAM wParam, LPARAM lParam);
+void InitDisplayNameCache(void);
+void FreeDisplayNameCache(void);
+void InitTray(void);
+void LoadCLUIModule();
+
+HANDLE hContactDoubleClicked, hContactIconChangedEvent;
+HIMAGELIST hCListImages;
+BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+extern BYTE nameOrder[];
+static int statusModeList[] = { ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH };
+static int skinIconStatusList[] = { SKINICON_STATUS_OFFLINE, SKINICON_STATUS_ONLINE, SKINICON_STATUS_AWAY, SKINICON_STATUS_NA, SKINICON_STATUS_OCCUPIED, SKINICON_STATUS_DND, SKINICON_STATUS_FREE4CHAT, SKINICON_STATUS_INVISIBLE, SKINICON_STATUS_ONTHEPHONE, SKINICON_STATUS_OUTTOLUNCH };
+struct ProtoIconIndex
+{
+ char *szProto;
+ int iIconBase;
+}
+static *protoIconIndex;
+static int protoIconIndexCount;
+static HANDLE hProtoAckHook;
+static HANDLE hContactSettingChanged;
+
+TCHAR* fnGetStatusModeDescription( int mode, int flags )
+{
+ static TCHAR szMode[64];
+ TCHAR* descr;
+ int noPrefixReqd = 0;
+ switch (mode) {
+ case ID_STATUS_OFFLINE:
+ descr = TranslateT("Offline");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_CONNECTING:
+ descr = TranslateT("Connecting");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_ONLINE:
+ descr = TranslateT("Online");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_AWAY:
+ descr = TranslateT("Away");
+ break;
+ case ID_STATUS_DND:
+ descr = TranslateT("DND");
+ break;
+ case ID_STATUS_NA:
+ descr = TranslateT("NA");
+ break;
+ case ID_STATUS_OCCUPIED:
+ descr = TranslateT("Occupied");
+ break;
+ case ID_STATUS_FREECHAT:
+ descr = TranslateT("Free for chat");
+ break;
+ case ID_STATUS_INVISIBLE:
+ descr = TranslateT("Invisible");
+ break;
+ case ID_STATUS_OUTTOLUNCH:
+ descr = TranslateT("Out to lunch");
+ break;
+ case ID_STATUS_ONTHEPHONE:
+ descr = TranslateT("On the phone");
+ break;
+ case ID_STATUS_IDLE:
+ descr = TranslateT("Idle");
+ break;
+ default:
+ if (mode > ID_STATUS_CONNECTING && mode < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES) {
+ mir_sntprintf(szMode, SIZEOF(szMode), TranslateT("Connecting (attempt %d)"), mode - ID_STATUS_CONNECTING + 1);
+ return szMode;
+ }
+ return NULL;
+ }
+ if (noPrefixReqd || !(flags & GSMDF_PREFIXONLINE))
+ return descr;
+
+ lstrcpy(szMode, TranslateT("Online"));
+ lstrcat(szMode, _T(": "));
+ lstrcat(szMode, descr);
+ return szMode;
+}
+
+static int GetStatusModeDescription(WPARAM wParam, LPARAM lParam)
+{
+ #ifdef UNICODE
+ if ( !( lParam & GCMDF_TCHAR ))
+ {
+ static char szMode[64]={0};
+ TCHAR* buf1 = (TCHAR*)cli.pfnGetStatusModeDescription(wParam,lParam);
+ char *buf2=u2a(buf1);
+ _snprintf(szMode,sizeof(szMode),"%s",buf2);
+ mir_free(buf2);
+ return (int)szMode;
+ }
+ #endif
+
+ return (int)cli.pfnGetStatusModeDescription(wParam,lParam);
+}
+
+static int ProtocolAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+
+ if (ack->type != ACKTYPE_STATUS)
+ return 0;
+ CallService(MS_CLUI_PROTOCOLSTATUSCHANGED, ack->lParam, (LPARAM) ack->szModule);
+
+ if ((int) ack->hProcess < ID_STATUS_ONLINE && ack->lParam >= ID_STATUS_ONLINE) {
+ DWORD caps;
+ caps = (DWORD) CallProtoService(ack->szModule, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (caps & PF1_SERVERCLIST) {
+ HANDLE hContact;
+ char *szProto;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !strcmp(szProto, ack->szModule))
+ if (DBGetContactSettingByte(hContact, "CList", "Delete", 0))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ }
+ }
+
+ cli.pfnTrayIconUpdateBase(ack->szModule);
+ return 0;
+}
+
+int fnIconFromStatusMode(const char *szProto, int status)
+{
+ int index, i;
+
+ for (index = 0; index < SIZEOF(statusModeList); index++)
+ if (status == statusModeList[index])
+ break;
+ if (index == SIZEOF(statusModeList))
+ index = 0;
+ if (szProto == NULL)
+ return index + 1;
+ for (i = 0; i < protoIconIndexCount; i++) {
+ if (strcmp(szProto, protoIconIndex[i].szProto))
+ continue;
+ return protoIconIndex[i].iIconBase + index;
+ }
+ return 1;
+}
+
+static int GetContactIcon(WPARAM wParam, LPARAM lParam)
+{
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ HANDLE hContact = (HANDLE)wParam;
+
+ return cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact);
+}
+
+static int ContactListShutdownProc(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact, hNext;
+
+ //remove transitory contacts
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact != NULL) {
+ hNext = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ hContact = hNext;
+ }
+ ImageList_Destroy(hCListImages);
+ UnhookEvent(hProtoAckHook);
+ UninitCListEvents();
+ mir_free(protoIconIndex);
+ DestroyHookableEvent(hContactDoubleClicked);
+ UnhookEvent(hContactSettingChanged);
+ return 0;
+}
+
+static int ContactListModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int i, protoCount, j, iImg;
+ PROTOCOLDESCRIPTOR **protoList;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & protoList);
+ protoIconIndexCount = 0;
+ protoIconIndex = NULL;
+ for (i = 0; i < protoCount; i++) {
+ if (protoList[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ protoIconIndex = (struct ProtoIconIndex *) mir_realloc(protoIconIndex, sizeof(struct ProtoIconIndex) * (protoIconIndexCount + 1));
+ protoIconIndex[protoIconIndexCount].szProto = protoList[i]->szName;
+ for (j = 0; j < SIZEOF(statusModeList); j++) {
+ iImg = ImageList_AddIcon(hCListImages, LoadSkinnedProtoIcon(protoList[i]->szName, statusModeList[j]));
+ if (j == 0)
+ protoIconIndex[protoIconIndexCount].iIconBase = iImg;
+ }
+ protoIconIndexCount++;
+ }
+ cli.pfnLoadContactTree();
+
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( NULL, TranslateT( "This plugin requires db3x plugin version 0.5.1.0 or later" ), _T("CList"), MB_OK );
+ return 1;
+ }
+
+ LoadCLUIModule();
+ return 0;
+}
+
+static int ContactDoubleClicked(WPARAM wParam, LPARAM lParam)
+{
+ // Check and an event from the CList queue for this hContact
+ if (cli.pfnEventsProcessContactDoubleClick((HANDLE) wParam))
+ NotifyEventHooks(hContactDoubleClicked, wParam, 0);
+
+ return 0;
+}
+
+static int GetIconsImageList(WPARAM wParam, LPARAM lParam)
+{
+ return (int) hCListImages;
+}
+
+static int ContactFilesDropped(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_FILE_SENDSPECIFICFILES, wParam, lParam);
+ return 0;
+}
+
+static int CListIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ int i, j;
+
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ ImageList_ReplaceIcon(hCListImages, i + 1, LoadSkinnedIcon(skinIconStatusList[i]));
+ ImageList_ReplaceIcon(hCListImages, IMAGE_GROUPOPEN, LoadSkinnedIcon(SKINICON_OTHER_GROUPOPEN));
+ ImageList_ReplaceIcon(hCListImages, IMAGE_GROUPSHUT, LoadSkinnedIcon(SKINICON_OTHER_GROUPSHUT));
+ for (i = 0; i < protoIconIndexCount; i++)
+ for (j = 0; j < SIZEOF(statusModeList); j++)
+ ImageList_ReplaceIcon(hCListImages, protoIconIndex[i].iIconBase + j, LoadSkinnedProtoIcon(protoIconIndex[i].szProto, statusModeList[j]));
+ cli.pfnTrayIconIconsChanged();
+ cli.pfnInvalidateRect((HWND) CallService(MS_CLUI_GETHWND, 0, 0), NULL, TRUE);
+ return 0;
+}
+
+/*
+Begin of Hrk's code for bug
+*/
+#define GWVS_HIDDEN 1
+#define GWVS_VISIBLE 2
+#define GWVS_COVERED 3
+#define GWVS_PARTIALLY_COVERED 4
+
+int fnGetWindowVisibleState(HWND hWnd, int iStepX, int iStepY)
+{
+ RECT rc = { 0 };
+ POINT pt = { 0 };
+ register int i = 0, j = 0, width = 0, height = 0, iCountedDots = 0, iNotCoveredDots = 0;
+ BOOL bPartiallyCovered = FALSE;
+ HWND hAux = 0;
+
+ if (hWnd == NULL) {
+ SetLastError(0x00000006); //Wrong handle
+ return -1;
+ }
+ //Some defaults now. The routine is designed for thin and tall windows.
+ if (iStepX <= 0)
+ iStepX = 4;
+ if (iStepY <= 0)
+ iStepY = 16;
+
+ if (IsIconic(hWnd) || !IsWindowVisible(hWnd))
+ return GWVS_HIDDEN;
+ else {
+ GetWindowRect(hWnd, &rc);
+ width = rc.right - rc.left;
+ height = rc.bottom - rc.top;
+
+ for (i = rc.top; i < rc.bottom; i += (height / iStepY)) {
+ pt.y = i;
+ for (j = rc.left; j < rc.right; j += (width / iStepX)) {
+ pt.x = j;
+ hAux = WindowFromPoint(pt);
+ while (GetParent(hAux) != NULL)
+ hAux = GetParent(hAux);
+ if (hAux != hWnd) //There's another window!
+ bPartiallyCovered = TRUE;
+ else
+ iNotCoveredDots++; //Let's count the not covered dots.
+ iCountedDots++; //Let's keep track of how many dots we checked.
+ }
+ }
+ if (iNotCoveredDots == iCountedDots) //Every dot was not covered: the window is visible.
+ return GWVS_VISIBLE;
+ else if (iNotCoveredDots == 0) //They're all covered!
+ return GWVS_COVERED;
+ else //There are dots which are visible, but they are not as many as the ones we counted: it's partially covered.
+ return GWVS_PARTIALLY_COVERED;
+ }
+}
+
+int fnShowHide(WPARAM wParam, LPARAM lParam)
+{
+ BOOL bShow = FALSE;
+
+ int iVisibleState = cli.pfnGetWindowVisibleState(cli.hwndContactList, 0, 0);
+
+ //bShow is FALSE when we enter the switch.
+ switch (iVisibleState) {
+ case GWVS_PARTIALLY_COVERED:
+ //If we don't want to bring it to top, we can use a simple break. This goes against readability ;-) but the comment explains it.
+ if (!DBGetContactSettingByte(NULL, "CList", "BringToFront", SETTING_BRINGTOFRONT_DEFAULT))
+ break;
+ case GWVS_COVERED: //Fall through (and we're already falling)
+ case GWVS_HIDDEN:
+ bShow = TRUE;
+ break;
+ case GWVS_VISIBLE: //This is not needed, but goes for readability.
+ bShow = FALSE;
+ break;
+ case -1: //We can't get here, both cli.hwndContactList and iStepX and iStepY are right.
+ return 0;
+ }
+ if (bShow == TRUE) {
+ WINDOWPLACEMENT pl = { 0 };
+ HMONITOR(WINAPI * MyMonitorFromWindow) (HWND, DWORD);
+ RECT rcScreen, rcWindow;
+ int offScreen = 0;
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, FALSE);
+ ShowWindow(cli.hwndContactList, SW_RESTORE);
+ SetWindowPos(cli.hwndContactList, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ if (!DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT))
+ SetWindowPos(cli.hwndContactList, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ SetForegroundWindow(cli.hwndContactList);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_NORMAL);
+ //this forces the window onto the visible screen
+ MyMonitorFromWindow = (HMONITOR(WINAPI *) (HWND, DWORD)) GetProcAddress(GetModuleHandleA("USER32"), "MonitorFromWindow");
+ GetWindowRect(cli.hwndContactList, &rcWindow);
+ if (MyMonitorFromWindow) {
+ if (MyMonitorFromWindow(cli.hwndContactList, 0) == NULL) {
+ BOOL(WINAPI * MyGetMonitorInfoA) (HMONITOR, LPMONITORINFO);
+ MONITORINFO mi = { 0 };
+ HMONITOR hMonitor = MyMonitorFromWindow(cli.hwndContactList, 2);
+ MyGetMonitorInfoA = (BOOL(WINAPI *) (HMONITOR, LPMONITORINFO)) GetProcAddress(GetModuleHandleA("USER32"), "GetMonitorInfoA");
+ mi.cbSize = sizeof(mi);
+ MyGetMonitorInfoA(hMonitor, &mi);
+ rcScreen = mi.rcWork;
+ offScreen = 1;
+ }
+ }
+ else {
+ RECT rcDest;
+ if (IntersectRect(&rcDest, &rcScreen, &rcWindow) == 0)
+ offScreen = 1;
+ }
+ if (offScreen) {
+ if (rcWindow.top >= rcScreen.bottom)
+ OffsetRect(&rcWindow, 0, rcScreen.bottom - rcWindow.bottom);
+ else if (rcWindow.bottom <= rcScreen.top)
+ OffsetRect(&rcWindow, 0, rcScreen.top - rcWindow.top);
+ if (rcWindow.left >= rcScreen.right)
+ OffsetRect(&rcWindow, rcScreen.right - rcWindow.right, 0);
+ else if (rcWindow.right <= rcScreen.left)
+ OffsetRect(&rcWindow, rcScreen.left - rcWindow.left, 0);
+ SetWindowPos(cli.hwndContactList, 0, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
+ SWP_NOZORDER);
+ }
+ }
+ else { //It needs to be hidden
+ ShowWindow(cli.hwndContactList, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+ if (MySetProcessWorkingSetSize != NULL && DBGetContactSettingByte(NULL, "CList", "DisableWorkingSet", 1))
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// old evil code. hopefully it will be deleted soon, cause nobody uses it now
+
+#define SAFESTRING(a) a?a:""
+
+int GetStatusModeOrdering(int statusMode);
+extern int sortByStatus, sortByProto;
+
+static int CompareContacts( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE a = (HANDLE) wParam, b = (HANDLE) lParam;
+ TCHAR namea[128], *nameb;
+ int statusa, statusb;
+ char *szProto1, *szProto2;
+ int rc;
+
+ szProto1 = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) a, 0);
+ szProto2 = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) b, 0);
+ statusa = DBGetContactSettingWord((HANDLE) a, SAFESTRING(szProto1), "Status", ID_STATUS_OFFLINE);
+ statusb = DBGetContactSettingWord((HANDLE) b, SAFESTRING(szProto2), "Status", ID_STATUS_OFFLINE);
+
+ if (sortByProto) {
+ /* deal with statuses, online contacts have to go above offline */
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ /* both are online, now check protocols */
+ rc = strcmp(SAFESTRING(szProto1), SAFESTRING(szProto2)); /* strcmp() doesn't like NULL so feed in "" as needed */
+ if (rc != 0 && (szProto1 != NULL && szProto2 != NULL))
+ return rc;
+ /* protocols are the same, order by display name */
+ }
+
+ if (sortByStatus) {
+ int ordera, orderb;
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ }
+ else {
+ //one is offline: offline goes below online
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ }
+
+ nameb = cli.pfnGetContactDisplayName( a, 0);
+ _tcsncpy(namea, nameb, SIZEOF(namea));
+ namea[ SIZEOF(namea)-1 ] = 0;
+ nameb = cli.pfnGetContactDisplayName( b, 0);
+
+ //otherwise just compare names
+ return _tcsicmp(namea, nameb);
+}
+
+/***************************************************************************************/
+
+static int TrayIconProcessMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnTrayIconProcessMessage( wParam, lParam ); }
+static int TrayIconPauseAutoHideStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnTrayIconPauseAutoHide( wParam, lParam ); }
+static int ShowHideStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnShowHide( wParam, lParam ); }
+static int SetHideOfflineStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnSetHideOffline( wParam, lParam ); }
+static int Docking_ProcessWindowMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnDocking_ProcessWindowMessage( wParam, lParam ); }
+static int HotkeysProcessMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnHotkeysProcessMessage( wParam, lParam ); }
+
+int LoadContactListModule2(void)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN, ContactListShutdownProc);
+ HookEvent(ME_SYSTEM_MODULESLOADED, ContactListModulesLoaded);
+ hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+ HookEvent(ME_DB_CONTACT_ADDED, ContactAdded);
+ HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ hProtoAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, ProtocolAck);
+ hContactDoubleClicked = CreateHookableEvent(ME_CLIST_DOUBLECLICKED);
+ hContactIconChangedEvent = CreateHookableEvent(ME_CLIST_CONTACTICONCHANGED);
+ CreateServiceFunction(MS_CLIST_CONTACTDOUBLECLICKED, ContactDoubleClicked);
+ CreateServiceFunction(MS_CLIST_CONTACTFILESDROPPED, ContactFilesDropped);
+ CreateServiceFunction(MS_CLIST_GETSTATUSMODEDESCRIPTION, GetStatusModeDescription);
+ CreateServiceFunction(MS_CLIST_GETCONTACTDISPLAYNAME, GetContactDisplayName);
+ CreateServiceFunction(MS_CLIST_INVALIDATEDISPLAYNAME, InvalidateDisplayName);
+ CreateServiceFunction(MS_CLIST_TRAYICONPROCESSMESSAGE, TrayIconProcessMessageStub );
+ CreateServiceFunction(MS_CLIST_PAUSEAUTOHIDE, TrayIconPauseAutoHideStub);
+ CreateServiceFunction(MS_CLIST_CONTACTSCOMPARE, CompareContacts);
+ CreateServiceFunction(MS_CLIST_CONTACTCHANGEGROUP, ContactChangeGroup);
+ CreateServiceFunction(MS_CLIST_SHOWHIDE, ShowHideStub);
+ CreateServiceFunction(MS_CLIST_SETHIDEOFFLINE, SetHideOfflineStub);
+ CreateServiceFunction(MS_CLIST_DOCKINGPROCESSMESSAGE, Docking_ProcessWindowMessageStub);
+ CreateServiceFunction(MS_CLIST_DOCKINGISDOCKED, Docking_IsDocked);
+ CreateServiceFunction(MS_CLIST_HOTKEYSPROCESSMESSAGE, HotkeysProcessMessageStub);
+ CreateServiceFunction(MS_CLIST_GETCONTACTICON, GetContactIcon);
+ MySetProcessWorkingSetSize = (BOOL(WINAPI *) (HANDLE, SIZE_T, SIZE_T)) GetProcAddress(GetModuleHandleA("kernel32"), "SetProcessWorkingSetSize");
+ InitDisplayNameCache();
+ InitCListEvents();
+ InitGroupServices();
+ InitTray();
+
+ hCListImages = ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16), 13, 0);
+ HookEvent(ME_SKIN_ICONSCHANGED, CListIconsChanged);
+ CreateServiceFunction(MS_CLIST_GETICONSIMAGELIST, GetIconsImageList);
+ ImageList_AddIcon(hCListImages, LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_BLANK)));
+ {
+ int i;
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ ImageList_AddIcon(hCListImages, LoadSkinnedIcon(skinIconStatusList[i]));
+ }
+ //see IMAGE_GROUP... in clist.h if you add more images above here
+ ImageList_AddIcon(hCListImages, LoadSkinnedIcon(SKINICON_OTHER_GROUPOPEN));
+ ImageList_AddIcon(hCListImages, LoadSkinnedIcon(SKINICON_OTHER_GROUPSHUT));
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/clistsettings.c b/miranda-wine/src/modules/clist/clistsettings.c new file mode 100644 index 0000000..afae3aa --- /dev/null +++ b/miranda-wine/src/modules/clist/clistsettings.c @@ -0,0 +1,380 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+#include "../database/dblists.h"
+
+SortedList* clistCache = NULL;
+
+static int compareContacts( ClcCacheEntryBase* p1, ClcCacheEntryBase* p2 )
+{
+ return ( char* )p1->hContact - ( char* )p2->hContact;
+}
+
+void InitDisplayNameCache(void)
+{
+ clistCache = List_Create( 0, 50 );
+ clistCache->sortFunc = compareContacts;
+}
+
+void FreeDisplayNameCache(void)
+{
+ if ( clistCache != NULL ) {
+ int i;
+ for ( i = 0; i < clistCache->realCount; i++) {
+ cli.pfnFreeCacheItem(( ClcCacheEntryBase* )clistCache->items[i] );
+ mir_free( clistCache->items[i] );
+ }
+
+ List_Destroy( clistCache );
+ mir_free(clistCache);
+ clistCache = NULL;
+} }
+
+// default handlers for the cache item creation and destruction
+
+ClcCacheEntryBase* fnCreateCacheItem( HANDLE hContact )
+{
+ ClcCacheEntryBase* p = ( ClcCacheEntryBase* )mir_calloc( sizeof( ClcCacheEntryBase ));
+ if ( p == NULL )
+ return NULL;
+
+ p->hContact = hContact;
+ return p;
+}
+
+void fnCheckCacheItem( ClcCacheEntryBase* p )
+{
+ DBVARIANT dbv;
+ if ( p->group == NULL ) {
+ if ( !DBGetContactSettingTString( p->hContact, "CList", "Group", &dbv )) {
+ p->group = mir_tstrdup( dbv.ptszVal );
+ mir_free( dbv.ptszVal );
+ }
+ else p->group = mir_tstrdup( _T("") );
+ }
+
+ if ( p->isHidden == -1 )
+ p->isHidden = DBGetContactSettingByte( p->hContact, "CList", "Hidden", 0 );
+}
+
+void fnFreeCacheItem( ClcCacheEntryBase* p )
+{
+ if ( p->name ) { mir_free( p->name ); p->name = NULL; }
+ #if defined( _UNICODE )
+ if ( p->szName ) { mir_free( p->szName); p->szName = NULL; }
+ #endif
+ if ( p->group ) { mir_free( p->group ); p->group = NULL; }
+ p->isHidden = -1;
+}
+
+ClcCacheEntryBase* fnGetCacheEntry(HANDLE hContact)
+{
+ ClcCacheEntryBase* p;
+ int idx;
+ if ( !List_GetIndex( clistCache, &hContact, &idx )) {
+ if (( p = cli.pfnCreateCacheItem( hContact )) != NULL ) {
+ List_Insert( clistCache, p, idx );
+ cli.pfnInvalidateDisplayNameCacheEntry( p );
+ }
+ }
+ else p = ( ClcCacheEntryBase* )clistCache->items[idx];
+
+ cli.pfnCheckCacheItem( p );
+ return p;
+}
+
+void fnInvalidateDisplayNameCacheEntry(HANDLE hContact)
+{
+ if (hContact == INVALID_HANDLE_VALUE) {
+ FreeDisplayNameCache();
+ InitDisplayNameCache();
+ SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0);
+ }
+ else {
+ int idx;
+ if ( List_GetIndex( clistCache, &hContact, &idx ))
+ cli.pfnFreeCacheItem(( ClcCacheEntryBase* )clistCache->items[idx] );
+} }
+
+TCHAR* fnGetContactDisplayName( HANDLE hContact, int mode )
+{
+ CONTACTINFO ci;
+ TCHAR *buffer;
+ ClcCacheEntryBase* cacheEntry = NULL;
+
+ if ( mode & GCDNF_NOCACHE )
+ mode &= ~GCDNF_NOCACHE;
+ else if ( mode != GCDNF_NOMYHANDLE) {
+ cacheEntry = cli.pfnGetCacheEntry( hContact );
+ if ( cacheEntry->name )
+ return cacheEntry->name;
+ }
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ if (ci.hContact == NULL)
+ ci.szProto = "ICQ";
+ ci.dwFlag = (mode == GCDNF_NOMYHANDLE) ? CNF_DISPLAYNC : CNF_DISPLAY;
+ #if defined( _UNICODE )
+ ci.dwFlag += CNF_UNICODE;
+ #endif
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (cacheEntry == NULL) {
+ size_t len = _tcslen(ci.pszVal);
+ buffer = (TCHAR*) mir_alloc( sizeof( TCHAR )*( len+1 ));
+ memcpy( buffer, ci.pszVal, len * sizeof( TCHAR ));
+ buffer[ len ] = 0;
+ mir_free(ci.pszVal);
+ return buffer;
+ }
+ else {
+ cacheEntry->name = ci.pszVal;
+ #if defined( _UNICODE )
+ cacheEntry->szName = u2a( ci.pszVal );
+ #endif
+ return ci.pszVal;
+ } }
+
+ if (ci.type == CNFT_DWORD) {
+ if (cacheEntry == NULL) {
+ buffer = (TCHAR*) mir_alloc(15 * sizeof( TCHAR ));
+ _ltot(ci.dVal, buffer, 10 );
+ return buffer;
+ }
+ else {
+ buffer = (TCHAR*) mir_alloc(15 * sizeof( TCHAR ));
+ _ltot(ci.dVal, buffer, 10 );
+ cacheEntry->name = buffer;
+ #if defined( _UNICODE )
+ cacheEntry->szName = u2a( buffer );
+ #else
+ #endif
+ return buffer;
+ } } }
+
+ CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0);
+ buffer = TranslateT("(Unknown Contact)");
+ return buffer;
+}
+
+int GetContactDisplayName(WPARAM wParam, LPARAM lParam)
+{
+ CONTACTINFO ci;
+ ClcCacheEntryBase* cacheEntry = NULL;
+ char *buffer;
+ HANDLE hContact = (HANDLE)wParam;
+
+ if ( lParam & GCDNF_UNICODE )
+ return ( int )cli.pfnGetContactDisplayName(hContact, lParam & ~GCDNF_UNICODE );
+
+ if ((int) lParam != GCDNF_NOMYHANDLE) {
+ cacheEntry = cli.pfnGetCacheEntry(hContact);
+ #if defined( _UNICODE )
+ if ( cacheEntry->szName )
+ return (int)cacheEntry->szName;
+ #else
+ if ( cacheEntry->name )
+ return (int)cacheEntry->name;
+ #endif
+ }
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ if (ci.hContact == NULL)
+ ci.szProto = "ICQ";
+ ci.dwFlag = (int) lParam == GCDNF_NOMYHANDLE ? CNF_DISPLAYNC : CNF_DISPLAY;
+ #if defined( _UNICODE )
+ ci.dwFlag += CNF_UNICODE;
+ #endif
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (cacheEntry == NULL) {
+ size_t len = _tcslen(ci.pszVal);
+ #if defined( _UNICODE )
+ buffer = u2a( ci.pszVal );
+ mir_free(ci.pszVal);
+ #else
+ buffer = ci.pszVal;
+ #endif
+ return (int) buffer;
+ }
+ else {
+ cacheEntry->name = ci.pszVal;
+ #if defined( _UNICODE )
+ cacheEntry->szName = u2a( ci.pszVal );
+ return (int)cacheEntry->szName;
+ #else
+ return (int)cacheEntry->name;
+ #endif
+ }
+ }
+ if (ci.type == CNFT_DWORD) {
+ if (cacheEntry == NULL) {
+ buffer = ( char* )mir_alloc(15);
+ ltoa(ci.dVal, buffer, 10 );
+ return (int) buffer;
+ }
+ else {
+ buffer = ( char* )mir_alloc(15);
+ ltoa(ci.dVal, buffer, 10 );
+ #if defined( _UNICODE )
+ cacheEntry->szName = buffer;
+ cacheEntry->name = a2u( buffer );
+ #else
+ cacheEntry->name = buffer;
+ #endif
+ return (int) buffer;
+ } } }
+
+ CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0);
+ buffer = Translate("(Unknown Contact)");
+ return (int) buffer;
+}
+
+int InvalidateDisplayName(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam);
+ return 0;
+}
+
+int ContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnChangeContactIcon((HANDLE)wParam, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), ID_STATUS_OFFLINE, NULL), 1);
+ cli.pfnSortContacts();
+ return 0;
+}
+
+int ContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ return 0;
+}
+
+int ContactSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ DBVARIANT dbv;
+ HANDLE hContact = (HANDLE)wParam;
+
+ // Early exit
+ if ( hContact == NULL)
+ return 0;
+
+ dbv.pszVal = NULL;
+ if (!DBGetContactSetting(hContact, "Protocol", "p", &dbv)) {
+ if (!strcmp(cws->szModule, dbv.pszVal)) {
+ cli.pfnInvalidateDisplayNameCacheEntry(hContact);
+ if (!strcmp(cws->szSetting, "UIN") || !strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName")
+ || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "e-mail")) {
+ CallService(MS_CLUI_CONTACTRENAMED, wParam, 0);
+ }
+ else if (!strcmp(cws->szSetting, "Status")) {
+ if (!DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)) {
+ // User's state is changing, and we are hideOffline-ing
+ if (cws->value.wVal == ID_STATUS_OFFLINE) {
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0);
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ mir_free(dbv.pszVal);
+ return 0;
+ }
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 1);
+ }
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0);
+ }
+ }
+ else {
+ mir_free(dbv.pszVal);
+ return 0;
+ }
+ cli.pfnSortContacts();
+ }
+ }
+
+ if (!strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "Hidden")) {
+ if (cws->value.type == DBVT_DELETED || cws->value.bVal == 0) {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(szProto, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact), 1);
+ }
+ else
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ }
+ if (!strcmp(cws->szSetting, "MyHandle")) {
+ cli.pfnInvalidateDisplayNameCacheEntry(hContact);
+ }
+ }
+
+ if (!strcmp(cws->szModule, "Protocol")) {
+ if (!strcmp(cws->szSetting, "p")) {
+ char *szProto;
+ if (cws->value.type == DBVT_DELETED)
+ szProto = NULL;
+ else
+ szProto = cws->value.pszVal;
+ cli.pfnChangeContactIcon(hContact,
+ cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status",
+ ID_STATUS_OFFLINE), hContact), 0);
+ }
+ }
+
+ // Clean up
+ if (dbv.pszVal)
+ mir_free(dbv.pszVal);
+
+ return 0;
+
+}
+
+/*-----------------------------------------------------*/
+
+char* u2a( wchar_t* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+wchar_t* a2u( char* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
+ wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
+ if ( result == NULL )
+ return NULL;
+
+ MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
+ result[ cbLen ] = 0;
+ return result;
+}
diff --git a/miranda-wine/src/modules/clist/clisttray.c b/miranda-wine/src/modules/clist/clisttray.c new file mode 100644 index 0000000..eca2cab --- /dev/null +++ b/miranda-wine/src/modules/clist/clisttray.c @@ -0,0 +1,632 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+#define TRAYICON_ID_BASE 100
+#define TIM_CALLBACK (WM_USER+1857)
+#define TIM_CREATE (WM_USER+1858)
+
+static VOID CALLBACK TrayCycleTimerProc(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime);
+void fnTrayIconUpdateBase(const char *szChangedProto);
+
+extern HIMAGELIST hCListImages;
+extern int currentStatusMenuItem, currentDesiredStatusMode;
+extern BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+
+static UINT WM_TASKBARCREATED;
+static int cycleTimerId = 0, cycleStep = 0;
+static int RefreshTimerId=0; /////by FYR
+
+struct trayIconInfo_t
+{
+ int id;
+ char *szProto;
+ HICON hBaseIcon;
+ int isBase;
+};
+static struct trayIconInfo_t *trayIcon = NULL;
+static int trayIconCount;
+
+// don't move to win2k.h, need new and old versions to work on 9x/2000/XP
+#define NIF_STATE 0x00000008
+#define NIF_INFO 0x00000010
+
+typedef struct _DllVersionInfo
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion; // Major version
+ DWORD dwMinorVersion; // Minor version
+ DWORD dwBuildNumber; // Build number
+ DWORD dwPlatformID; // DLLVER_PLATFORM_*
+}
+ DLLVERSIONINFO;
+
+#define DLLVER_PLATFORM_WINDOWS 0x00000001 // Windows 95
+#define DLLVER_PLATFORM_NT 0x00000002 // Windows NT
+typedef HRESULT(CALLBACK * DLLGETVERSIONPROC) (DLLVERSIONINFO *);
+
+static DLLVERSIONINFO dviShell;
+
+static TCHAR *TrayIconMakeTooltip(const TCHAR *szPrefix, const char *szProto)
+{
+ static TCHAR szTip[128];
+ char szProtoName[32];
+ TCHAR *szStatus, *szSeparator, *sztProto;
+
+ szSeparator = (IsWinVerMEPlus())? szSeparator = _T("\n") : _T(" | ");
+
+ if (szProto == NULL) {
+ PROTOCOLDESCRIPTOR **protos;
+ int count, netProtoCount, i;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (i = 0, netProtoCount = 0; i < count; i++)
+ if (protos[i]->type == PROTOTYPE_PROTOCOL)
+ netProtoCount++;
+ if (netProtoCount == 1)
+ for (i = 0; i < count; i++)
+ if (protos[i]->type == PROTOTYPE_PROTOCOL)
+ return TrayIconMakeTooltip(szPrefix, protos[i]->szName);
+ if (szPrefix && szPrefix[0]) {
+ lstrcpyn(szTip, szPrefix, SIZEOF(szTip));
+ if (!DBGetContactSettingByte(NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT))
+ return szTip;
+ }
+ else
+ szTip[0] = '\0';
+ szTip[ SIZEOF(szTip) - 1] = '\0';
+ for (i = count - 1; i >= 0; i--) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ CallProtoService(protos[i]->szName, PS_GETNAME, SIZEOF(szProtoName), (LPARAM) szProtoName);
+ szStatus = cli.pfnGetStatusModeDescription( CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0), 0);
+ if (szTip[0])
+ _tcsncat(szTip, szSeparator, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ #if defined( _UNICODE )
+ { TCHAR* p = a2u( szProtoName );
+ _tcsncat(szTip, p, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ mir_free( p );
+ }
+ #else
+ _tcsncat(szTip, szProtoName, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ #endif
+ _tcsncat(szTip, _T(" "), SIZEOF(szTip) - 1 - _tcslen(szTip));
+ _tcsncat(szTip, szStatus, SIZEOF(szTip) - 1 - _tcslen(szTip));
+ }
+ }
+ else {
+ CallProtoService(szProto, PS_GETNAME, SIZEOF(szProtoName), (LPARAM) szProtoName);
+ #if defined( _UNICODE )
+ sztProto = a2u( szProtoName );
+ #else
+ sztProto = szProtoName;
+ #endif
+
+ szStatus = cli.pfnGetStatusModeDescription(CallProtoService(szProto, PS_GETSTATUS, 0, 0), 0);
+ if (szPrefix && szPrefix[0]) {
+ if (DBGetContactSettingByte(NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT))
+ mir_sntprintf(szTip, SIZEOF(szTip), _T("%s%s%s %s"), szPrefix, szSeparator, sztProto, szStatus);
+ else
+ lstrcpyn(szTip, szPrefix, SIZEOF(szTip));
+ }
+ else mir_sntprintf(szTip, SIZEOF(szTip), _T("%s %s"), sztProto, szStatus);
+
+ #if defined( _UNICODE )
+ mir_free(sztProto);
+ #endif
+ }
+ return szTip;
+}
+
+static int TrayIconAdd(HWND hwnd, const char *szProto, const char *szIconProto, int status)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ for (i = 0; i < trayIconCount; i++)
+ if (trayIcon[i].id == 0)
+ break;
+
+ trayIcon[i].id = TRAYICON_ID_BASE + i;
+ trayIcon[i].szProto = (char *) szProto;
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ nid.uID = trayIcon[i].id;
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = TIM_CALLBACK;
+ trayIcon[i].hBaseIcon = ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(szIconProto ? szIconProto : trayIcon[i].szProto, status, NULL), ILD_NORMAL);
+ nid.hIcon = trayIcon[i].hBaseIcon;
+
+ if (dviShell.dwMajorVersion >= 5)
+ nid.uFlags |= NIF_INFO;
+
+ lstrcpyn(nid.szTip, TrayIconMakeTooltip(NULL, trayIcon[i].szProto), SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ trayIcon[i].isBase = 1;
+ return i;
+}
+
+static void TrayIconRemove(HWND hwnd, const char *szProto)
+{
+ int i;
+ NOTIFYICONDATA nid = { 0 };
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(szProto, trayIcon[i].szProto))
+ continue;
+ nid.uID = trayIcon[i].id;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ trayIcon[i].id = 0;
+ break;
+ }
+}
+
+static int TrayIconInit(HWND hwnd)
+{
+ int count, netProtoCount, i;
+ int averageMode = 0;
+ PROTOCOLDESCRIPTOR **protos;
+
+ if (cycleTimerId) {
+ KillTimer(NULL, cycleTimerId);
+ cycleTimerId = 0;
+ }
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (i = 0, netProtoCount = 0; i < count; i++) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ cycleStep = i;
+ netProtoCount++;
+ if (averageMode == 0)
+ averageMode = CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0);
+ else if (averageMode != CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0)) {
+ averageMode = -1;
+ break;
+ }
+ }
+ trayIconCount = count;
+ trayIcon = (struct trayIconInfo_t *) mir_alloc(sizeof(struct trayIconInfo_t) * count);
+ ZeroMemory(trayIcon, sizeof(struct trayIconInfo_t) * count);
+ if (DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI &&
+ (averageMode <= 0 || DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))) {
+ int i;
+ for (i = count - 1; i >= 0; i--)
+ if (protos[i]->type == PROTOTYPE_PROTOCOL)
+ TrayIconAdd(hwnd, protos[i]->szName, NULL, CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0));
+ }
+ else if (averageMode <= 0 && DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_SINGLE) {
+ DBVARIANT dbv = { DBVT_DELETED };
+ char *szProto;
+ if (DBGetContactSetting(NULL, "CList", "PrimaryStatus", &dbv))
+ szProto = NULL;
+ else
+ szProto = dbv.pszVal;
+ TrayIconAdd(hwnd, NULL, szProto, szProto ? CallProtoService(szProto, PS_GETSTATUS, 0, 0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0));
+ DBFreeVariant(&dbv);
+ }
+ else
+ TrayIconAdd(hwnd, NULL, NULL, averageMode);
+ if (averageMode <= 0 && DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_CYCLE)
+ cycleTimerId = SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, TrayCycleTimerProc);
+ return 0;
+}
+
+static void TrayIconDestroy(HWND hwnd)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ nid.uID = trayIcon[i].id;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ }
+ if (trayIcon)
+ mir_free(trayIcon);
+ trayIcon = NULL;
+ trayIconCount = 0;
+}
+
+//called when Explorer crashes and the taskbar is remade
+static void TrayIconTaskbarCreated(HWND hwnd)
+{
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+}
+
+static int TrayIconUpdate(HICON hNewIcon, const TCHAR *szNewTip, const char *szPreferredProto, int isBase)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ nid.uFlags = NIF_ICON | NIF_TIP;
+ nid.hIcon = hNewIcon;
+
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(trayIcon[i].szProto, szPreferredProto))
+ continue;
+ nid.uID = trayIcon[i].id;
+ lstrcpyn(nid.szTip, TrayIconMakeTooltip(szNewTip, trayIcon[i].szProto), SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+
+ trayIcon[i].isBase = isBase;
+ return i;
+ }
+
+ //if there wasn't a suitable icon, change all the icons
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ nid.uID = trayIcon[i].id;
+ lstrcpyn(nid.szTip, TrayIconMakeTooltip(szNewTip, trayIcon[i].szProto), SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+
+ trayIcon[i].isBase = isBase;
+ }
+ return -1;
+}
+
+static int TrayIconSetBaseInfo(HICON hIcon, char *szPreferredProto)
+{
+ int i;
+
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(trayIcon[i].szProto, szPreferredProto))
+ continue;
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ trayIcon[i].hBaseIcon = hIcon;
+ return i;
+ }
+ //if there wasn't a specific icon, there will only be one suitable
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ DestroyIcon(trayIcon[i].hBaseIcon);
+ trayIcon[i].hBaseIcon = hIcon;
+ return i;
+ }
+ DestroyIcon(hIcon);
+ return -1;
+}
+
+void fnTrayIconUpdateWithImageList(int iImage, const TCHAR *szNewTip, char *szPreferredProto)
+{
+ HICON hIcon = ImageList_GetIcon(hCListImages, iImage, ILD_NORMAL);
+ TrayIconUpdate(hIcon, szNewTip, szPreferredProto, 0);
+ DestroyIcon(hIcon);
+}
+
+static VOID CALLBACK TrayCycleTimerProc(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ int count;
+ PROTOCOLDESCRIPTOR **protos;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (cycleStep++;; cycleStep++) {
+ if (cycleStep >= count)
+ cycleStep = 0;
+ if (protos[cycleStep]->type == PROTOTYPE_PROTOCOL)
+ break;
+ }
+ DestroyIcon(trayIcon[0].hBaseIcon);
+ trayIcon[0].hBaseIcon =
+ ImageList_GetIcon(hCListImages,
+ cli.pfnIconFromStatusMode(protos[cycleStep]->szName, CallProtoService(protos[cycleStep]->szName, PS_GETSTATUS, 0, 0), NULL), ILD_NORMAL);
+ if (trayIcon[0].isBase)
+ TrayIconUpdate(trayIcon[0].hBaseIcon, NULL, NULL, 1);
+}
+
+void fnTrayIconUpdateBase(const char *szChangedProto)
+{
+ int i, count, netProtoCount, changed = -1;
+ PROTOCOLDESCRIPTOR **protos;
+ int averageMode = 0;
+ HWND hwnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+
+ if (cycleTimerId) {
+ KillTimer(NULL, cycleTimerId);
+ cycleTimerId = 0;
+ }
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & count, (LPARAM) & protos);
+ for (i = 0, netProtoCount = 0; i < count; i++) {
+ if (protos[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ netProtoCount++;
+ if (!lstrcmpA(szChangedProto, protos[i]->szName))
+ cycleStep = i;
+ if (averageMode == 0)
+ averageMode = CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0);
+ else if (averageMode != CallProtoService(protos[i]->szName, PS_GETSTATUS, 0, 0)) {
+ averageMode = -1;
+ break;
+ }
+ }
+ if (netProtoCount > 1) {
+ if (averageMode > 0) {
+ if (DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI) {
+ if (DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(szChangedProto, averageMode, NULL), ILD_NORMAL), (char*)szChangedProto);
+ else if (trayIcon && trayIcon[0].szProto != NULL) {
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+ }
+ else
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+ }
+ else
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+ }
+ else {
+ switch (DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT)) {
+ case SETTING_TRAYICON_SINGLE:
+ {
+ DBVARIANT dbv = { DBVT_DELETED };
+ char *szProto;
+ if (DBGetContactSetting(NULL, "CList", "PrimaryStatus", &dbv))
+ szProto = NULL;
+ else
+ szProto = dbv.pszVal;
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages,cli.pfnIconFromStatusMode(szProto,szProto ? CallProtoService(szProto, PS_GETSTATUS, 0,0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0), NULL),ILD_NORMAL), NULL);
+ DBFreeVariant(&dbv);
+ break;
+ }
+ case SETTING_TRAYICON_CYCLE:
+ cycleTimerId =
+ SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, TrayCycleTimerProc);
+ changed =
+ TrayIconSetBaseInfo(ImageList_GetIcon
+ (hCListImages, cli.pfnIconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), NULL),
+ ILD_NORMAL), NULL);
+ break;
+ case SETTING_TRAYICON_MULTI:
+ if (!trayIcon) {
+ TrayIconRemove(NULL, NULL);
+ }
+ else if (DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), NULL), ILD_NORMAL), (char*)szChangedProto);
+ else {
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+ }
+ break;
+ }
+ }
+ }
+ else
+ changed = TrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+ if (changed != -1 && trayIcon[changed].isBase)
+ TrayIconUpdate(trayIcon[changed].hBaseIcon, NULL, trayIcon[changed].szProto, 1);
+}
+
+void fnTrayIconSetToBase(char *szPreferredProto)
+{
+ int i;
+
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(trayIcon[i].szProto, szPreferredProto))
+ continue;
+ TrayIconUpdate(trayIcon[i].hBaseIcon, NULL, szPreferredProto, 1);
+ return;
+ }
+ //if there wasn't a specific icon, there will only be one suitable
+ for (i = 0; i < trayIconCount; i++) {
+ if (trayIcon[i].id == 0)
+ continue;
+ TrayIconUpdate(trayIcon[i].hBaseIcon, NULL, szPreferredProto, 1);
+ return;
+ }
+}
+
+void fnTrayIconIconsChanged(void)
+{
+ HWND hwnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ TrayIconDestroy(hwnd);
+ TrayIconInit(hwnd);
+}
+
+static int autoHideTimerId;
+static VOID CALLBACK TrayIconAutoHideTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ HWND hwndClui;
+ KillTimer(hwnd, idEvent);
+ hwndClui = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ if (GetActiveWindow() == hwndClui)
+ return;
+ ShowWindow(hwndClui, SW_HIDE);
+ if (MySetProcessWorkingSetSize != NULL)
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+}
+
+int fnTrayIconPauseAutoHide(WPARAM wParam, LPARAM lParam)
+{
+ if (DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT)) {
+ if (GetActiveWindow() != (HWND) CallService(MS_CLUI_GETHWND, 0, 0)) {
+ KillTimer(NULL, autoHideTimerId);
+ autoHideTimerId = SetTimer(NULL, 0, 1000 * DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), TrayIconAutoHideTimer);
+ }
+ }
+ return 0;
+}
+
+int fnTrayIconProcessMessage(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *) wParam;
+ switch (msg->message) {
+ case WM_CREATE: {
+ WM_TASKBARCREATED = RegisterWindowMessageA("TaskbarCreated");
+ PostMessage(msg->hwnd, TIM_CREATE, 0, 0);
+ break;
+ }
+ case TIM_CREATE:
+ TrayIconInit(msg->hwnd);
+ break;
+ case WM_ACTIVATE:
+ if (DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT)) {
+ if (LOWORD(msg->wParam) == WA_INACTIVE)
+ autoHideTimerId = SetTimer(NULL, 0, 1000 * DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), TrayIconAutoHideTimer);
+ else
+ KillTimer(NULL, autoHideTimerId);
+ }
+ break;
+ case WM_DESTROY:
+ TrayIconDestroy(msg->hwnd);
+ break;
+ case TIM_CALLBACK:
+ if (msg->lParam == WM_MBUTTONUP) {
+ cli.pfnShowHide(0, 0);
+ }
+ else if (msg->lParam ==
+ (DBGetContactSettingByte(NULL, "CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT) ? WM_LBUTTONUP : WM_LBUTTONDBLCLK)) {
+ if ((GetAsyncKeyState(VK_CONTROL) & 0x8000))
+ cli.pfnShowHide(0, 0);
+ else {
+ if (cli.pfnEventsProcessTrayDoubleClick())
+ cli.pfnShowHide(0, 0);
+ }
+ }
+ else if (msg->lParam == WM_RBUTTONUP) {
+ MENUITEMINFO mi;
+ POINT pt;
+ HMENU hMainMenu = LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ HMENU hMenu = GetSubMenu(hMainMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMenu, 0);
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = MENUITEMINFO_V4_SIZE;
+ mi.fMask = MIIM_SUBMENU | MIIM_TYPE;
+ mi.fType = MFT_STRING;
+ mi.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ mi.dwTypeData = TranslateT("&Main Menu");
+ InsertMenuItem(hMenu, 1, TRUE, &mi);
+ mi.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ mi.dwTypeData = TranslateT("&Status");
+ InsertMenuItem(hMenu, 2, TRUE, &mi);
+ SetMenuDefaultItem(hMenu, ID_TRAY_HIDE, FALSE);
+
+ SetForegroundWindow(msg->hwnd);
+ SetFocus(msg->hwnd);
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, msg->hwnd, NULL);
+
+ RemoveMenu(hMenu, 1, MF_BYPOSITION);
+ RemoveMenu(hMenu, 1, MF_BYPOSITION);
+ DestroyMenu(hMainMenu);
+ }
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ default:
+ if (msg->message == WM_TASKBARCREATED) {
+ TrayIconTaskbarCreated(msg->hwnd);
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+int fnCListTrayNotify(MIRANDASYSTRAYNOTIFY *msn)
+{
+ if (msn && msn->cbSize == sizeof(MIRANDASYSTRAYNOTIFY) && msn->szInfo && msn->szInfoTitle) {
+ if (trayIcon) {
+ NOTIFYICONDATAA nid = { 0 };
+ nid.cbSize = ( dviShell.dwMajorVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATAA_V1_SIZE;
+ nid.hWnd = (HWND) CallService(MS_CLUI_GETHWND, 0, 0);
+ if (msn->szProto) {
+ int j;
+ for (j = 0; j < trayIconCount; j++) {
+ if (trayIcon[j].szProto != NULL) {
+ if (strcmp(msn->szProto, trayIcon[j].szProto) == 0) {
+ nid.uID = trayIcon[j].id;
+ j = trayIconCount;
+ continue;
+ }
+ }
+ else {
+ if (trayIcon[j].isBase) {
+ nid.uID = trayIcon[j].id;
+ j = trayIconCount;
+ continue;
+ }
+ }
+ } //for
+ }
+ else {
+ nid.uID = trayIcon[0].id;
+ }
+ nid.uFlags = NIF_INFO;
+ lstrcpynA(nid.szInfo, msn->szInfo, sizeof(nid.szInfo));
+ lstrcpynA(nid.szInfoTitle, msn->szInfoTitle, sizeof(nid.szInfoTitle));
+ nid.uTimeout = msn->uTimeout;
+ nid.dwInfoFlags = msn->dwInfoFlags;
+ return Shell_NotifyIconA(NIM_MODIFY, (void *) &nid) == 0;
+ }
+ return 2;
+ }
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int pfnCListTrayNotifyStub(WPARAM wParam, LPARAM lParam )
+{ return cli.pfnCListTrayNotify(( MIRANDASYSTRAYNOTIFY* )lParam );
+}
+
+void InitTray(void)
+{
+ HINSTANCE hLib;
+
+ hLib = LoadLibraryA("shell32.dll");
+ if (hLib) {
+ DLLGETVERSIONPROC proc;
+ dviShell.cbSize = sizeof(dviShell);
+ proc = (DLLGETVERSIONPROC) GetProcAddress(hLib, "DllGetVersion");
+ if (proc) {
+ proc(&dviShell);
+ }
+ FreeLibrary(hLib);
+ }
+ if (dviShell.dwMajorVersion >= 5)
+ CreateServiceFunction(MS_CLIST_SYSTRAY_NOTIFY, pfnCListTrayNotifyStub );
+
+ return;
+}
diff --git a/miranda-wine/src/modules/clist/clui.c b/miranda-wine/src/modules/clist/clui.c new file mode 100644 index 0000000..6437321 --- /dev/null +++ b/miranda-wine/src/modules/clist/clui.c @@ -0,0 +1,1042 @@ +/*
+
+ Miranda IM: the free IM client for Microsoft* Windows*
+
+ Copyright 2000-2006 Miranda ICQ/IM project,
+ all portions of this codebase are copyrighted to the people
+ listed in contributors.txt.
+
+ 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 "commonheaders.h"
+#include "clc.h"
+
+#define TM_AUTOALPHA 1
+#define MENU_MIRANDAMENU 0xFFFF1234
+
+static HMODULE hUserDll;
+static HIMAGELIST himlMirandaIcon;
+static HANDLE hContactDraggingEvent, hContactDroppedEvent, hContactDragStopEvent;
+static int transparentFocus = 1;
+UINT uMsgProcessProfile;
+
+void LoadCluiServices();
+
+BOOL(WINAPI * MySetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+BOOL(WINAPI * MyAnimateWindow) (HWND hWnd, DWORD dwTime, DWORD dwFlags);
+
+typedef struct {
+ int showsbar;
+ int showgrip;
+ int transparent;
+ int alpha;
+} CluiOpts;
+static CluiOpts cluiopt = {0};
+
+void fnLoadCluiGlobalOpts() {
+ cluiopt.showsbar = DBGetContactSettingByte(NULL, "CLUI", "ShowSBar", 1);
+ cluiopt.showgrip = DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1);
+ cluiopt.transparent = DBGetContactSettingByte(NULL,"CList","Transparent",SETTING_TRANSPARENT_DEFAULT);
+ cluiopt.alpha = DBGetContactSettingByte(NULL, "CList", "Alpha", SETTING_ALPHA_DEFAULT);
+}
+
+static int CluiModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ MENUITEMINFO mii;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, 0, TRUE, &mii);
+ mii.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, 1, TRUE, &mii);
+ return 0;
+}
+
+// Restore protocols to the last global status.
+// Used to reconnect on restore after standby.
+static void RestoreMode(HWND hwnd)
+{
+ int nStatus = DBGetContactSettingWord(NULL, "CList", "Status", ID_STATUS_OFFLINE);
+ if (nStatus != ID_STATUS_OFFLINE)
+ PostMessage(hwnd&&IsWindow(hwnd)?hwnd:cli.hwndContactList, WM_COMMAND, nStatus, 0);
+}
+
+// Disconnect all protocols.
+// Happens on shutdown and standby.
+static void DisconnectAll()
+{
+ PROTOCOLDESCRIPTOR **ppProtoDesc;
+ int nProtoCount;
+ int nProto;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & nProtoCount, (LPARAM) & ppProtoDesc);
+ for (nProto = 0; nProto < nProtoCount; nProto++) {
+ if (ppProtoDesc[nProto]->type == PROTOTYPE_PROTOCOL)
+ CallProtoService(ppProtoDesc[nProto]->szName, PS_SETSTATUS, ID_STATUS_OFFLINE, 0);
+ }
+}
+
+static int CluiIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ ImageList_ReplaceIcon(himlMirandaIcon, 0, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ DrawMenuBar(cli.hwndContactList);
+ return 0;
+}
+
+static HANDLE hRenameMenuItem;
+
+static int MenuItem_PreBuild(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR cls[128];
+ HANDLE hItem;
+ HWND hwndClist = GetFocus();
+ CLISTMENUITEM mi;
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS;
+ GetClassName(hwndClist, cls, SIZEOF(cls));
+ hwndClist = (!lstrcmp(CLISTCONTROL_CLASS, cls)) ? hwndClist : cli.hwndContactList;
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_GETSELECTION, 0, 0);
+ if (!hItem) {
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hRenameMenuItem, (LPARAM) & mi);
+ return 0;
+}
+
+static int MenuItem_RenameContact(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR cls[128];
+ HANDLE hItem;
+ HWND hwndClist = GetFocus();
+ GetClassName(hwndClist, cls, SIZEOF(cls));
+ // worst case scenario, the rename is sent to the main contact list
+ hwndClist = (!lstrcmp(CLISTCONTROL_CLASS, cls)) ? hwndClist : cli.hwndContactList;
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_GETSELECTION, 0, 0);
+ if (hItem) {
+ SetFocus(hwndClist);
+ SendMessage(hwndClist, CLM_EDITLABEL, (WPARAM) hItem, 0);
+ }
+ return 0;
+}
+
+static BOOL CALLBACK AskForConfirmationDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hWnd);
+ {
+ LOGFONT lf;
+ HFONT hFont;
+
+ hFont = (HFONT) SendDlgItemMessage(hWnd, IDYES, WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ SendDlgItemMessage(hWnd, IDC_TOPLINE, WM_SETFONT, (WPARAM) CreateFontIndirect(&lf), 0);
+ }
+ {
+ TCHAR szFormat[256];
+ TCHAR szFinal[256];
+
+ GetDlgItemText(hWnd, IDC_TOPLINE, szFormat, SIZEOF(szFormat));
+ mir_sntprintf(szFinal, SIZEOF(szFinal), szFormat, cli.pfnGetContactDisplayName((HANDLE)lParam, 0));
+ SetDlgItemText(hWnd, IDC_TOPLINE, szFinal);
+ }
+ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDYES:
+ if (IsDlgButtonChecked(hWnd, IDC_HIDE)) {
+ EndDialog(hWnd, IDC_HIDE);
+ break;
+ }
+ //fall through
+ case IDCANCEL:
+ case IDNO:
+ EndDialog(hWnd, LOWORD(wParam));
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDNO, BN_CLICKED), 0);
+ break;
+
+ case WM_DESTROY:
+ DeleteObject((HFONT) SendDlgItemMessage(hWnd, IDC_TOPLINE, WM_GETFONT, 0, 0));
+ break;
+ }
+
+ return FALSE;
+
+}
+
+static int MenuItem_DeleteContact(WPARAM wParam, LPARAM lParam)
+{
+ //see notes about deleting contacts on PF1_SERVERCLIST servers in m_protosvc.h
+ int action;
+
+ if (DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT))
+ // Ask user for confirmation, and if the contact should be archived (hidden, not deleted)
+ action = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DELETECONTACT), (HWND) lParam, AskForConfirmationDlgProc, wParam);
+ else
+ action = IDYES;
+
+ switch (action) {
+
+ // Delete contact
+ case IDYES:
+ {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL) {
+ // Check if protocol uses server side lists
+ DWORD caps;
+
+ caps = (DWORD) CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (caps & PF1_SERVERCLIST) {
+ int status;
+
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (status == ID_STATUS_OFFLINE || (status >= ID_STATUS_CONNECTING && status < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES)) {
+ // Set a flag so we remember to delete the contact when the protocol goes online the next time
+ DBWriteContactSettingByte((HANDLE) wParam, "CList", "Delete", 1);
+ MessageBox( NULL,
+ TranslateT("This contact is on an instant messaging system which stores its contact list on a central server. The contact will be removed from the server and from your contact list when you next connect to that network."),
+ TranslateT("Delete Contact"), MB_OK);
+ return 0;
+ } } }
+
+ CallService(MS_DB_CONTACT_DELETE, wParam, 0);
+ }
+ break;
+
+ // Archive contact
+ case IDC_HIDE:
+ DBWriteContactSettingByte((HANDLE) wParam, "CList", "Hidden", 1);
+ break;
+ }
+
+ return 0;
+}
+
+static int MenuItem_AddContactToList(WPARAM wParam, LPARAM lParam)
+{
+ ADDCONTACTSTRUCT acs = { 0 };
+
+ acs.handle = (HANDLE) wParam;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = "";
+
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM) NULL, (LPARAM) & acs);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// this is the smalles available window procedure
+
+#ifndef CS_DROPSHADOW
+#define CS_DROPSHADOW 0x00020000
+#endif
+
+LRESULT CALLBACK ContactListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ MSG m;
+ m.hwnd=hwnd;
+ m.message=msg;
+ m.wParam=wParam;
+ m.lParam=lParam;
+ if ( cli.pfnDocking_ProcessWindowMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+ if ( cli.pfnTrayIconProcessMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+ if ( cli.pfnHotkeysProcessMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+
+ return cli.pfnContactListWndProc( hwnd, msg, wParam, lParam );
+}
+
+int LoadCLUIModule(void)
+{
+ WNDCLASS wndclass;
+ DBVARIANT dbv;
+ TCHAR titleText[256];
+
+ uMsgProcessProfile = RegisterWindowMessageA("Miranda::ProcessProfile");
+ cli.pfnLoadCluiGlobalOpts();
+ hUserDll = LoadLibraryA("user32.dll");
+ if (hUserDll) {
+ MySetLayeredWindowAttributes = (BOOL(WINAPI *) (HWND, COLORREF, BYTE, DWORD)) GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
+ MyAnimateWindow = (BOOL(WINAPI *) (HWND, DWORD, DWORD)) GetProcAddress(hUserDll, "AnimateWindow");
+ }
+ HookEvent(ME_SYSTEM_MODULESLOADED, CluiModulesLoaded);
+ HookEvent(ME_SKIN_ICONSCHANGED, CluiIconsChanged);
+
+ hContactDraggingEvent = CreateHookableEvent(ME_CLUI_CONTACTDRAGGING);
+ hContactDroppedEvent = CreateHookableEvent(ME_CLUI_CONTACTDROPPED);
+ hContactDragStopEvent = CreateHookableEvent(ME_CLUI_CONTACTDRAGSTOP);
+ LoadCluiServices();
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
+ wndclass.lpfnWndProc = cli.pfnContactListControlWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(void *);
+ wndclass.hInstance = cli.hInst;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = CLISTCONTROL_CLASS;
+ RegisterClass(&wndclass);
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | (IsWinVerXPPlus() && DBGetContactSettingByte(NULL, "CList", "WindowShadow", 0) == 1 ? CS_DROPSHADOW : 0);
+ wndclass.lpfnWndProc = ContactListWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = cli.hInst;
+ wndclass.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
+ wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_CLISTMENU);
+ wndclass.lpszClassName = _T(MIRANDACLASS);
+ RegisterClass(&wndclass);
+
+ if (DBGetContactSettingTString(NULL, "CList", "TitleText", &dbv))
+ lstrcpyn(titleText, _T(MIRANDANAME), SIZEOF( titleText ));
+ else {
+ lstrcpyn(titleText, dbv.ptszVal, SIZEOF(titleText));
+ DBFreeVariant(&dbv);
+ }
+
+ cli.hwndContactList = CreateWindowEx(
+ DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT) ? WS_EX_TOOLWINDOW : 0,
+ _T(MIRANDACLASS),
+ titleText,
+ (DBGetContactSettingByte(NULL, "CLUI", "ShowCaption", SETTING_SHOWCAPTION_DEFAULT) ?
+ WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX : 0) | WS_POPUPWINDOW | WS_THICKFRAME | WS_CLIPCHILDREN,
+ (int) DBGetContactSettingDword(NULL, "CList", "x", 700),
+ (int) DBGetContactSettingDword(NULL, "CList", "y", 221),
+ (int) DBGetContactSettingDword(NULL, "CList", "Width", 108),
+ (int) DBGetContactSettingDword(NULL, "CList", "Height", 310),
+ NULL, NULL, cli.hInst, NULL);
+
+ if (DBGetContactSettingByte(NULL, "CList", "OnDesktop", 0)) {
+ HWND hProgMan = FindWindowA("Progman", NULL);
+ if (IsWindow(hProgMan))
+ SetParent(cli.hwndContactList, hProgMan);
+ }
+
+ cli.pfnOnCreateClc();
+
+ {
+ int state = DBGetContactSettingByte(NULL, "CList", "State", SETTING_STATE_NORMAL);
+ cli.hMenuMain = GetMenu(cli.hwndContactList);
+ if (!DBGetContactSettingByte(NULL, "CLUI", "ShowMainMenu", SETTING_SHOWMAINMENU_DEFAULT))
+ SetMenu(cli.hwndContactList, NULL);
+ if (state == SETTING_STATE_NORMAL)
+ ShowWindow(cli.hwndContactList, SW_SHOW);
+ else if (state == SETTING_STATE_MINIMIZED)
+ ShowWindow(cli.hwndContactList, SW_SHOWMINIMIZED);
+ SetWindowPos(cli.hwndContactList, DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ }
+ {
+ CLISTMENUITEM mi;
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+
+ CreateServiceFunction("CList/DeleteContactCommand", MenuItem_DeleteContact);
+ mi.position = 2000070000;
+ mi.flags = 0;
+ mi.hIcon = LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_DELETE));
+ mi.pszContactOwner = NULL; //on every contact
+ mi.pszName = Translate("De&lete");
+ mi.pszService = "CList/DeleteContactCommand";
+ CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ CreateServiceFunction("CList/RenameContactCommand", MenuItem_RenameContact);
+ mi.position = 2000050000;
+ mi.flags = 0;
+ mi.hIcon = LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_RENAME));
+ mi.pszContactOwner = NULL; //on every contact
+ mi.pszName = Translate("&Rename");
+ mi.pszService = "CList/RenameContactCommand";
+ hRenameMenuItem = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MenuItem_PreBuild);
+
+ CreateServiceFunction("CList/AddToListContactCommand", MenuItem_AddContactToList);
+ mi.position = -2050000000;
+ mi.flags = CMIF_NOTONLIST;
+ mi.hIcon = LoadIcon(cli.hInst, MAKEINTRESOURCE(IDI_ADDCONTACT));
+ mi.pszName = Translate("&Add permanently to list");
+ mi.pszService = "CList/AddToListContactCommand";
+ CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default contact list window procedure
+
+void fnDrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, HICON eventIcon)
+{
+ if (!IsWinVerXPPlus()) {
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dis->itemState & ODS_HOTLIGHT)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_RAISEDINNER, BF_RECT);
+ else if (dis->itemState & ODS_SELECTED)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_SUNKENOUTER, BF_RECT);
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else {
+ HBRUSH hBr;
+ BOOL bfm = FALSE;
+ SystemParametersInfo(SPI_GETFLATMENU, 0, &bfm, 0);
+ if (bfm) {
+ /* flat menus: fill with COLOR_MENUHILIGHT and outline with COLOR_HIGHLIGHT, otherwise use COLOR_MENUBAR */
+ if (dis->itemState & ODS_SELECTED || dis->itemState & ODS_HOTLIGHT) {
+ /* selected or hot lighted, no difference */
+ hBr = GetSysColorBrush(COLOR_MENUHILIGHT);
+ FillRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ /* draw the frame */
+ hBr = GetSysColorBrush(COLOR_HIGHLIGHT);
+ FrameRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ } else {
+ /* flush the DC with the menu bar colour (only supported on XP) and then draw the icon */
+ hBr = GetSysColorBrush(COLOR_MENUBAR);
+ FillRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ } //if
+ /* draw the icon */
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else {
+ /* non-flat menus, flush the DC with a normal menu colour */
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dis->itemState & ODS_HOTLIGHT)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_RAISEDINNER, BF_RECT);
+ else if (dis->itemState & ODS_SELECTED)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_SUNKENOUTER, BF_RECT);
+
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ } }
+
+ DestroyIcon(hIcon);
+ return;
+}
+
+#define M_CREATECLC (WM_USER+1)
+LRESULT CALLBACK fnContactListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == uMsgProcessProfile) {
+ char profile[MAX_PATH];
+ int rc;
+ // wParam = (ATOM)hProfileAtom, lParam = 0
+ if (GlobalGetAtomNameA((ATOM) wParam, profile, SIZEOF(profile))) {
+ char path[MAX_PATH];
+ char file[MAX_PATH];
+ char p[MAX_PATH];
+ CallService(MS_DB_GETPROFILEPATH, SIZEOF(path), (LPARAM) & path);
+ CallService(MS_DB_GETPROFILENAME, SIZEOF(file), (LPARAM) & file);
+ mir_snprintf(p, SIZEOF(p), "%s\\%s", path, file);
+ rc = lstrcmpiA(profile, p) == 0;
+ ReplyMessage(rc);
+ if (rc) {
+ ShowWindow(hwnd, SW_SHOW);
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ }
+ return 0;
+ }
+
+ switch (msg) {
+ case WM_NCCREATE:
+ {
+ MENUITEMINFO mii;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_TYPE | MIIM_DATA;
+ himlMirandaIcon = ImageList_Create(g_IconWidth, g_IconHeight, ILC_COLOR32 | ILC_MASK, 1, 1);
+ ImageList_AddIcon(himlMirandaIcon, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ mii.dwItemData = MENU_MIRANDAMENU;
+ mii.fType = MFT_OWNERDRAW;
+ mii.dwTypeData = NULL;
+ SetMenuItemInfo(GetMenu(hwnd), 0, TRUE, &mii);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ case WM_CREATE:
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) GetMenu(hwnd), 0);
+ DrawMenuBar(hwnd);
+
+ //create the status wnd
+ {
+ int flags = WS_CHILD | CCS_BOTTOM;
+ flags |= cluiopt.showsbar ? WS_VISIBLE : 0;
+ flags |= cluiopt.showgrip ? SBARS_SIZEGRIP : 0;
+ cli.hwndStatus = CreateWindow(STATUSCLASSNAME, NULL, flags, 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL);
+ }
+ cli.pfnCluiProtocolStatusChanged(0, 0);
+
+ //delay creation of CLC so that it can get the status icons right the first time (needs protocol modules loaded)
+ PostMessage(hwnd, M_CREATECLC, 0, 0);
+
+ if (cluiopt.transparent) {
+ SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+ if (MySetLayeredWindowAttributes)
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ }
+ transparentFocus = 1;
+
+ #ifndef _DEBUG
+ // Miranda is starting up! Restore last status mode.
+ // This is not done in debug builds because frequent
+ // reconnections will get you banned from the servers.
+ RestoreMode(hwnd);
+ #endif
+
+ return FALSE;
+
+ case M_CREATECLC:
+ cli.hwndContactTree = CreateWindow( CLISTCONTROL_CLASS, _T(""),
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
+ | CLS_CONTACTLIST
+ | (DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) ? CLS_USEGROUPS : 0)
+ | (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? CLS_HIDEOFFLINE : 0)
+ | (DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) ?
+ CLS_HIDEEMPTYGROUPS : 0), 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ break;
+
+ // Power management
+ case WM_POWERBROADCAST:
+ switch ((DWORD) wParam) {
+ case PBT_APMSUSPEND:
+ // Computer is suspending, disconnect all protocols
+ DisconnectAll();
+ break;
+
+ case PBT_APMRESUMESUSPEND:
+ // Computer is resuming, restore all protocols
+ RestoreMode(NULL);
+ break;
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ SendMessage(cli.hwndContactTree, msg, wParam, lParam);
+ SendMessage(cli.hwndStatus, msg, wParam, lParam);
+ // XXX: only works with 4.71 with 95, IE4.
+ SendMessage(cli.hwndStatus, SB_SETBKCOLOR, 0, GetSysColor(COLOR_3DFACE));
+ break;
+
+ case WM_SIZE:
+ if (IsZoomed(hwnd))
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ {
+ RECT rect, rcStatus;
+ GetClientRect(hwnd, &rect);
+ if (cluiopt.showsbar) {
+ SetWindowPos(cli.hwndStatus, NULL, 0, rect.bottom - 20, rect.right - rect.left, 20, SWP_NOZORDER);
+ GetWindowRect(cli.hwndStatus, &rcStatus);
+ cli.pfnCluiProtocolStatusChanged(0, 0);
+ }
+ else
+ rcStatus.top = rcStatus.bottom = 0;
+ SetWindowPos(cli.hwndContactTree, NULL, 0, 0, rect.right, rect.bottom - (rcStatus.bottom - rcStatus.top), SWP_NOZORDER);
+ }
+ if (wParam == SIZE_MINIMIZED) {
+ if (DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT)) {
+ ShowWindow(hwnd, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+ }
+ else
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_MINIMIZED);
+ }
+ // drop thru
+ case WM_MOVE:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ DBWriteContactSettingDword(NULL, "CList", "Height", (DWORD) (rc.bottom - rc.top));
+ DBWriteContactSettingDword(NULL, "CList", "x", (DWORD) rc.left);
+ DBWriteContactSettingDword(NULL, "CList", "y", (DWORD) rc.top);
+ }
+ DBWriteContactSettingDword(NULL, "CList", "Width", (DWORD) (rc.right - rc.left));
+ }
+ return FALSE;
+
+ case WM_SETFOCUS:
+ SetFocus(cli.hwndContactTree);
+ return 0;
+
+ case WM_ACTIVATE:
+ if (wParam == WA_INACTIVE) {
+ if ((HWND) wParam != hwnd)
+ if (cluiopt.transparent)
+ if (transparentFocus)
+ SetTimer(hwnd, TM_AUTOALPHA, 250, NULL);
+ }
+ else {
+ if (cluiopt.transparent) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ if (MySetLayeredWindowAttributes)
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ transparentFocus = 1;
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_SETCURSOR:
+ if(cluiopt.transparent) {
+ if (!transparentFocus && GetForegroundWindow()!=hwnd && MySetLayeredWindowAttributes) {
+ MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)cluiopt.alpha, LWA_ALPHA);
+ transparentFocus=1;
+ SetTimer(hwnd, TM_AUTOALPHA,250,NULL);
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_NCHITTEST:
+ {
+ LRESULT result;
+ result = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT ||
+ result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT)
+ if (DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0))
+ return HTCLIENT;
+ return result;
+ }
+
+ case WM_TIMER:
+ if ((int) wParam == TM_AUTOALPHA) {
+ int inwnd;
+
+ if (GetForegroundWindow() == hwnd) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ inwnd = 1;
+ }
+ else {
+ POINT pt;
+ HWND hwndPt;
+ pt.x = (short) LOWORD(GetMessagePos());
+ pt.y = (short) HIWORD(GetMessagePos());
+ hwndPt = WindowFromPoint(pt);
+ inwnd = (hwndPt == hwnd || GetParent(hwndPt) == hwnd);
+ }
+ if (inwnd != transparentFocus && MySetLayeredWindowAttributes) { //change
+ transparentFocus = inwnd;
+ if (transparentFocus)
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ else
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) DBGetContactSettingByte(NULL, "CList", "AutoAlpha", SETTING_AUTOALPHA_DEFAULT), LWA_ALPHA);
+ }
+ if (!transparentFocus)
+ KillTimer(hwnd, TM_AUTOALPHA);
+ }
+ return TRUE;
+
+ case WM_SHOWWINDOW:
+ {
+ static int noRecurse = 0;
+ if (lParam)
+ break;
+ if (noRecurse)
+ break;
+ if (!DBGetContactSettingByte(NULL, "CLUI", "FadeInOut", 0) || !IsWinVer2000Plus())
+ break;
+ if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) {
+ DWORD thisTick, startTick;
+ int sourceAlpha, destAlpha;
+ if (wParam) {
+ sourceAlpha = 0;
+ destAlpha = (BYTE) cluiopt.alpha;
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_ALPHA);
+ noRecurse = 1;
+ ShowWindow(hwnd, SW_SHOW);
+ noRecurse = 0;
+ }
+ else {
+ sourceAlpha = (BYTE) cluiopt.alpha;
+ destAlpha = 0;
+ }
+ for (startTick = GetTickCount();;) {
+ thisTick = GetTickCount();
+ if (thisTick >= startTick + 200)
+ break;
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0),
+ (BYTE) (sourceAlpha + (destAlpha - sourceAlpha) * (int) (thisTick - startTick) / 200), LWA_ALPHA);
+ }
+ MySetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) destAlpha, LWA_ALPHA);
+ }
+ else {
+ if (wParam)
+ SetForegroundWindow(hwnd);
+ MyAnimateWindow(hwnd, 200, AW_BLEND | (wParam ? 0 : AW_HIDE));
+ SetWindowPos(cli.hwndContactTree, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ }
+ break;
+ }
+ case WM_MENURBUTTONUP: /* this API is so badly documented at MSDN!! */
+ {
+ UINT id = 0;
+
+ id = GetMenuItemID((HMENU) lParam, LOWORD(wParam)); /* LOWORD(wParam) contains the menu pos in its parent menu */
+ if (id != (-1))
+ SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(id, 0), 0);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ case WM_SYSCOMMAND:
+ if (wParam == SC_MAXIMIZE)
+ return 0;
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_COMMAND:
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), (LPARAM) (HANDLE) NULL))
+ break;
+ switch (LOWORD(wParam)) {
+ case ID_TRAY_EXIT:
+ case ID_ICQ_EXIT:
+ if (CallService(MS_SYSTEM_OKTOEXIT, 0, 0))
+ DestroyWindow(hwnd);
+ break;
+ case ID_TRAY_HIDE:
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ break;
+ case POPUP_NEWGROUP:
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0);
+ CallService(MS_CLIST_GROUPCREATE, 0, 0);
+ break;
+ case POPUP_HIDEOFFLINE:
+ CallService(MS_CLIST_SETHIDEOFFLINE, (WPARAM) (-1), 0);
+ break;
+ case POPUP_HIDEOFFLINEROOT:
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEOFFLINEROOT, !SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0), 0);
+ break;
+ case POPUP_HIDEEMPTYGROUPS:
+ {
+ int newVal = !(GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS);
+ DBWriteContactSettingByte(NULL, "CList", "HideEmptyGroups", (BYTE) newVal);
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_DISABLEGROUPS:
+ {
+ int newVal = !(GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS);
+ DBWriteContactSettingByte(NULL, "CList", "UseGroups", (BYTE) newVal);
+ SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_HIDEMIRANDA:
+ {
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ break;
+ } }
+ return FALSE;
+ case WM_KEYDOWN:
+ CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_MAINMENU | MPCF_CONTACTMENU);
+ break;
+
+ case WM_GETMINMAXINFO:
+ DefWindowProc(hwnd, msg, wParam, lParam);
+ ((LPMINMAXINFO) lParam)->ptMinTrackSize.x = 16 + GetSystemMetrics(SM_CXHTHUMB);
+ ((LPMINMAXINFO) lParam)->ptMinTrackSize.y = 16;
+ return 0;
+
+ case WM_DISPLAYCHANGE:
+ SendMessage(cli.hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
+ break;
+
+ //MSG FROM CHILD CONTROL
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->hwndFrom == cli.hwndContactTree) {
+ switch (((LPNMHDR) lParam)->code) {
+ case CLN_EXPANDED:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM) nmc->hItem, nmc->action);
+ return FALSE;
+ }
+ case CLN_DRAGGING:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ ClientToScreen(hwnd, &nmc->pt);
+ if (!(nmc->flags & CLNF_ISGROUP))
+ if (NotifyEventHooks(hContactDraggingEvent, (WPARAM) nmc->hItem, MAKELPARAM(nmc->pt.x, nmc->pt.y))) {
+ SetCursor(LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)));
+ return TRUE;
+ }
+ break;
+ }
+ case CLN_DRAGSTOP:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ if (!(nmc->flags & CLNF_ISGROUP))
+ NotifyEventHooks(hContactDragStopEvent, (WPARAM) nmc->hItem, 0);
+ break;
+ }
+ case CLN_DROPPED:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ ClientToScreen(hwnd, &nmc->pt);
+ if (!(nmc->flags & CLNF_ISGROUP))
+ if (NotifyEventHooks(hContactDroppedEvent, (WPARAM) nmc->hItem, MAKELPARAM(nmc->pt.x, nmc->pt.y))) {
+ SetCursor(LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)));
+ return TRUE;
+ }
+ break;
+ }
+ case NM_KEYDOWN:
+ {
+ NMKEY *nmkey = (NMKEY *) lParam;
+ return CallService(MS_CLIST_MENUPROCESSHOTKEY, nmkey->nVKey, MPCF_MAINMENU | MPCF_CONTACTMENU);
+ }
+ case CLN_LISTSIZECHANGE:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ RECT rcWindow, rcTree, rcWorkArea;
+ int maxHeight, newHeight;
+
+ if (!DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0))
+ break;
+ if (CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0))
+ break;
+ maxHeight = DBGetContactSettingByte(NULL, "CLUI", "MaxSizeHeight", 75);
+ GetWindowRect(hwnd, &rcWindow);
+ GetWindowRect(cli.hwndContactTree, &rcTree);
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, FALSE);
+ newHeight = max(nmc->pt.y, 9) + 1 + (rcWindow.bottom - rcWindow.top) - (rcTree.bottom - rcTree.top);
+ if (newHeight > (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100)
+ newHeight = (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100;
+ if (DBGetContactSettingByte(NULL, "CLUI", "AutoSizeUpward", 0)) {
+ rcWindow.top = rcWindow.bottom - newHeight;
+ if (rcWindow.top < rcWorkArea.top)
+ rcWindow.top = rcWorkArea.top;
+ }
+ else {
+ rcWindow.bottom = rcWindow.top + newHeight;
+ if (rcWindow.bottom > rcWorkArea.bottom)
+ rcWindow.bottom = rcWorkArea.bottom;
+ }
+ SetWindowPos(hwnd, 0, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ break;
+ }
+ case NM_CLICK:
+ {
+ NMCLISTCONTROL *nm = (NMCLISTCONTROL *) lParam;
+ DWORD hitFlags;
+
+ if (SendMessage(cli.hwndContactTree, CLM_HITTEST, (WPARAM) & hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y)))
+ break;
+ if ((hitFlags & (CLCHT_NOWHERE | CLCHT_INLEFTMARGIN | CLCHT_BELOWITEMS)) == 0)
+ break;
+ if (DBGetContactSettingByte(NULL, "CLUI", "ClientAreaDrag", SETTING_CLIENTDRAG_DEFAULT)) {
+ POINT pt;
+ pt = nm->pt;
+ ClientToScreen(cli.hwndContactTree, &pt);
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ } }
+ }
+ else if (((LPNMHDR) lParam)->hwndFrom == cli.hwndStatus) {
+ if (((LPNMHDR) lParam)->code == NM_CLICK)
+ {
+ unsigned int nParts, nPanel;
+ NMMOUSE *nm = (NMMOUSE *) lParam;
+ HMENU hMenu;
+ RECT rc;
+ POINT pt;
+
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ nParts = SendMessage(cli.hwndStatus, SB_GETPARTS, 0, 0);
+ if (nm->dwItemSpec == 0xFFFFFFFE) {
+ nPanel = nParts - 1;
+ SendMessage(cli.hwndStatus, SB_GETRECT, nPanel, (LPARAM) & rc);
+ if (nm->pt.x < rc.left)
+ return FALSE;
+ }
+ else nPanel = nm->dwItemSpec;
+
+ if (nParts > 1)
+ hMenu = GetSubMenu(hMenu, nPanel);
+ SendMessage(cli.hwndStatus, SB_GETRECT, nPanel, (LPARAM) & rc);
+ pt.x = rc.left;
+ pt.y = rc.top;
+ ClientToScreen(cli.hwndStatus, &pt);
+ TrackPopupMenu(hMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, NULL);
+ } }
+ return FALSE;
+
+ case WM_CONTEXTMENU:
+ {
+ RECT rc;
+ POINT pt;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ // x/y might be -1 if it was generated by a kb click
+ GetWindowRect(cli.hwndContactTree, &rc);
+ if (pt.x == -1 && pt.y == -1) {
+ // all this is done in screen-coords!
+ GetCursorPos(&pt);
+ // the mouse isnt near the window, so put it in the middle of the window
+ if (!PtInRect(&rc, pt)) {
+ pt.x = rc.left + (rc.right - rc.left) / 2;
+ pt.y = rc.top + (rc.bottom - rc.top) / 2;
+ }
+ }
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ hMenu = GetSubMenu(LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 1);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMenu, 0);
+ CheckMenuItem(hMenu, POPUP_HIDEOFFLINE,
+ DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_HIDEOFFLINEROOT, SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_HIDEEMPTYGROUPS,
+ GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_DISABLEGROUPS, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS ? MF_UNCHECKED : MF_CHECKED);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ GetWindowRect(cli.hwndStatus, &rc);
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ if (DBGetContactSettingByte(NULL, "CLUI", "SBarRightClk", 0))
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ else
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ return 0;
+ } }
+ break;
+
+ case WM_MEASUREITEM:
+ if (((LPMEASUREITEMSTRUCT) lParam)->itemData == MENU_MIRANDAMENU) {
+ ((LPMEASUREITEMSTRUCT) lParam)->itemWidth = g_IconWidth * 4 / 3;
+ ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = 0;
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+ if (dis->hwndItem == cli.hwndStatus) {
+ char *szProto = (char *) dis->itemData;
+ int status, x;
+ SIZE textSize;
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ SetBkMode(dis->hDC, TRANSPARENT);
+ x = dis->rcItem.left;
+ if (showOpts & 1) {
+ HICON hIcon;
+ hIcon = LoadSkinnedProtoIcon(szProto, status);
+ DrawIconEx(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - g_IconHeight) >> 1, hIcon,
+ g_IconWidth, g_IconHeight, 0, NULL, DI_NORMAL);
+ x += g_IconWidth + 2;
+ }
+ else
+ x += 2;
+ if (showOpts & 2) {
+ char szName[64];
+ szName[0] = 0;
+ if (CallProtoService(szProto, PS_GETNAME, sizeof(szName), (LPARAM) szName)) {
+ strcpy(szName, szProto);
+ } //if
+ if (lstrlenA(szName) < SIZEOF(szName) - 1)
+ lstrcatA(szName, " ");
+ GetTextExtentPoint32A(dis->hDC, szName, lstrlenA(szName), &textSize);
+ TextOutA(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - textSize.cy) >> 1, szName, lstrlenA(szName));
+ x += textSize.cx;
+ }
+ if (showOpts & 4) {
+ char *szStatus = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, 0);
+ if (!szStatus)
+ szStatus = "";
+ GetTextExtentPoint32A(dis->hDC, szStatus, lstrlenA(szStatus), &textSize);
+ TextOutA(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - textSize.cy) >> 1, szStatus, lstrlenA(szStatus));
+ }
+ }
+ else if (dis->CtlType == ODT_MENU) {
+ if (dis->itemData == MENU_MIRANDAMENU) {
+ HICON hIcon = ImageList_GetIcon(himlMirandaIcon, 0, ILD_NORMAL);
+ fnDrawMenuItem(dis, hIcon, NULL);
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ } }
+ return 0;
+
+ case WM_CLOSE:
+ if (DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT))
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ else
+ SendMessage(hwnd, WM_COMMAND, ID_ICQ_EXIT, 0);
+
+ return FALSE;
+ case WM_DESTROY:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ DBWriteContactSettingDword(NULL, "CList", "Height", (DWORD) (rc.bottom - rc.top));
+ DBWriteContactSettingDword(NULL, "CList", "x", (DWORD) rc.left);
+ DBWriteContactSettingDword(NULL, "CList", "y", (DWORD) rc.top);
+ }
+ DBWriteContactSettingDword(NULL, "CList", "Width", (DWORD) (rc.right - rc.left));
+ }
+
+ if ( cli.hwndStatus ) {
+ DestroyWindow( cli.hwndStatus );
+ cli.hwndStatus = NULL;
+ }
+
+ // Disconnect all protocols
+ DisconnectAll();
+
+ ShowWindow(hwnd, SW_HIDE);
+ DestroyWindow(cli.hwndContactTree);
+ ImageList_Destroy(himlMirandaIcon);
+ FreeLibrary(hUserDll);
+ PostQuitMessage(0);
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ return TRUE;
+}
diff --git a/miranda-wine/src/modules/clist/cluiservices.c b/miranda-wine/src/modules/clist/cluiservices.c new file mode 100644 index 0000000..0b01b3e --- /dev/null +++ b/miranda-wine/src/modules/clist/cluiservices.c @@ -0,0 +1,239 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+static int GetHwnd(WPARAM wParam, LPARAM lParam)
+{
+ return (int)cli.hwndContactList;
+}
+
+static int GetHwndTree(WPARAM wParam,LPARAM lParam)
+{
+ return (int)cli.hwndContactTree;
+}
+
+static int CluiProtocolStatusChanged(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnCluiProtocolStatusChanged( wParam, (const char*)lParam );
+ return 0;
+}
+
+int SortList(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int GroupAdded(WPARAM wParam, LPARAM lParam)
+{
+ //CLC does this automatically unless it's a new group
+ if (lParam) {
+ HANDLE hItem;
+ TCHAR szFocusClass[64];
+ HWND hwndFocus = GetFocus();
+
+ GetClassName(hwndFocus, szFocusClass, SIZEOF(szFocusClass));
+ if (!lstrcmp(szFocusClass, CLISTCONTROL_CLASS)) {
+ hItem = (HANDLE) SendMessage(hwndFocus, CLM_FINDGROUP, wParam, 0);
+ if (hItem)
+ SendMessage(hwndFocus, CLM_EDITLABEL, (WPARAM) hItem, 0);
+ }
+ }
+ return 0;
+}
+
+static int ContactSetIcon(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ListBeginRebuild(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int ListEndRebuild(WPARAM wParam, LPARAM lParam)
+{
+ int rebuild = 0;
+ //CLC does this automatically, but we need to force it if hideoffline or hideempty has changed
+ if ((DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) == 0) != ((GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEOFFLINE) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT))
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) | CLS_HIDEOFFLINE);
+ else
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & ~CLS_HIDEOFFLINE);
+ rebuild = 1;
+ }
+ if ((DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) == 0) != ((GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT))
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) | CLS_HIDEEMPTYGROUPS);
+ else
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ rebuild = 1;
+ }
+ if ((DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) == 0) != ((GetWindowLong(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) | CLS_USEGROUPS);
+ else
+ SetWindowLong(cli.hwndContactTree, GWL_STYLE, GetWindowLong(cli.hwndContactTree, GWL_STYLE) & ~CLS_USEGROUPS);
+ rebuild = 1;
+ }
+ if (rebuild)
+ SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0);
+ return 0;
+}
+
+static int ContactRenamed(WPARAM wParam, LPARAM lParam)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static int GetCaps(WPARAM wParam, LPARAM lParam)
+{
+ switch (wParam) {
+ case CLUICAPS_FLAGS1:
+ return CLUIF_HIDEEMPTYGROUPS | CLUIF_DISABLEGROUPS | CLUIF_HASONTOPOPTION | CLUIF_HASAUTOHIDEOPTION;
+ }
+ return 0;
+}
+
+int LoadCluiServices(void)
+{
+ CreateServiceFunction(MS_CLUI_GETHWND, GetHwnd);
+ CreateServiceFunction(MS_CLUI_GETHWNDTREE,GetHwndTree);
+ CreateServiceFunction(MS_CLUI_PROTOCOLSTATUSCHANGED, CluiProtocolStatusChanged);
+ CreateServiceFunction(MS_CLUI_GROUPADDED, GroupAdded);
+ CreateServiceFunction(MS_CLUI_CONTACTSETICON, ContactSetIcon);
+ CreateServiceFunction(MS_CLUI_CONTACTADDED, ContactAdded);
+ CreateServiceFunction(MS_CLUI_CONTACTDELETED, ContactDeleted);
+ CreateServiceFunction(MS_CLUI_CONTACTRENAMED, ContactRenamed);
+ CreateServiceFunction(MS_CLUI_LISTBEGINREBUILD, ListBeginRebuild);
+ CreateServiceFunction(MS_CLUI_LISTENDREBUILD, ListEndRebuild);
+ CreateServiceFunction(MS_CLUI_SORTLIST, SortList);
+ CreateServiceFunction(MS_CLUI_GETCAPS, GetCaps);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default protocol status notification handler
+
+int fnCluiProtocolStatusChanged(int parStatus, const char* szProto)
+{
+ int protoCount, i;
+ PROTOCOLDESCRIPTOR **proto;
+ int *partWidths, partCount;
+ int borders[3];
+ int status;
+ int flags = 0;
+
+ SendMessage(cli.hwndStatus, SB_GETBORDERS, 0, (LPARAM) & borders);
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM) & protoCount, (LPARAM) & proto);
+ if (protoCount == 0)
+ return 0;
+ partWidths = (int *) mir_alloc(protoCount * sizeof(int));
+ if (DBGetContactSettingByte(NULL, "CLUI", "EqualSections", 0)) {
+ RECT rc;
+ int part;
+ GetClientRect(cli.hwndStatus, &rc);
+ rc.right -= borders[0] * 2 + (DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1) ? GetSystemMetrics(SM_CXVSCROLL) : 0);
+ for (partCount = 0, i = protoCount - 1; i >= 0; i--)
+ if (proto[i]->type == PROTOTYPE_PROTOCOL && CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) != 0)
+ partCount++;
+ for (part = 0, i = 0; i < protoCount; i++) {
+ if (proto[i]->type != PROTOTYPE_PROTOCOL)
+ continue;
+ partWidths[part] = (part + 1) * rc.right / partCount - (borders[2] >> 1);
+ part++;
+ }
+ }
+ else {
+ char *modeDescr;
+ HDC hdc;
+ SIZE textSize;
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+ int x;
+ char szName[32];
+
+ hdc = GetDC(NULL);
+ SelectObject(hdc, (HFONT) SendMessage(cli.hwndStatus, WM_GETFONT, 0, 0));
+ for (partCount = 0, i = protoCount - 1; i >= 0; i--) { //count down since built in ones tend to go at the end
+ if (proto[i]->type != PROTOTYPE_PROTOCOL || CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ continue;
+ x = 2;
+ if (showOpts & 1)
+ x += g_IconWidth;
+ if (showOpts & 2) {
+ CallProtoService(proto[i]->szName, PS_GETNAME, SIZEOF(szName), (LPARAM) szName);
+ if (showOpts & 4 && lstrlenA(szName) < SIZEOF(szName) - 1)
+ lstrcatA(szName, " ");
+ GetTextExtentPoint32A(hdc, szName, lstrlenA(szName), &textSize);
+ x += textSize.cx;
+ x += GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ if (showOpts & 4) {
+ modeDescr = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, CallProtoService(proto[i]->szName, PS_GETSTATUS, 0, 0), 0);
+ GetTextExtentPoint32A(hdc, modeDescr, lstrlenA(modeDescr), &textSize);
+ x += textSize.cx;
+ x += GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ partWidths[partCount] = (partCount ? partWidths[partCount - 1] : 0) + x + 2;
+ partCount++;
+ }
+ ReleaseDC(NULL, hdc);
+ }
+ if (partCount == 0) {
+ mir_free(partWidths);
+ return 0;
+ }
+ partWidths[partCount - 1] = -1;
+ SendMessage(cli.hwndStatus, SB_SETMINHEIGHT, g_IconHeight, 0);
+ SendMessage(cli.hwndStatus, SB_SETPARTS, partCount, (LPARAM) partWidths);
+ mir_free(partWidths);
+ flags = SBT_OWNERDRAW;
+ if (DBGetContactSettingByte(NULL, "CLUI", "SBarBevel", 1) == 0)
+ flags |= SBT_NOBORDERS;
+ for (partCount = 0, i = protoCount - 1; i >= 0; i--) { //count down since built in ones tend to go at the end
+ // okay, so it was a bug ;)
+ if (proto[i]->type != PROTOTYPE_PROTOCOL || (CallProtoService(proto[i]->szName, PS_GETCAPS, PFLAGNUM_2, 0) == 0))
+ continue;
+ status = CallProtoService(proto[i]->szName, PS_GETSTATUS, 0, 0);
+ SendMessage(cli.hwndStatus, SB_SETTEXT, partCount | flags, (LPARAM) proto[i]->szName);
+ partCount++;
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/contact.c b/miranda-wine/src/modules/clist/contact.c new file mode 100644 index 0000000..be14573 --- /dev/null +++ b/miranda-wine/src/modules/clist/contact.c @@ -0,0 +1,185 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+extern HANDLE hContactIconChangedEvent;
+
+int sortByStatus;
+int sortByProto;
+struct {
+ int status,order;
+} statusModeOrder[]={
+ {ID_STATUS_OFFLINE,500},
+ {ID_STATUS_ONLINE,0},
+ {ID_STATUS_AWAY,200},
+ {ID_STATUS_DND,400},
+ {ID_STATUS_NA,450},
+ {ID_STATUS_OCCUPIED,100},
+ {ID_STATUS_FREECHAT,50},
+ {ID_STATUS_INVISIBLE,20},
+ {ID_STATUS_ONTHEPHONE,150},
+ {ID_STATUS_OUTTOLUNCH,425}};
+
+static int GetContactStatus(HANDLE hContact)
+{
+ char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL)
+ return ID_STATUS_OFFLINE;
+ return DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+}
+
+void fnChangeContactIcon(HANDLE hContact, int iIcon, int add)
+{
+ CallService(add ? MS_CLUI_CONTACTADDED : MS_CLUI_CONTACTSETICON, (WPARAM) hContact, iIcon);
+ NotifyEventHooks(hContactIconChangedEvent, (WPARAM) hContact, iIcon);
+}
+
+int GetStatusModeOrdering(int statusMode)
+{
+ int i;
+ for (i = 0; i < SIZEOF(statusModeOrder); i++)
+ if (statusModeOrder[i].status == statusMode)
+ return statusModeOrder[i].order;
+ return 1000;
+}
+
+void fnLoadContactTree(void)
+{
+ HANDLE hContact;
+ int i, status, hideOffline;
+
+ CallService(MS_CLUI_LISTBEGINREBUILD, 0, 0);
+ for (i = 1;; i++) {
+ if ( cli.pfnGetGroupName(i, NULL) == NULL)
+ break;
+ CallService(MS_CLUI_GROUPADDED, i, 0);
+ }
+
+ hideOffline = DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact != NULL) {
+ status = GetContactStatus(hContact);
+ if ((!hideOffline || status != ID_STATUS_OFFLINE) && !DBGetContactSettingByte(hContact, "CList", "Hidden", 0))
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0), status, hContact), 1);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ sortByStatus = DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT);
+ sortByProto = DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT);
+ CallService(MS_CLUI_SORTLIST, 0, 0);
+ CallService(MS_CLUI_LISTENDREBUILD, 0, 0);
+}
+
+int fnCompareContacts(const struct ClcContact* c1, const struct ClcContact* c2)
+{
+ HANDLE a = c1->hContact, b = c2->hContact;
+ TCHAR namea[128], *nameb;
+ int statusa, statusb;
+ int rc;
+
+ statusa = DBGetContactSettingWord((HANDLE) a, c1->proto, "Status", ID_STATUS_OFFLINE);
+ statusb = DBGetContactSettingWord((HANDLE) b, c2->proto, "Status", ID_STATUS_OFFLINE);
+
+ if (sortByProto) {
+ /* deal with statuses, online contacts have to go above offline */
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ /* both are online, now check protocols */
+ rc = lstrcmpA( c1->proto, c2->proto);
+ if (rc != 0 && (c1->proto != NULL && c2->proto != NULL))
+ return rc;
+ /* protocols are the same, order by display name */
+ }
+
+ if (sortByStatus) {
+ int ordera, orderb;
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ }
+ else {
+ //one is offline: offline goes below online
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ }
+
+ nameb = cli.pfnGetContactDisplayName( a, 0);
+ _tcsncpy(namea, nameb, SIZEOF(namea));
+ namea[ SIZEOF(namea)-1 ] = 0;
+ nameb = cli.pfnGetContactDisplayName( b, 0);
+
+ //otherwise just compare names
+ return _tcsicmp(namea, nameb);
+}
+
+static int resortTimerId = 0;
+static VOID CALLBACK SortContactsTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ KillTimer(NULL, resortTimerId);
+ resortTimerId = 0;
+ CallService(MS_CLUI_SORTLIST, 0, 0);
+}
+
+void fnSortContacts(void)
+{
+ //avoid doing lots of resorts in quick succession
+ sortByStatus = DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT);
+ sortByProto = DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT);
+ if (resortTimerId)
+ KillTimer(NULL, resortTimerId);
+ // setting this to a higher delay causes shutdown waits.
+ resortTimerId = SetTimer(NULL, 0, 500, SortContactsTimer);
+}
+
+int ContactChangeGroup(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ if ((HANDLE) lParam == NULL)
+ DBDeleteContactSetting((HANDLE) wParam, "CList", "Group");
+ else
+ DBWriteContactSettingTString((HANDLE) wParam, "CList", "Group", cli.pfnGetGroupName(lParam, NULL));
+ CallService(MS_CLUI_CONTACTADDED, wParam,
+ cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), GetContactStatus((HANDLE) wParam), (HANDLE) wParam));
+ return 0;
+}
+
+int fnSetHideOffline(WPARAM wParam, LPARAM lParam)
+{
+ switch ((int) wParam) {
+ case 0:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", 0);
+ break;
+ case 1:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", 1);
+ break;
+ case -1:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline",
+ (BYTE) ! DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT));
+ break;
+ }
+ cli.pfnLoadContactTree();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/groups.c b/miranda-wine/src/modules/clist/groups.c new file mode 100644 index 0000000..3c48e1e --- /dev/null +++ b/miranda-wine/src/modules/clist/groups.c @@ -0,0 +1,514 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+static int RenameGroup(WPARAM wParam, LPARAM lParam);
+static int MoveGroupBefore(WPARAM wParam, LPARAM lParam);
+
+static int CountGroups(void)
+{
+ DBVARIANT dbv;
+ int i;
+ char str[33];
+
+ for (i = 0;; i++) {
+ itoa(i, str, 10);
+ if (DBGetContactSetting(NULL, "CListGroups", str, &dbv))
+ break;
+ DBFreeVariant(&dbv);
+ }
+ return i;
+}
+
+static int GroupNameExists(const TCHAR *name, int skipGroup)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int i;
+
+ for (i = 0;; i++) {
+ if (i == skipGroup)
+ continue;
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (!_tcscmp(dbv.ptszVal + 1, name)) {
+ DBFreeVariant(&dbv);
+ return 1;
+ }
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+static int CreateGroup(WPARAM wParam, LPARAM lParam)
+{
+ int newId = CountGroups();
+ TCHAR newBaseName[127], newName[128];
+ char str[33];
+ int i;
+ DBVARIANT dbv;
+
+ if (wParam) {
+ itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 0;
+
+ mir_sntprintf( newBaseName, SIZEOF(newBaseName), _T("%s\\%s"), dbv.ptszVal + 1, TranslateT("New Group"));
+ mir_free(dbv.pszVal);
+ }
+ else lstrcpyn( newBaseName, TranslateT( "New Group" ), SIZEOF( newBaseName ));
+
+ itoa(newId, str, 10);
+ i = 1;
+ lstrcpyn( newName + 1, newBaseName, SIZEOF(newName) - 1);
+ while (GroupNameExists(newName + 1, -1))
+ mir_sntprintf( newName + 1, SIZEOF(newName) - 1, _T("%s (%d)"), newBaseName, ++i );
+
+ newName[0] = 1 | GROUPF_EXPANDED; //1 is required so we never get '\0'
+ DBWriteContactSettingTString(NULL, "CListGroups", str, newName);
+ CallService(MS_CLUI_GROUPADDED, newId + 1, 1);
+ return newId + 1;
+}
+
+static int GetGroupName2(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ static char name[128];
+
+ itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSetting(NULL, "CListGroups", idstr, &dbv))
+ return (int) (char *) NULL;
+ lstrcpynA(name, dbv.pszVal + 1, SIZEOF(name));
+ if ((DWORD *) lParam != NULL)
+ *(DWORD *) lParam = dbv.pszVal[0];
+ DBFreeVariant(&dbv);
+ return (int) name;
+}
+
+TCHAR* fnGetGroupName( int idx, DWORD* pdwFlags )
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ static TCHAR name[128];
+
+ itoa( idx-1, idstr, 10);
+ if (DBGetContactSettingTString( NULL, "CListGroups", idstr, &dbv ))
+ return NULL;
+
+ lstrcpyn( name, dbv.ptszVal + 1, SIZEOF( name ));
+ if ( pdwFlags != NULL )
+ *pdwFlags = dbv.ptszVal[0];
+ DBFreeVariant( &dbv );
+ return name;
+}
+
+static int GetGroupName(WPARAM wParam, LPARAM lParam)
+{
+ int ret;
+ ret = GetGroupName2(wParam, lParam);
+ if ((int *) lParam)
+ *(int *) lParam = 0 != (*(int *) lParam & GROUPF_EXPANDED);
+ return ret;
+}
+
+static int DeleteGroup(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ char str[33];
+ DBVARIANT dbv;
+ HANDLE hContact;
+ TCHAR name[256], szNewParent[256], *pszLastBackslash;
+
+ //get the name
+ itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 1;
+ if (DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT))
+ if (MessageBox((HWND)CallService(MS_CLUI_GETHWND, 0, 0), TranslateT("Are you sure you want to delete this group? This operation can not be undone."), TranslateT("Delete Group"), MB_YESNO|MB_ICONQUESTION)==IDNO)
+ return 1;
+ lstrcpyn(name, dbv.ptszVal + 1, SIZEOF(name));
+ DBFreeVariant(&dbv);
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+ //must remove setting from all child contacts too
+ //children are demoted to the next group up, not deleted.
+ lstrcpy(szNewParent, name);
+ pszLastBackslash = _tcsrchr(szNewParent, '\\');
+ if (pszLastBackslash)
+ pszLastBackslash[0] = '\0';
+ else
+ szNewParent[0] = '\0';
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ if (DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ continue;
+ if (_tcscmp(dbv.ptszVal, name)) {
+ DBFreeVariant(&dbv);
+ continue;
+ }
+ DBFreeVariant(&dbv);
+ if (szNewParent[0])
+ DBWriteContactSettingTString(hContact, "CList", "Group", szNewParent);
+ else
+ DBDeleteContactSetting(hContact, "CList", "Group");
+ } while ((hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)) != NULL);
+ //shuffle list of groups up to fill gap
+ for (i = wParam - 1;; i++) {
+ itoa(i + 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv))
+ break;
+ itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ itoa(i, str, 10);
+ DBDeleteContactSetting(NULL, "CListGroups", str);
+ //rename subgroups
+ {
+ TCHAR szNewName[256];
+ int len;
+
+ len = lstrlen(name);
+ for (i = 0;; i++) {
+ itoa(i, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ break;
+ if (!_tcsncmp(dbv.ptszVal + 1, name, len) && dbv.pszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) {
+ if (szNewParent[0])
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s\\%s"), szNewParent, dbv.ptszVal + len + 2);
+ else
+ lstrcpyn(szNewName, dbv.ptszVal + len + 2, SIZEOF(szNewName));
+ cli.pfnRenameGroup(i + 1, szNewName);
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ cli.pfnLoadContactTree();
+ return 0;
+}
+
+static int RenameGroupWithMove(int groupId, const TCHAR *szName, int move)
+{
+ char idstr[33];
+ TCHAR str[256], oldName[256];
+ DBVARIANT dbv;
+ HANDLE hContact;
+
+ if (GroupNameExists(szName, groupId)) {
+ MessageBox(NULL, TranslateT("You already have a group with that name. Please enter a unique name for the group."), TranslateT("Rename Group"), MB_OK);
+ return 1;
+ }
+
+ //do the change
+ itoa(groupId, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ str[0] = dbv.pszVal[0];
+ lstrcpyn(oldName, dbv.ptszVal + 1, SIZEOF(oldName));
+ DBFreeVariant(&dbv);
+ lstrcpyn(str + 1, szName, SIZEOF(str) - 1);
+ DBWriteContactSettingTString(NULL, "CListGroups", idstr, str);
+
+ //must rename setting in all child contacts too
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ ClcCacheEntryBase* cache = cli.pfnGetCacheEntry( hContact );
+ if ( !lstrcmp(cache->group, oldName)) {
+ DBWriteContactSettingTString(hContact, "CList", "Group", szName);
+ mir_free(cache->group);
+ cache->group = 0;
+ cli.pfnCheckCacheItem(cache);
+ }
+ }
+ while ((hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)) != NULL);
+
+ //rename subgroups
+ {
+ TCHAR szNewName[256];
+ int len, i;
+
+ len = lstrlen(oldName);
+ for (i = 0;; i++) {
+ if (i == groupId)
+ continue;
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if ( !_tcsncmp(dbv.ptszVal + 1, oldName, len) && dbv.ptszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) {
+ mir_sntprintf( szNewName, SIZEOF(szNewName), _T("%s\\%s"), szName, dbv.ptszVal + len + 2 );
+ RenameGroupWithMove(i, szNewName, 0); //luckily, child groups will never need reordering
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ //finally must make sure it's after any parent items
+ if (move) {
+ TCHAR *pszLastBackslash;
+ int i;
+
+ lstrcpyn(str, szName, SIZEOF(str));
+ pszLastBackslash = _tcsrchr(str, '\\');
+ if (pszLastBackslash == NULL)
+ return 0;
+ *pszLastBackslash = '\0';
+ for (i = 0;; i++) {
+ itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (!lstrcmp(dbv.ptszVal + 1, str)) {
+ if (i < groupId)
+ break; //is OK
+ MoveGroupBefore(groupId + 1, i + 2);
+ break;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+}
+
+int fnRenameGroup( int groupID, TCHAR* newName )
+{
+ return -1 != RenameGroupWithMove( groupID-1, newName, 1);
+}
+
+static int RenameGroup(WPARAM wParam, LPARAM lParam)
+{
+ #if defined( _UNICODE )
+ WCHAR* temp = a2u(( char* )lParam );
+ int result = ( -1 != RenameGroupWithMove(wParam - 1, temp, 1));
+ mir_free( temp );
+ return result;
+ #else
+ return -1 != RenameGroupWithMove(wParam - 1, (TCHAR*) lParam, 1);
+ #endif
+}
+
+static int SetGroupExpandedState(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+
+ itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ if (lParam)
+ dbv.pszVal[0] |= GROUPF_EXPANDED;
+ else
+ dbv.pszVal[0] = dbv.pszVal[0] & ~GROUPF_EXPANDED;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", idstr, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ return 0;
+}
+
+static int SetGroupFlags(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int flags, oldval, newval;
+
+ itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ flags = LOWORD(lParam) & HIWORD(lParam);
+ oldval = dbv.pszVal[0];
+ newval = dbv.pszVal[0] = (dbv.pszVal[0] & ~HIWORD(lParam)) | flags;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", idstr, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if ((oldval & GROUPF_HIDEOFFLINE) != (newval & GROUPF_HIDEOFFLINE))
+ cli.pfnLoadContactTree();
+ return 0;
+}
+
+static int MoveGroupBefore(WPARAM wParam, LPARAM lParam)
+{
+ int i, shuffleFrom, shuffleTo, shuffleDir;
+ char str[33];
+ TCHAR *szMoveName;
+ DBVARIANT dbv;
+
+ if (wParam == 0 || (LPARAM) wParam == lParam)
+ return 0;
+ itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 0;
+ szMoveName = dbv.ptszVal;
+ //shuffle list of groups up to fill gap
+ if (lParam == 0) {
+ shuffleFrom = wParam - 1;
+ shuffleTo = -1;
+ shuffleDir = -1;
+ }
+ else {
+ if ((LPARAM) wParam < lParam) {
+ shuffleFrom = wParam - 1;
+ shuffleTo = lParam - 2;
+ shuffleDir = -1;
+ }
+ else {
+ shuffleFrom = wParam - 1;
+ shuffleTo = lParam - 1;
+ shuffleDir = 1;
+ }
+ }
+ if (shuffleDir == -1) {
+ for (i = shuffleFrom; i != shuffleTo; i++) {
+ itoa(i + 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv)) {
+ shuffleTo = i;
+ break;
+ }
+ itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ else {
+ for (i = shuffleFrom; i != shuffleTo; i--) {
+ itoa(i - 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv)) {
+ mir_free(szMoveName);
+ return 1;
+ } //never happens
+ itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ itoa(shuffleTo, str, 10);
+ DBWriteContactSettingTString(NULL, "CListGroups", str, szMoveName);
+ mir_free(szMoveName);
+ return shuffleTo + 1;
+}
+
+static int BuildGroupMenu(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int groupId;
+ HMENU hRootMenu, hThisMenu;
+ int nextMenuId = 100;
+ TCHAR *pBackslash, *pNextField, szThisField[128], szThisMenuItem[128];
+ int menuId, compareResult, menuItemCount;
+ MENUITEMINFO mii = { 0 };
+
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", "0", &dbv))
+ return (int) (HMENU) NULL;
+ DBFreeVariant(&dbv);
+ hRootMenu = CreateMenu();
+ for (groupId = 0;; groupId++) {
+ itoa(groupId, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+
+ pNextField = dbv.ptszVal + 1;
+ hThisMenu = hRootMenu;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ do {
+ pBackslash = _tcschr(pNextField, '\\');
+ if (pBackslash == NULL) {
+ lstrcpyn(szThisField, pNextField, SIZEOF(szThisField));
+ pNextField = NULL;
+ }
+ else {
+ lstrcpyn(szThisField, pNextField, min( SIZEOF(szThisField), pBackslash - pNextField + 1));
+ pNextField = pBackslash + 1;
+ }
+ compareResult = 1;
+ menuItemCount = GetMenuItemCount(hThisMenu);
+ for (menuId = 0; menuId < menuItemCount; menuId++) {
+ mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA;
+ mii.cch = SIZEOF(szThisMenuItem);
+ mii.dwTypeData = szThisMenuItem;
+ GetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ compareResult = lstrcmp(szThisField, szThisMenuItem);
+ if (compareResult == 0) {
+ if (pNextField == NULL) {
+ mii.fMask = MIIM_DATA;
+ mii.dwItemData = groupId + 1;
+ SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ }
+ else {
+ if (mii.hSubMenu == NULL) {
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = CreateMenu();
+ SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
+ //dwItemData doesn't change
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = TranslateT("This group");
+ mii.wID = nextMenuId++;
+ InsertMenuItem(mii.hSubMenu, 0, TRUE, &mii);
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(mii.hSubMenu, 1, TRUE, &mii);
+ }
+ hThisMenu = mii.hSubMenu;
+ }
+ break;
+ }
+ if ((int) mii.dwItemData - 1 > groupId)
+ break;
+ }
+ if (compareResult) {
+ mii.fMask = MIIM_TYPE | MIIM_ID;
+ mii.wID = nextMenuId++;
+ mii.dwTypeData = szThisField;
+ mii.fType = MFT_STRING;
+ if (pNextField) {
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = CreateMenu();
+ }
+ else {
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = groupId + 1;
+ }
+ InsertMenuItem(hThisMenu, menuId, TRUE, &mii);
+ if (pNextField) {
+ hThisMenu = mii.hSubMenu;
+ }
+ }
+ } while (pNextField);
+
+ DBFreeVariant(&dbv);
+ }
+ return (int) hRootMenu;
+}
+
+int InitGroupServices(void)
+{
+ CreateServiceFunction(MS_CLIST_GROUPCREATE, CreateGroup);
+ CreateServiceFunction(MS_CLIST_GROUPDELETE, DeleteGroup);
+ CreateServiceFunction(MS_CLIST_GROUPRENAME, RenameGroup);
+ CreateServiceFunction(MS_CLIST_GROUPGETNAME, GetGroupName);
+ CreateServiceFunction(MS_CLIST_GROUPGETNAME2, GetGroupName2);
+ CreateServiceFunction(MS_CLIST_GROUPSETEXPANDED, SetGroupExpandedState);
+ CreateServiceFunction(MS_CLIST_GROUPSETFLAGS, SetGroupFlags);
+ CreateServiceFunction(MS_CLIST_GROUPMOVEBEFORE, MoveGroupBefore);
+ CreateServiceFunction(MS_CLIST_GROUPBUILDMENU, BuildGroupMenu);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/clist/keyboard.c b/miranda-wine/src/modules/clist/keyboard.c new file mode 100644 index 0000000..d64c0b9 --- /dev/null +++ b/miranda-wine/src/modules/clist/keyboard.c @@ -0,0 +1,135 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "clc.h"
+
+static ATOM aHide = 0;
+static ATOM aRead = 0;
+static ATOM aSearch = 0;
+static ATOM aOpts = 0;
+
+static void WordToModAndVk(WORD w, UINT * mod, UINT * vk)
+{
+ *mod = 0;
+ if (HIBYTE(w) & HOTKEYF_CONTROL)
+ *mod |= MOD_CONTROL;
+ if (HIBYTE(w) & HOTKEYF_SHIFT)
+ *mod |= MOD_SHIFT;
+ if (HIBYTE(w) & HOTKEYF_ALT)
+ *mod |= MOD_ALT;
+ if (HIBYTE(w) & HOTKEYF_EXT)
+ *mod |= MOD_WIN;
+ *vk = LOBYTE(w);
+}
+
+int fnHotKeysRegister(HWND hwnd)
+{
+ UINT mod, vk;
+
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnShowHide", 0)) {
+ if (!aHide)
+ aHide = GlobalAddAtomA("HKEnShowHide");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKShowHide", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aHide, mod, vk);
+ }
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnReadMsg", 0)) {
+ if (!aRead)
+ aRead = GlobalAddAtomA("HKEnReadMsg");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKReadMsg", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aRead, mod, vk);
+ }
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnNetSearch", 0)) {
+ if (!aSearch)
+ aSearch = GlobalAddAtomA("HKEnNetSearch");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKNetSearch", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aSearch, mod, vk);
+ }
+ if (DBGetContactSettingByte(NULL, "CList", "HKEnShowOptions", 0)) {
+ if (!aOpts)
+ aOpts = GlobalAddAtomA("HKEnShowOptions");
+ WordToModAndVk((WORD) DBGetContactSettingWord(NULL, "CList", "HKShowOptions", 0), &mod, &vk);
+ RegisterHotKey(hwnd, aOpts, mod, vk);
+ }
+ return 0;
+}
+
+void fnHotKeysUnregister(HWND hwnd)
+{
+ if (aHide) {
+ UnregisterHotKey(hwnd, aHide);
+ GlobalDeleteAtom(aHide);
+ }
+ if (aRead) {
+ UnregisterHotKey(hwnd, aRead);
+ GlobalDeleteAtom(aRead);
+ }
+ if (aSearch) {
+ UnregisterHotKey(hwnd, aSearch);
+ GlobalDeleteAtom(aSearch);
+ }
+ if (aOpts) {
+ UnregisterHotKey(hwnd, aOpts);
+ GlobalDeleteAtom(aOpts);
+ }
+}
+
+int fnHotKeysProcess(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == aHide)
+ cli.pfnShowHide(0, 0);
+ else if (wParam == aSearch) {
+ DBVARIANT dbv;
+ if (!DBGetContactSetting(NULL, "CList", "SearchUrl", &dbv)) {
+ CallService(MS_UTILS_OPENURL, DBGetContactSettingByte(NULL, "CList", "HKSearchNewWnd", 0), (LPARAM) dbv.pszVal);
+ DBFreeVariant( &dbv );
+ }
+ }
+ else if (wParam == aRead) {
+ if (cli.pfnEventsProcessTrayDoubleClick() == 0)
+ return TRUE;
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else if (wParam == aOpts) {
+ CallService("Options/OptionsCommand", 0, 0);
+ }
+ return TRUE;
+}
+
+int fnHotkeysProcessMessage(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *) wParam;
+ switch (msg->message) {
+ case WM_CREATE:
+ cli.pfnHotKeysRegister(msg->hwnd);
+ break;
+ case WM_HOTKEY:
+ *((LRESULT *) lParam) = cli.pfnHotKeysProcess(msg->hwnd, msg->wParam, msg->lParam);
+ return TRUE;
+ case WM_DESTROY:
+ cli.pfnHotKeysUnregister(msg->hwnd);
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/contacts/contacts.c b/miranda-wine/src/modules/contacts/contacts.c new file mode 100644 index 0000000..bd703a0 --- /dev/null +++ b/miranda-wine/src/modules/contacts/contacts.c @@ -0,0 +1,478 @@ +/*
+Miranda IM
+
+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 "commonheaders.h"
+
+#define NAMEORDERCOUNT 8
+static TCHAR* nameOrderDescr[ NAMEORDERCOUNT ] =
+{
+ _T( "My custom name (not moveable)" ),
+ _T( "Nick" ),
+ _T( "FirstName" ),
+ _T( "E-mail" ),
+ _T( "LastName" ),
+ _T( "Username" ),
+ _T( "FirstName LastName" ),
+ _T( "'(Unknown Contact)' (not moveable)" )
+};
+
+BYTE nameOrder[NAMEORDERCOUNT];
+
+static int GetDatabaseString( CONTACTINFO *ci, const char* setting, DBVARIANT* dbv )
+{
+ if ( ci->dwFlag & CNF_UNICODE )
+ return DBGetContactSettingWString(ci->hContact,ci->szProto,setting,dbv);
+
+ return DBGetContactSetting(ci->hContact,ci->szProto,setting,dbv);
+}
+
+static int ProcessDatabaseValueDefault(CONTACTINFO *ci, const char* setting)
+{
+ DBVARIANT dbv;
+ if ( GetDatabaseString( ci, setting, &dbv ))
+ return 1;
+
+ switch (dbv.type) {
+ case DBVT_ASCIIZ:
+ case DBVT_WCHAR:
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ case DBVT_BYTE:
+ ci->type = CNFT_BYTE;
+ ci->bVal = dbv.bVal;
+ return 0;
+ case DBVT_WORD:
+ ci->type = CNFT_WORD;
+ ci->wVal = dbv.wVal;
+ return 0;
+ case DBVT_DWORD:
+ ci->type = CNFT_DWORD;
+ ci->dVal = dbv.dVal;
+ return 0;
+ }
+
+ DBFreeVariant( &dbv );
+ return 1;
+}
+
+static int GetContactInfo(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ CONTACTINFO *ci = (CONTACTINFO*)lParam;
+
+ if (ci==NULL) return 1;
+ if (ci->szProto==NULL) ci->szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)ci->hContact,0);
+ if (ci->szProto==NULL) return 1;
+ ci->type = 0;
+ switch(ci->dwFlag & 0x7F) {
+ case CNF_FIRSTNAME: return ProcessDatabaseValueDefault( ci, "FirstName" );
+ case CNF_LASTNAME: return ProcessDatabaseValueDefault( ci, "LastName" );
+ case CNF_NICK: return ProcessDatabaseValueDefault( ci, "Nick" );
+ case CNF_EMAIL: return ProcessDatabaseValueDefault( ci, "e-mail" );
+ case CNF_CITY: return ProcessDatabaseValueDefault( ci, "City" );
+ case CNF_STATE: return ProcessDatabaseValueDefault( ci, "State" );
+ case CNF_PHONE: return ProcessDatabaseValueDefault( ci, "Phone" );
+ case CNF_HOMEPAGE: return ProcessDatabaseValueDefault( ci, "Homepage" );
+ case CNF_ABOUT: return ProcessDatabaseValueDefault( ci, "About" );
+ case CNF_AGE: return ProcessDatabaseValueDefault( ci, "Age" );
+ case CNF_GENDER: return ProcessDatabaseValueDefault( ci, "Gender" );
+ case CNF_FAX: return ProcessDatabaseValueDefault( ci, "Fax" );
+ case CNF_CELLULAR: return ProcessDatabaseValueDefault( ci, "Cellular" );
+ case CNF_BIRTHDAY: return ProcessDatabaseValueDefault( ci, "BirthDay" );
+ case CNF_BIRTHMONTH: return ProcessDatabaseValueDefault( ci, "BirthMonth" );
+ case CNF_BIRTHYEAR: return ProcessDatabaseValueDefault( ci, "BirthYear" );
+ case CNF_STREET: return ProcessDatabaseValueDefault( ci, "Street" );
+ case CNF_ZIP: return ProcessDatabaseValueDefault( ci, "ZIP" );
+ case CNF_LANGUAGE1: return ProcessDatabaseValueDefault( ci, "Language1" );
+ case CNF_LANGUAGE2: return ProcessDatabaseValueDefault( ci, "Language2" );
+ case CNF_LANGUAGE3: return ProcessDatabaseValueDefault( ci, "Language3" );
+ case CNF_CONAME: return ProcessDatabaseValueDefault( ci, "Company" );
+ case CNF_CODEPT: return ProcessDatabaseValueDefault( ci, "CompanyDepartment" );
+ case CNF_COPOSITION: return ProcessDatabaseValueDefault( ci, "CompanyPosition" );
+ case CNF_COSTREET: return ProcessDatabaseValueDefault( ci, "CompanyStreet" );
+ case CNF_COCITY: return ProcessDatabaseValueDefault( ci, "CompanyCity" );
+ case CNF_COSTATE: return ProcessDatabaseValueDefault( ci, "CompanyState" );
+ case CNF_COZIP: return ProcessDatabaseValueDefault( ci, "CompanyZIP" );
+ case CNF_COHOMEPAGE: return ProcessDatabaseValueDefault( ci, "CompanyHomepage" );
+
+ case CNF_CUSTOMNICK:
+ {
+ char* saveProto = ci->szProto; ci->szProto = "CList";
+ if ( ci->hContact != NULL && !ProcessDatabaseValueDefault( ci, "MyHandle" )) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ }
+ case CNF_COUNTRY:
+ {
+ int i,countryCount;
+ struct CountryListEntry *countries;
+ if (!DBGetContactSetting(ci->hContact,ci->szProto,"Country",&dbv)) {
+ CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&countryCount,(LPARAM)&countries);
+ for(i=0;i<countryCount;i++) {
+ if(countries[i].id!=dbv.wVal) continue;
+
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int cbLen = MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )countries[i].szName, -1, NULL, 0 );
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*(cbLen+1) );
+ if ( buf != NULL )
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )countries[i].szName, -1, buf, cbLen );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else ci->pszVal = ( TCHAR* )mir_strdup(countries[i].szName);
+
+ ci->type = CNFT_ASCIIZ;
+ DBFreeVariant(&dbv);
+ return 0;
+ }
+ DBFreeVariant(&dbv);
+ }
+ break;
+ }
+ case CNF_FIRSTLAST:
+ if( !GetDatabaseString( ci, "FirstName", &dbv )) {
+ DBVARIANT dbv2;
+ if(!GetDatabaseString(ci,"LastName",&dbv2)) {
+ ci->type = CNFT_ASCIIZ;
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int len = wcslen(dbv.pwszVal) + wcslen(dbv2.pwszVal) + 2;
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*len );
+ if ( buf != NULL )
+ wcscat( wcscat( wcscpy( buf, dbv.pwszVal ), L" " ), dbv2.pwszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else {
+ int len = strlen(dbv.pszVal) + strlen(dbv2.pszVal) + 2;
+ char* buf = ( char* )mir_alloc( len );
+ if ( buf != NULL )
+ strcat( strcat( strcpy( buf, dbv.pszVal ), " " ), dbv2.pszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ DBFreeVariant( &dbv );
+ DBFreeVariant( &dbv2 );
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+ break;
+
+ case CNF_UNIQUEID:
+ {
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((int)uid!=CALLSERVICE_NOTFOUND&&uid)
+ if (!ProcessDatabaseValueDefault(ci,uid))
+ return 0;
+
+ break;
+ }
+ case CNF_DISPLAYNC:
+ case CNF_DISPLAY:
+ {
+ int i;
+ for( i=0; i < NAMEORDERCOUNT; i++ ) {
+ switch(nameOrder[i]) {
+ case 0: // custom name
+ {
+ // make sure we aren't in CNF_DISPLAYNC mode
+ // don't get custom name for NULL contact
+ char* saveProto = ci->szProto; ci->szProto = "CList";
+ if (ci->hContact!=NULL && (ci->dwFlag&0x7F)==CNF_DISPLAY && !ProcessDatabaseValueDefault(ci,"MyHandle")) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ }
+ case 1:
+ if ( !ProcessDatabaseValueDefault( ci, "Nick" )) // nick
+ return 0;
+ break;
+ case 2:
+ if ( !ProcessDatabaseValueDefault( ci, "FirstName" )) // First Name
+ return 0;
+ break;
+ case 3:
+ if ( !ProcessDatabaseValueDefault( ci, "e-mail" )) // E-mail
+ return 0;
+ break;
+ case 4:
+ if ( !ProcessDatabaseValueDefault( ci, "LastName" )) // Last Name
+ return 0;
+ break;
+ case 5: // Unique id
+ {
+ // protocol must define a PFLAG_UNIQUEIDSETTING
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((int)uid!=CALLSERVICE_NOTFOUND&&uid) {
+ if (!GetDatabaseString(ci,uid,&dbv)) {
+ if ( dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD ) {
+ long value = (dbv.type == DBVT_BYTE) ? dbv.bVal:(dbv.type==DBVT_WORD ? dbv.wVal : dbv.dVal);
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ WCHAR buf[ 40 ];
+ _ltow( value, buf, 10 );
+ ci->pszVal = ( TCHAR* )mir_wstrdup( buf );
+ }
+ else {
+ char buf[ 40 ];
+ _ltoa( value, buf, 10 );
+ ci->pszVal = ( TCHAR* )mir_strdup(buf);
+ }
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ }
+ if (dbv.type==DBVT_ASCIIZ) {
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ } } }
+ break;
+ }
+ case 6: // first + last name
+ if(!GetDatabaseString(ci,"FirstName",&dbv)) {
+ DBVARIANT dbv2;
+ if(!GetDatabaseString(ci,"LastName",&dbv2)) {
+ ci->type = CNFT_ASCIIZ;
+
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int len = wcslen(dbv.pwszVal) + wcslen(dbv2.pwszVal) + 2;
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*len );
+ if ( buf != NULL )
+ wcscat( wcscat( wcscpy( buf, dbv.pwszVal ), L" " ), dbv2.pwszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else {
+ int len = strlen(dbv.pszVal) + strlen(dbv2.pszVal) + 2;
+ char* buf = ( char* )mir_alloc( len );
+ if ( buf != NULL )
+ strcat( strcat( strcpy( buf, dbv.pszVal ), " " ), dbv2.pszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+
+ DBFreeVariant( &dbv );
+ DBFreeVariant( &dbv2 );
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+ break;
+
+ case 7:
+ if ( ci->dwFlag & CNF_UNICODE )
+ ci->pszVal = ( TCHAR* )mir_wstrdup( TranslateW( L"'(Unknown Contact)'" ));
+ else
+ ci->pszVal = ( TCHAR* )mir_strdup( Translate("'(Unknown Contact)'"));
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ } } }
+ break;
+
+ case CNF_TIMEZONE: {
+ char str[80];
+ DBVARIANT dbv;
+
+ if (!DBGetContactSetting(ci->hContact,ci->szProto,"Timezone",&dbv)) {
+ sprintf(str,dbv.cVal?"GMT%+d:%02d":"GMT",-dbv.cVal/2,(dbv.cVal&1)*30);
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int cbLen = MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )str, -1, NULL, 0 );
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*(cbLen+1) );
+ if ( buf != NULL )
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )str, -1, buf, cbLen );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else ci->pszVal = ( TCHAR* )mir_strdup(str);
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ }
+ break;
+ }
+ case CNF_MYNOTES: {
+ char* saveProto = ci->szProto; ci->szProto = "UserInfo";
+ if (!ProcessDatabaseValueDefault(ci,"MyNotes")) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ } }
+
+ return 1;
+}
+
+struct ContactOptionsData {
+ int dragging;
+ HTREEITEM hDragItem;
+};
+
+static BOOL CALLBACK ContactOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{ struct ContactOptionsData *dat;
+
+ dat=(struct ContactOptionsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { TranslateDialogDefault(hwndDlg);
+ dat=(struct ContactOptionsData*)mir_alloc(sizeof(struct ContactOptionsData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->dragging=0;
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_NAMEORDER),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_NAMEORDER),GWL_STYLE)|TVS_NOHSCROLL);
+ { TVINSERTSTRUCT tvis;
+ int i;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT|TVIF_PARAM;
+ for(i=0; i < SIZEOF(nameOrderDescr); i++ ) {
+ tvis.item.lParam = nameOrder[i];
+ tvis.item.pszText = TranslateTS( nameOrderDescr[ nameOrder[i]] );
+ TreeView_InsertItem( GetDlgItem(hwndDlg,IDC_NAMEORDER), &tvis );
+ } }
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ { DBCONTACTWRITESETTING cws;
+ TVITEM tvi;
+ int i;
+ cws.szModule = "Contact";
+ cws.szSetting = "NameOrder";
+ cws.value.type = DBVT_BLOB;
+ cws.value.cpbVal = SIZEOF(nameOrderDescr);
+ cws.value.pbVal = nameOrder;
+ tvi.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_NAMEORDER));
+ i=0;
+ while( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE;
+ TreeView_GetItem( GetDlgItem(hwndDlg,IDC_NAMEORDER), &tvi );
+ nameOrder[i++] = (BYTE)tvi.lParam;
+ tvi.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg,IDC_NAMEORDER),tvi.hItem);
+ }
+ CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws);
+ CallService(MS_CLIST_INVALIDATEDISPLAYNAME,(WPARAM)INVALID_HANDLE_VALUE,0);
+ }
+ break;
+ case IDC_NAMEORDER:
+ if (((LPNMHDR)lParam)->code == TVN_BEGINDRAGA) {
+ LPNMTREEVIEWA notify = (LPNMTREEVIEWA)lParam;
+ if ( notify->itemNew.lParam==0 || notify->itemNew.lParam == SIZEOF(nameOrderDescr)-1 )
+ break;
+ SetCapture(hwndDlg);
+ dat->dragging=1;
+ dat->hDragItem=((LPNMTREEVIEW)lParam)->itemNew.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),dat->hDragItem);
+ }
+ break;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if(!dat->dragging) break;
+ { TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti.pt);
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ if(hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_NAMEORDER))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),hti.hItem,1);
+ }
+ else {
+ if(hti.flags&TVHT_ABOVE) SendDlgItemMessage(hwndDlg,IDC_NAMEORDER,WM_VSCROLL,MAKEWPARAM(SB_LINEUP,0),0);
+ if(hti.flags&TVHT_BELOW) SendDlgItemMessage(hwndDlg,IDC_NAMEORDER,WM_VSCROLL,MAKEWPARAM(SB_LINEDOWN,0),0);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),NULL,0);
+ }
+ }
+ break;
+ case WM_LBUTTONUP:
+ if(!dat->dragging) break;
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),NULL,0);
+ dat->dragging=0;
+ ReleaseCapture();
+ { TVHITTESTINFO hti;
+ TVITEM tvi;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti.pt);
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_NAMEORDER))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ if(dat->hDragItem==hti.hItem) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hti.hItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvi);
+ if(tvi.lParam == SIZEOF(nameOrderDescr)-1) break;
+ if(hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ TVINSERTSTRUCT tvis;
+ TCHAR name[128];
+ tvis.item.mask=TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT|TVIF_PARAM;
+ tvis.item.stateMask=0xFFFFFFFF;
+ tvis.item.pszText=name;
+ tvis.item.cchTextMax=SIZEOF(name);
+ tvis.item.hItem=dat->hDragItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvis.item);
+ TreeView_DeleteItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),dat->hDragItem);
+ tvis.hParent=NULL;
+ tvis.hInsertAfter=hti.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),TreeView_InsertItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvis));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case WM_DESTROY:
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int ContactOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -1000000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CONTACT);
+ odp.pszGroup = "Contact List";
+ odp.pszTitle = "Contact Display";
+ odp.pfnDlgProc = ContactOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+int LoadContactsModule(void) {
+ {
+ // Load the name order
+ BYTE i;
+ DBVARIANT dbv;
+
+ for(i=0; i<NAMEORDERCOUNT; i++)
+ nameOrder[i]=i;
+
+ if(!DBGetContactSetting(NULL,"Contact","NameOrder",&dbv))
+ {
+ CopyMemory(nameOrder,dbv.pbVal,dbv.cpbVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ CreateServiceFunction(MS_CONTACT_GETCONTACTINFO,GetContactInfo);
+ HookEvent(ME_OPT_INITIALISE,ContactOptInit);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/database/database.c b/miranda-wine/src/modules/database/database.c new file mode 100644 index 0000000..ead8acd --- /dev/null +++ b/miranda-wine/src/modules/database/database.c @@ -0,0 +1,377 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "profilemanager.h"
+
+
+// from the plugin loader, hate extern but the db frontend is pretty much tied
+extern PLUGINLINK pluginCoreLink;
+// contains the location of mirandaboot.ini
+extern char mirandabootini[MAX_PATH];
+
+// returns 1 if the profile path was returned, without trailing slash
+int getProfilePath(char * buf, size_t cch)
+{
+ char profiledir[MAX_PATH];
+ char exprofiledir[MAX_PATH];
+ char * p = 0;
+ // grab the base location now
+ GetModuleFileNameA(NULL, buf, cch);
+ p = strrchr(buf, '\\');
+ if ( p != 0 ) *p=0;
+ // change to this location, or "." wont expand properly
+ _chdir(buf);
+ GetPrivateProfileStringA("Database", "ProfileDir", ".", profiledir, SIZEOF(profiledir), mirandabootini);
+ // get the string containing envars and maybe relative paths
+ // get rid of the vars
+ ExpandEnvironmentStringsA(profiledir, exprofiledir, SIZEOF(exprofiledir));
+ if ( _fullpath(profiledir, exprofiledir, SIZEOF(profiledir)) != 0 ) {
+ /* XXX: really use CreateDirectory()? it only creates the last dir given a\b\c, SHCreateDirectory()
+ does what we want however thats 2000+ only */
+ DWORD dw = INVALID_FILE_ATTRIBUTES;
+ CreateDirectoryA(profiledir, NULL);
+ dw=GetFileAttributesA(profiledir);
+ if ( dw != INVALID_FILE_ATTRIBUTES && dw&FILE_ATTRIBUTE_DIRECTORY ) {
+ strncpy(buf, profiledir, cch);
+ p = strrchr(buf, '\\');
+ // if the char after '\' is null then change '\' to null
+ if ( p != 0 && *(++p)==0 ) *(--p)=0;
+ return 1;
+ }
+ }
+ // this never happens, usually C:\ is always returned
+ return 0;
+}
+
+// returns 1 if *.dat spec is matched
+int isValidProfileName(char * name)
+{
+ char * p = strrchr(name, '.');
+ if ( p ) {
+ p++;
+ if ( lstrcmpiA( p, "dat" ) == 0 ) {
+ if ( p[3] == 0 ) return 1;
+ }
+ }
+ return 0;
+}
+
+// returns 1 if a single profile (full path) is found within the profile dir
+static int getProfile1(char * szProfile, size_t cch, char * profiledir, BOOL * noProfiles)
+{
+ int rc = 1;
+ char searchspec[MAX_PATH];
+ WIN32_FIND_DATAA ffd;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ unsigned int found=0;
+ mir_snprintf(searchspec,SIZEOF(searchspec),"%s\\*.dat", profiledir);
+ hFind = FindFirstFileA(searchspec, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE )
+ {
+ // make sure the first hit is actually a *.dat file
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) )
+ {
+ // copy the profile name early cos it might be the only one
+ mir_snprintf(szProfile, cch, "%s\\%s", profiledir, ffd.cFileName);
+ found++;
+ // this might be the only dat but there might be a few wrong things returned before another *.dat
+ while ( FindNextFileA(hFind,&ffd) ) {
+ // found another *.dat, but valid?
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) ) {
+ rc=0;
+ found++;
+ break;
+ } //if
+ } // while
+ } //if
+ FindClose(hFind);
+ }
+ if ( found == 0 && noProfiles != 0 ) {
+ *noProfiles=TRUE;
+ rc=0;
+ }
+ return rc;
+}
+
+// returns 1 if something that looks like a profile is there
+static int getProfileCmdLineArgs(char * szProfile, size_t cch)
+{
+ char *szCmdLine=GetCommandLineA();
+ char *szEndOfParam;
+ char szThisParam[1024];
+ int firstParam=1;
+
+ while(szCmdLine[0]) {
+ if(szCmdLine[0]=='"') {
+ szEndOfParam=strchr(szCmdLine+1,'"');
+ if(szEndOfParam==NULL) break;
+ lstrcpynA(szThisParam,szCmdLine+1,min( SIZEOF(szThisParam),szEndOfParam-szCmdLine));
+ szCmdLine=szEndOfParam+1;
+ }
+ else {
+ szEndOfParam=szCmdLine+strcspn(szCmdLine," \t");
+ lstrcpynA(szThisParam,szCmdLine,min( SIZEOF(szThisParam),szEndOfParam-szCmdLine+1));
+ szCmdLine=szEndOfParam;
+ }
+ while(*szCmdLine && *szCmdLine<=' ') szCmdLine++;
+ if(firstParam) {firstParam=0; continue;} //first param is executable name
+ if(szThisParam[0]=='/' || szThisParam[0]=='-') continue; //no switches supported
+ ExpandEnvironmentStringsA(szThisParam,szProfile,cch);
+ return 1;
+ }
+ return 0;
+}
+
+// returns 1 if a valid filename (incl. dat) is found, includes fully qualified path
+static int getProfileCmdLine(char * szProfile, size_t cch, char * profiledir)
+{
+ char buf[MAX_PATH];
+ HANDLE hFile;
+ int rc;
+ if ( getProfileCmdLineArgs(buf, SIZEOF(buf)) ) {
+ // have something that looks like a .dat, with or without .dat in the filename
+ if ( !isValidProfileName(buf) ) mir_snprintf(buf, SIZEOF(buf)-5,"%s.dat",buf);
+ // expand the relative to a full path , which might fail
+ if ( _fullpath(szProfile, buf, cch) != 0 ) {
+ hFile=CreateFileA(szProfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ rc=hFile != INVALID_HANDLE_VALUE;
+ CloseHandle(hFile);
+ return rc;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+// returns 1 if the profile manager should be shown
+static int showProfileManager(void)
+{
+ char Mgr[32];
+ // is control pressed?
+ if (GetAsyncKeyState(VK_CONTROL)&0x8000) return 1;
+ // wanna show it?
+ GetPrivateProfileStringA("Database", "ShowProfileMgr", "never", Mgr, SIZEOF(Mgr), mirandabootini);
+ if ( _strcmpi(Mgr,"yes") == 0 ) return 1;
+ return 0;
+}
+
+// returns 1 if a default profile should be selected instead of showing the manager.
+static int getProfileAutoRun(char * szProfile, size_t cch, char * profiledir)
+{
+ char Mgr[32];
+ char env_profile[MAX_PATH];
+ char exp_profile[MAX_PATH];
+ GetPrivateProfileStringA("Database", "ShowProfileMgr", "", Mgr, SIZEOF(Mgr), mirandabootini);
+ if ( lstrcmpiA(Mgr,"never") ) return 0;
+ GetPrivateProfileStringA("Database", "DefaultProfile", "", env_profile, SIZEOF(env_profile), mirandabootini);
+ if ( lstrlenA(env_profile) == 0 ) return 0;
+ ExpandEnvironmentStringsA(env_profile, exp_profile, SIZEOF(exp_profile));
+ mir_snprintf(szProfile, cch, "%s\\%s.dat", profiledir, exp_profile);
+ return 1;
+}
+
+
+
+// returns 1 if a profile was selected
+static int getProfile(char * szProfile, size_t cch)
+{
+ char profiledir[MAX_PATH];
+ PROFILEMANAGERDATA pd;
+ ZeroMemory(&pd,sizeof(pd));
+ getProfilePath(profiledir,SIZEOF(profiledir));
+ if ( getProfileCmdLine(szProfile, cch, profiledir) ) return 1;
+ if ( getProfileAutoRun(szProfile, cch, profiledir) ) return 1;
+ if ( !showProfileManager() && getProfile1(szProfile, cch, profiledir, &pd.noProfiles) ) return 1;
+ else {
+ pd.szProfile=szProfile;
+ pd.szProfileDir=profiledir;
+ return getProfileManager(&pd);
+ }
+}
+
+// called by the UI, return 1 on success, use link to create profile, set error if any
+int makeDatabase(char * profile, DATABASELINK * link, HWND hwndDlg)
+{
+ char buf[256];
+ int err=0;
+ // check if the file already exists
+ HANDLE hFile=CreateFileA(profile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ char * file = strrchr(profile,'\\');
+ file++;
+ if ( hFile != INVALID_HANDLE_VALUE ) {
+ CloseHandle(hFile);
+ mir_snprintf(buf, SIZEOF(buf), Translate("The profile '%s' already exists. Do you want to move it to the "
+ "Recycle Bin? \n\nWARNING: The profile will be deleted if Recycle Bin is disabled.\nWARNING: A profile may contain confidential information and should be properly deleted."),file);
+ // file already exists!
+ if ( MessageBoxA(hwndDlg, buf, Translate("The profile already exists"), MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES ) return 0;
+ // move the file
+ {
+ char szName[MAX_PATH]; // SHFileOperation needs a "double null"
+ SHFILEOPSTRUCTA sf;
+ ZeroMemory(&sf,sizeof(sf));
+ sf.wFunc=FO_DELETE;
+ sf.pFrom=szName;
+ sf.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+ mir_snprintf(szName, SIZEOF(szName),"%s\0",profile);
+ if ( SHFileOperationA(&sf) != 0 ) {
+ mir_snprintf(buf, SIZEOF(buf),Translate("Couldn't move '%s' to the Recycle Bin, Please select another profile name."),file);
+ MessageBoxA(0,buf,Translate("Problem moving profile"),MB_ICONINFORMATION|MB_OK);
+ return 0;
+ }
+ }
+ // now the file should be gone!
+ }
+ // ask the database to create the profile
+ if ( link->makeDatabase(profile,&err) ) {
+ mir_snprintf(buf, SIZEOF(buf),Translate("Unable to create the profile '%s', the error was %x"),file, err);
+ MessageBoxA(hwndDlg,buf,Translate("Problem creating profile"),MB_ICONERROR|MB_OK);
+ return 0;
+ }
+ // the profile has been created! woot
+ return 1;
+}
+
+// enumerate all plugins that had valid DatabasePluginInfo()
+static int FindDbPluginForProfile(char * pluginname, DATABASELINK * dblink, LPARAM lParam)
+{
+ char * szProfile = (char *) lParam;
+ if ( dblink && dblink->cbSize == sizeof(DATABASELINK) ) {
+ int err=0;
+ int rc=0;
+ // liked the profile?
+ rc=dblink->grokHeader(szProfile,&err);
+ if ( rc == 0 ) {
+ // added APIs?
+ if ( dblink->Load(szProfile, &pluginCoreLink) == 0 ) return DBPE_DONE;
+ return DBPE_HALT;
+ } else {
+ switch ( err ) {
+ case EGROKPRF_CANTREAD:
+ case EGROKPRF_UNKHEADER:
+ {
+ // just not supported.
+ return DBPE_CONT;
+ }
+ case EGROKPRF_VERNEWER:
+ case EGROKPRF_DAMAGED:
+ {
+ break;
+ }
+ }
+ return DBPE_HALT;
+ } //if
+ }
+ return DBPE_CONT;
+}
+
+typedef struct {
+ char * profile;
+ UINT msg;
+ ATOM aPath;
+ int found;
+} ENUMMIRANDAWINDOW;
+
+static BOOL CALLBACK EnumMirandaWindows(HWND hwnd, LPARAM lParam)
+{
+ TCHAR classname[256];
+ ENUMMIRANDAWINDOW * x = (ENUMMIRANDAWINDOW *)lParam;
+ DWORD res=0;
+ if ( GetClassName(hwnd,classname,SIZEOF(classname)) && lstrcmp( _T("Miranda"),classname)==0 ) {
+ if ( SendMessageTimeout(hwnd, x->msg, (WPARAM)x->aPath, 0, SMTO_ABORTIFHUNG, 100, &res) && res ) {
+ x->found++;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int FindMirandaForProfile(char * szProfile)
+{
+ ENUMMIRANDAWINDOW x={0};
+ x.profile=szProfile;
+ x.msg=RegisterWindowMessage( _T( "Miranda::ProcessProfile" ));
+ x.aPath=GlobalAddAtomA(szProfile);
+ EnumWindows(EnumMirandaWindows, (LPARAM)&x);
+ GlobalDeleteAtom(x.aPath);
+ return x.found;
+}
+
+int LoadDatabaseModule(void)
+{
+ int iReturn = 0;
+ char szProfile[MAX_PATH];
+ szProfile[0]=0;
+
+ // load the older basic services of the db
+ InitTime();
+
+ // find out which profile to load
+ if ( getProfile(szProfile, SIZEOF(szProfile)) )
+ {
+ int rc;
+ PLUGIN_DB_ENUM dbe;
+
+ dbe.cbSize=sizeof(PLUGIN_DB_ENUM);
+ dbe.pfnEnumCallback=( int(*) (char*,void*,LPARAM) )FindDbPluginForProfile;
+ dbe.lParam=(LPARAM)szProfile;
+
+ // find a driver to support the given profile
+ rc=CallService(MS_PLUGINS_ENUMDBPLUGINS, 0, (LPARAM)&dbe);
+ switch ( rc ) {
+ case -1: {
+ // no plugins at all
+ char buf[256];
+ char * p = strrchr(szProfile,'\\');
+ mir_snprintf(buf,SIZEOF(buf),Translate("Miranda is unable to open '%s' because you do not have any profile plugins installed.\nYou need to install dbx_3x.dll or equivalent."), p ? ++p : szProfile );
+ MessageBoxA(0,buf,Translate("No profile support installed!"),MB_OK | MB_ICONERROR);
+ break;
+ }
+ case 1: {
+ // if there were drivers but they all failed cos the file is locked, try and find the miranda which locked it
+ HANDLE hFile;
+ hFile=CreateFileA(szProfile,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
+ if ( hFile == INVALID_HANDLE_VALUE ) {
+ if ( !FindMirandaForProfile(szProfile) ) {
+ // file is locked, tried to find miranda window, but that failed too.
+ }
+ } else {
+ // file isn't locked, just no driver could open it.
+ char buf[256];
+ char * p = strrchr(szProfile,'\\');
+ mir_snprintf(buf,SIZEOF(buf),Translate("Miranda was unable to open '%s', its in an unknown format.\nThis profile might also be damaged, please run DB-tool which should be installed."), p ? ++p : szProfile);
+ MessageBoxA(0,buf,Translate("Miranda can't understand that profile"),MB_OK | MB_ICONERROR);
+ CloseHandle(hFile);
+ }
+ break;
+ }
+ }
+ iReturn = (rc != 0);
+ }
+ else
+ {
+ iReturn = 1;
+ }
+
+ return iReturn;
+}
+
diff --git a/miranda-wine/src/modules/database/dbini.c b/miranda-wine/src/modules/database/dbini.c new file mode 100644 index 0000000..0717080 --- /dev/null +++ b/miranda-wine/src/modules/database/dbini.c @@ -0,0 +1,495 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "../../core/commonheaders.h"
+//#include "database.h"
+
+static HANDLE hIniChangeNotification;
+extern char mirandabootini[MAX_PATH];
+
+int GetCommandLineDbName(char *szName,int cbName)
+{
+ char *szCmdLine=GetCommandLineA();
+ char *szEndOfParam;
+ char szThisParam[1024];
+ int firstParam=1;
+
+ while(szCmdLine[0]) {
+ if(szCmdLine[0]=='"') {
+ szEndOfParam=strchr(szCmdLine+1,'"');
+ if(szEndOfParam==NULL) break;
+ lstrcpynA(szThisParam,szCmdLine+1,min(sizeof(szThisParam),szEndOfParam-szCmdLine));
+ szCmdLine=szEndOfParam+1;
+ }
+ else {
+ szEndOfParam=szCmdLine+strcspn(szCmdLine," \t");
+ lstrcpynA(szThisParam,szCmdLine,min(sizeof(szThisParam),szEndOfParam-szCmdLine+1));
+ szCmdLine=szEndOfParam;
+ }
+ while(*szCmdLine && *szCmdLine<=' ') szCmdLine++;
+ if(firstParam) {firstParam=0; continue;} //first param is executable name
+ if(szThisParam[0]=='/' || szThisParam[0]=='-') continue; //no switches supported
+ lstrcpynA(szName,szThisParam,cbName);
+ return 0;
+ }
+ return 1;
+}
+
+void GetProfileDirectory(char *szPath,int cbPath)
+{
+ char *str2;
+ char szMirandaDir[MAX_PATH],szProfileDir[MAX_PATH],szExpandedProfileDir[MAX_PATH];
+ DWORD dwAttributes;
+
+ GetModuleFileNameA(GetModuleHandle(NULL),szMirandaDir,sizeof(szMirandaDir));
+ str2=strrchr(szMirandaDir,'\\');
+ if(str2!=NULL) *str2=0;
+ GetPrivateProfileStringA("Database","ProfileDir",".",szProfileDir,sizeof(szProfileDir),mirandabootini);
+ ExpandEnvironmentStringsA(szProfileDir,szExpandedProfileDir,sizeof(szExpandedProfileDir));
+ _chdir(szMirandaDir);
+ if(!_fullpath(szPath,szExpandedProfileDir,cbPath))
+ lstrcpynA(szPath,szMirandaDir,cbPath);
+ if(szPath[lstrlenA(szPath)-1]=='\\') szPath[lstrlenA(szPath)-1]='\0';
+ if((dwAttributes=GetFileAttributesA(szPath))!=0xffffffff&&dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ CreateDirectoryA(szPath,NULL);
+}
+
+int ShouldAutoCreate(void)
+{
+ char szAutoCreate[4];
+ GetPrivateProfileStringA("Database","AutoCreate","no",szAutoCreate,sizeof(szAutoCreate),mirandabootini);
+ return !lstrcmpiA(szAutoCreate,"yes");
+}
+
+int GetDefaultProfilePath(char *szPath,int cbPath,int *specified)
+{
+ char szProfileDir[MAX_PATH],szDefaultName[MAX_PATH],szExpandedDefaultName[MAX_PATH];
+ HANDLE hFind;
+ char szSearchPath[MAX_PATH],szSingleExistingPath[MAX_PATH];
+ WIN32_FIND_DATAA fd;
+
+ if(specified) *specified=1;
+ GetProfileDirectory(szProfileDir,sizeof(szProfileDir));
+ if(GetCommandLineDbName(szDefaultName,sizeof(szDefaultName))) {
+ if(specified) *specified=0;
+ GetPrivateProfileStringA("Database","DefaultProfile","",szDefaultName,sizeof(szDefaultName),mirandabootini);
+ }
+ ExpandEnvironmentStringsA(szDefaultName,szExpandedDefaultName,sizeof(szExpandedDefaultName));
+
+ _chdir(szProfileDir);
+
+ szSingleExistingPath[0]='\0';
+ lstrcpyA(szSearchPath,szProfileDir);
+ lstrcatA(szSearchPath,"\\*.dat");
+ hFind=FindFirstFileA(szSearchPath,&fd);
+ if(hFind!=INVALID_HANDLE_VALUE) {
+ if(FindNextFileA(hFind,&fd)==0)
+ if(_fullpath(szSingleExistingPath,fd.cFileName,cbPath)==NULL)
+ szSingleExistingPath[0]='\0';
+ FindClose(hFind);
+ }
+
+ if(szExpandedDefaultName[0]) {
+ lstrcatA(szExpandedDefaultName,".dat");
+ if(_fullpath(szPath,szExpandedDefaultName,cbPath)!=NULL) {
+ if(specified && !lstrcmpiA(szSingleExistingPath,szPath)) *specified=1;
+ if(!_access(szPath,0)) return 0;
+ if(ShouldAutoCreate()) {
+ HANDLE hFile;
+ if(specified && szSingleExistingPath[0]=='\0') *specified=1;
+ hFile=CreateFileA(szPath,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,0,NULL);
+ CloseHandle(hFile);
+ return 0;
+ }
+ }
+ }
+
+ if(szSingleExistingPath[0]) {
+ if(specified && szExpandedDefaultName[0]=='\0') *specified=1;
+ lstrcpynA(szPath,szSingleExistingPath,cbPath);
+ return 0;
+ }
+ return 1;
+}
+
+int ShouldShowProfileManager(void)
+{
+ char szShowValue[7];
+ char szDefaultProfile[MAX_PATH];
+ int defaultProfileSpecified;
+
+ if(GetAsyncKeyState(VK_CONTROL)&0x8000) return 1;
+ GetPrivateProfileStringA("Database","ShowProfileMgr","smart",szShowValue,sizeof(szShowValue),mirandabootini);
+ if(!lstrcmpiA(szShowValue,"always")) return 1;
+ if(!lstrcmpiA(szShowValue,"never")) {
+ return GetDefaultProfilePath(szDefaultProfile,sizeof(szDefaultProfile),NULL);
+ }
+ return GetDefaultProfilePath(szDefaultProfile,sizeof(szDefaultProfile),&defaultProfileSpecified)
+ || !defaultProfileSpecified;
+}
+
+static BOOL CALLBACK InstallIniDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_ININAME,(char*)lParam);
+ { char szSecurity[11],*pszSecurityInfo;
+ GetPrivateProfileStringA("AutoExec","Warn","notsafe",szSecurity,sizeof(szSecurity),mirandabootini);
+ if(!lstrcmpiA(szSecurity,"all"))
+ pszSecurityInfo="Security systems to prevent malicious changes are in place and you will be warned before every change that is made.";
+ else if(!lstrcmpiA(szSecurity,"onlyunsafe"))
+ pszSecurityInfo="Security systems to prevent malicious changes are in place and you will be warned before changes that are known to be unsafe.";
+ else if(!lstrcmpiA(szSecurity,"none"))
+ pszSecurityInfo="Security systems to prevent malicious changes have been disabled. You will receive no further warnings.";
+ else pszSecurityInfo=NULL;
+ if(pszSecurityInfo) SetDlgItemTextA(hwndDlg,IDC_SECURITYINFO,ServiceExists(MS_LANGPACK_TRANSLATESTRING)?Translate(pszSecurityInfo):pszSecurityInfo);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_VIEWINI:
+ { char szPath[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_ININAME,szPath,sizeof(szPath));
+ ShellExecuteA(hwndDlg,"open",szPath,NULL,NULL,SW_SHOW);
+ break;
+ }
+ case IDOK:
+ case IDCANCEL:
+ case IDC_NOTOALL:
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int IsInSpaceSeparatedList(const char *szWord,const char *szList)
+{
+ char *szItem,*szEnd;
+ int wordLen=lstrlenA(szWord);
+
+ for(szItem=(char*)szList;;) {
+ szEnd=strchr(szItem,' ');
+ if(szEnd==NULL) return !lstrcmpA(szItem,szWord);
+ if(szEnd-szItem==wordLen) {
+ if(!strncmp(szItem,szWord,wordLen)) return 1;
+ }
+ szItem=szEnd+1;
+ }
+ return 0;
+}
+
+struct warnSettingChangeInfo_t {
+ char *szIniPath;
+ char *szSection;
+ char *szSafeSections;
+ char *szUnsafeSections;
+ char *szName;
+ char *szValue;
+ int warnNoMore,cancel;
+};
+
+static BOOL CALLBACK WarnIniChangeDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ static struct warnSettingChangeInfo_t *warnInfo;
+
+ switch(message) {
+ case WM_INITDIALOG:
+ { char szSettingName[256];
+ char *pszSecurityInfo;
+ warnInfo=(struct warnSettingChangeInfo_t*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_ININAME,warnInfo->szIniPath);
+ lstrcpyA(szSettingName,warnInfo->szSection);
+ lstrcatA(szSettingName," / ");
+ lstrcatA(szSettingName,warnInfo->szName);
+ SetDlgItemTextA(hwndDlg,IDC_SETTINGNAME,szSettingName);
+ SetDlgItemTextA(hwndDlg,IDC_NEWVALUE,warnInfo->szValue);
+ if(IsInSpaceSeparatedList(warnInfo->szSection,warnInfo->szSafeSections))
+ pszSecurityInfo="This change is known to be safe.";
+ else if(IsInSpaceSeparatedList(warnInfo->szSection,warnInfo->szUnsafeSections))
+ pszSecurityInfo="This change is known to be potentially hazardous.";
+ else
+ pszSecurityInfo="This change is not known to be safe.";
+ SetDlgItemTextA(hwndDlg,IDC_SECURITYINFO,ServiceExists(MS_LANGPACK_TRANSLATESTRING)?Translate(pszSecurityInfo):pszSecurityInfo);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ warnInfo->cancel=1;
+ case IDYES:
+ case IDNO:
+ warnInfo->warnNoMore=IsDlgButtonChecked(hwndDlg,IDC_WARNNOMORE);
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK IniImportDoneDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_ININAME,(char*)lParam);
+ SetDlgItemTextA(hwndDlg,IDC_NEWNAME,(char*)lParam);
+ return TRUE;
+ case WM_COMMAND:
+ { char szIniPath[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_ININAME,szIniPath,sizeof(szIniPath));
+ switch(LOWORD(wParam)) {
+ case IDC_DELETE:
+ DeleteFileA(szIniPath);
+ case IDC_LEAVE:
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_RECYCLE:
+ { SHFILEOPSTRUCTA shfo={0};
+ shfo.wFunc=FO_DELETE;
+ shfo.pFrom=szIniPath;
+ szIniPath[lstrlenA(szIniPath)+1]='\0';
+ shfo.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+ SHFileOperationA(&shfo);
+ }
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_MOVE:
+ { char szNewPath[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_NEWNAME,szNewPath,sizeof(szNewPath));
+ MoveFileA(szIniPath,szNewPath);
+ }
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static void DoAutoExec(void)
+{
+ HANDLE hFind;
+ char szMirandaDir[MAX_PATH],szUse[7],szIniPath[MAX_PATH],szFindPath[MAX_PATH],szExpandedFindPath[MAX_PATH];
+ char szLine[2048];
+ char *str2;
+ WIN32_FIND_DATAA fd;
+ FILE *fp;
+ char szSection[128];
+ int lineLength;
+ char szSafeSections[2048],szUnsafeSections[2048],szSecurity[11],szOverrideSecurityFilename[MAX_PATH];
+ int warnThisSection=0;
+
+ GetPrivateProfileStringA("AutoExec","Use","prompt",szUse,sizeof(szUse),mirandabootini);
+ if(!lstrcmpiA(szUse,"no")) return;
+ GetPrivateProfileStringA("AutoExec","Safe","CLC Icons CLUI CList SkinSounds",szSafeSections,sizeof(szSafeSections),mirandabootini);
+ GetPrivateProfileStringA("AutoExec","Unsafe","ICQ MSN",szUnsafeSections,sizeof(szUnsafeSections),mirandabootini);
+ GetPrivateProfileStringA("AutoExec","Warn","notsafe",szSecurity,sizeof(szSecurity),mirandabootini);
+ GetPrivateProfileStringA("AutoExec","OverrideSecurityFilename","",szOverrideSecurityFilename,sizeof(szOverrideSecurityFilename),mirandabootini);
+ GetModuleFileNameA(GetModuleHandle(NULL),szMirandaDir,sizeof(szMirandaDir));
+ str2=strrchr(szMirandaDir,'\\');
+ if(str2!=NULL) *str2=0;
+ _chdir(szMirandaDir);
+ GetPrivateProfileStringA("AutoExec","Glob","autoexec_*.ini",szFindPath,sizeof(szFindPath),mirandabootini);
+ ExpandEnvironmentStringsA(szFindPath,szExpandedFindPath,sizeof(szExpandedFindPath));
+ hFind=FindFirstFileA(szExpandedFindPath,&fd);
+ if(hFind==INVALID_HANDLE_VALUE) return;
+ str2=strrchr(szExpandedFindPath,'\\');
+ if(str2==NULL) str2=szExpandedFindPath;
+ else str2++;
+ *str2='\0';
+ szSection[0]='\0';
+ do {
+ lstrcpyA(szIniPath,szExpandedFindPath);
+ lstrcatA(szIniPath,fd.cFileName);
+ if(!lstrcmpiA(szUse,"prompt") && lstrcmpiA(fd.cFileName,szOverrideSecurityFilename)) {
+ int result=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_INSTALLINI),NULL,InstallIniDlgProc,(LPARAM)szIniPath);
+ if(result==IDC_NOTOALL) break;
+ if(result==IDCANCEL) continue;
+ }
+ fp=fopen(szIniPath,"rt");
+ while(!feof(fp)) {
+ if(fgets(szLine,sizeof(szLine),fp)==NULL) break;
+ lineLength=lstrlenA(szLine);
+ while(lineLength && (BYTE)(szLine[lineLength-1])<=' ') szLine[--lineLength]='\0';
+ if(szLine[0]==';' || szLine[0]<=' ') continue;
+ if(szLine[0]=='[') {
+ char *szEnd=strchr(szLine+1,']');
+ if(szEnd==NULL) continue;
+ if(szLine[1]=='!')
+ szSection[0]='\0';
+ else {
+ lstrcpynA(szSection,szLine+1,min(sizeof(szSection),szEnd-szLine));
+ if(!lstrcmpiA(szSecurity,"none")) warnThisSection=0;
+ else if(!lstrcmpiA(szSecurity,"notsafe"))
+ warnThisSection=!IsInSpaceSeparatedList(szSection,szSafeSections);
+ else if(!lstrcmpiA(szSecurity,"onlyunsafe"))
+ warnThisSection=IsInSpaceSeparatedList(szSection,szUnsafeSections);
+ else warnThisSection=1;
+ if(!lstrcmpiA(fd.cFileName,szOverrideSecurityFilename)) warnThisSection=0;
+ }
+ }
+ else {
+ char *szValue;
+ char szName[128];
+ struct warnSettingChangeInfo_t warnInfo;
+
+ if(szSection[0]=='\0') continue;
+ szValue=strchr(szLine,'=');
+ if(szValue==NULL) continue;
+ lstrcpynA(szName,szLine,min(sizeof(szName),szValue-szLine+1));
+ szValue++;
+ warnInfo.szIniPath=szIniPath;
+ warnInfo.szName=szName;
+ warnInfo.szSafeSections=szSafeSections;
+ warnInfo.szSection=szSection;
+ warnInfo.szUnsafeSections=szUnsafeSections;
+ warnInfo.szValue=szValue;
+ warnInfo.warnNoMore=0;
+ warnInfo.cancel=0;
+ if(!warnThisSection || IDNO!=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_WARNINICHANGE),NULL,WarnIniChangeDlgProc,(LPARAM)&warnInfo)) {
+ if(warnInfo.cancel) break;
+ if(warnInfo.warnNoMore) warnThisSection=0;
+ switch(szValue[0]) {
+ case 'b':
+ case 'B':
+ DBWriteContactSettingByte(NULL,szSection,szName,(BYTE)strtol(szValue+1,NULL,0));
+ break;
+ case 'w':
+ case 'W':
+ DBWriteContactSettingWord(NULL,szSection,szName,(WORD)strtol(szValue+1,NULL,0));
+ break;
+ case 'd':
+ case 'D':
+ DBWriteContactSettingDword(NULL,szSection,szName,(DWORD)strtoul(szValue+1,NULL,0));
+ break;
+ case 'l':
+ case 'L':
+ DBDeleteContactSetting(NULL,szSection,szName);
+ break;
+ case 's':
+ case 'S':
+ DBWriteContactSettingString(NULL,szSection,szName,szValue+1);
+ break;
+ case 'u':
+ case 'U':
+ DBWriteContactSettingStringUtf(NULL,szSection,szName,szValue+1);
+ break;
+ case 'n':
+ case 'N':
+ { PBYTE buf;
+ int len;
+ char *pszValue,*pszEnd;
+ DBCONTACTWRITESETTING cws;
+
+ buf=(PBYTE)mir_alloc(lstrlenA(szValue+1));
+ for(len=0,pszValue=szValue+1;;len++) {
+ buf[len]=(BYTE)strtol(pszValue,&pszEnd,0x10);
+ if(pszValue==pszEnd) break;
+ pszValue=pszEnd;
+ }
+ cws.szModule=szSection;
+ cws.szSetting=szName;
+ cws.value.type=DBVT_BLOB;
+ cws.value.pbVal=buf;
+ cws.value.cpbVal=len;
+ CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws);
+ mir_free(buf);
+ }
+ break;
+ default:
+ if(ServiceExists(MS_LANGPACK_TRANSLATESTRING))
+ MessageBox(NULL,TranslateT("Invalid setting type. The first character of every value must be b, w, d, l, s or n."),TranslateT("Install Database Settings"),MB_OK);
+ else
+ MessageBoxA(NULL,"Invalid setting type. The first character of every value must be b, w, d, l, s or n.","Install Database Settings",MB_OK);
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ if(!lstrcmpiA(fd.cFileName,szOverrideSecurityFilename))
+ DeleteFileA(szIniPath);
+ else {
+ char szOnCompletion[8];
+ GetPrivateProfileStringA("AutoExec","OnCompletion","recycle",szOnCompletion,sizeof(szOnCompletion),mirandabootini);
+ if(!lstrcmpiA(szOnCompletion,"delete"))
+ DeleteFileA(szIniPath);
+ else if(!lstrcmpiA(szOnCompletion,"recycle")) {
+ SHFILEOPSTRUCTA shfo={0};
+ shfo.wFunc=FO_DELETE;
+ shfo.pFrom=szIniPath;
+ szIniPath[lstrlenA(szIniPath)+1]='\0';
+ shfo.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+ SHFileOperationA(&shfo);
+ }
+ else if(!lstrcmpiA(szOnCompletion,"rename")) {
+ char szRenamePrefix[MAX_PATH];
+ char szNewPath[MAX_PATH];
+ GetPrivateProfileStringA("AutoExec","RenamePrefix","done_",szRenamePrefix,sizeof(szRenamePrefix),mirandabootini);
+ lstrcpyA(szNewPath,szExpandedFindPath);
+ lstrcatA(szNewPath,szRenamePrefix);
+ lstrcatA(szNewPath,fd.cFileName);
+ MoveFileA(szIniPath,szNewPath);
+ }
+ else if(!lstrcmpiA(szOnCompletion,"ask"))
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_INIIMPORTDONE),NULL,IniImportDoneDlgProc,(LPARAM)szIniPath);
+ }
+ } while(FindNextFileA(hFind,&fd));
+ FindClose(hFind);
+}
+
+static int CheckIniImportNow(WPARAM wParam,LPARAM lParam)
+{
+ DoAutoExec();
+ FindNextChangeNotification(hIniChangeNotification);
+ return 0;
+}
+
+int InitIni(void)
+{
+ char szMirandaDir[MAX_PATH];
+ char *str2;
+
+ DoAutoExec();
+ GetModuleFileNameA(GetModuleHandle(NULL),szMirandaDir,sizeof(szMirandaDir));
+ str2=strrchr(szMirandaDir,'\\');
+ if(str2!=NULL) *str2=0;
+ hIniChangeNotification=FindFirstChangeNotificationA(szMirandaDir,0,FILE_NOTIFY_CHANGE_FILE_NAME);
+ if(hIniChangeNotification!=INVALID_HANDLE_VALUE) {
+ CreateServiceFunction("DB/Ini/CheckImportNow",CheckIniImportNow);
+ CallService(MS_SYSTEM_WAITONHANDLE,(WPARAM)hIniChangeNotification,(LPARAM)"DB/Ini/CheckImportNow");
+ }
+ return 0;
+}
+
+void UninitIni(void)
+{
+ CallService(MS_SYSTEM_REMOVEWAIT,(WPARAM)hIniChangeNotification,0);
+ FindCloseChangeNotification(hIniChangeNotification);
+}
\ No newline at end of file diff --git a/miranda-wine/src/modules/database/dblists.c b/miranda-wine/src/modules/database/dblists.c new file mode 100644 index 0000000..ab656ff --- /dev/null +++ b/miranda-wine/src/modules/database/dblists.c @@ -0,0 +1,149 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "dblists.h"
+
+/* a simple sorted list implementation */
+
+SortedList* List_Create( int p_limit, int p_increment )
+{
+ SortedList* result = ( SortedList* )mir_calloc( sizeof( SortedList ));
+ if ( result == NULL )
+ return(NULL);
+
+ result->increment = p_increment;
+ result->limit = p_limit;
+ return(result);
+}
+
+void List_Destroy( SortedList* p_list )
+{
+ if ( p_list == NULL )
+ return;
+
+ if ( p_list->items != NULL ) {
+ mir_free( p_list->items );
+ p_list->items = NULL;
+ }
+
+ p_list->realCount = p_list->limit = 0;
+}
+
+void* List_Find( SortedList* p_list, void* p_value )
+{
+ int index;
+
+ if ( !List_GetIndex( p_list, p_value, &index ))
+ return(NULL);
+
+ return(p_list->items[ index ]);
+}
+
+int List_GetIndex( SortedList* p_list, void* p_value, int* p_index )
+{
+ if ( p_list->sortFunc != NULL )
+ {
+ int low = 0;
+ int high = p_list->realCount-1;
+
+ while( low <= high )
+ {
+ int i = ( low+high )/2;
+ int result = p_list->sortFunc( p_list->items[ i ], p_value );
+ if ( result == 0 )
+ { *p_index = i;
+ return 1;
+ }
+
+ if ( result < 0 )
+ low = i+1;
+ else
+ high = i-1;
+ }
+
+ *p_index = low;
+ }
+ return 0;
+}
+
+int List_IndexOf( SortedList* p_list, void* p_value )
+{
+ int i;
+ for ( i=0; i < p_list->realCount; i++ )
+ if ( p_list->items[i] == p_value )
+ return i;
+
+ return -1;
+}
+
+int List_Insert( SortedList* p_list, void* p_value, int p_index)
+{
+ if ( p_value == NULL || p_index > p_list->realCount )
+ return 0;
+
+ if ( p_list->realCount == p_list->limit )
+ {
+ p_list->items = ( void** )mir_realloc( p_list->items, sizeof( void* )*(p_list->realCount + p_list->increment));
+ p_list->limit += p_list->increment;
+ }
+
+ if ( p_index < p_list->realCount )
+ memmove( p_list->items+p_index+1, p_list->items+p_index, sizeof( void* )*( p_list->realCount-p_index ));
+
+ p_list->realCount++;
+
+ p_list->items[ p_index ] = p_value;
+ return 1;
+}
+
+int List_InsertPtr( SortedList* list, void* p )
+{
+ int idx;
+ List_GetIndex( list, p, &idx );
+ return List_Insert( list, p, idx );
+}
+
+int List_Remove( SortedList* p_list, int index )
+{
+ if ( index < 0 || index > p_list->realCount )
+ return(0);
+
+ p_list->realCount--;
+ if ( p_list->realCount > index )
+ {
+ memmove( p_list->items+index, p_list->items+index+1, sizeof( void* )*( p_list->realCount-index ));
+ p_list->items[ p_list->realCount ] = NULL;
+ }
+
+ return 1;
+}
+
+int List_RemovePtr( SortedList* list, void* p )
+{
+ int idx = -1;
+ if ( List_GetIndex( list, p, &idx ))
+ List_Remove( list, idx );
+
+ return idx;
+}
diff --git a/miranda-wine/src/modules/database/dblists.h b/miranda-wine/src/modules/database/dblists.h new file mode 100644 index 0000000..c3397ab --- /dev/null +++ b/miranda-wine/src/modules/database/dblists.h @@ -0,0 +1,36 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+/* a simple sorted list implementation */
+
+SortedList* List_Create( int, int );
+void List_Destroy( SortedList* );
+
+void* List_Find( SortedList*, void* );
+int List_GetIndex( SortedList*, void*, int* );
+int List_Insert( SortedList*, void*, int );
+int List_Remove( SortedList*, int );
+int List_IndexOf( SortedList*, void* );
+
+int List_InsertPtr( SortedList* list, void* p );
+int List_RemovePtr( SortedList* list, void* p );
diff --git a/miranda-wine/src/modules/database/dbtime.c b/miranda-wine/src/modules/database/dbtime.c new file mode 100644 index 0000000..b2c9eb1 --- /dev/null +++ b/miranda-wine/src/modules/database/dbtime.c @@ -0,0 +1,239 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+//#include "database.h"
+
+static int daysInMonth[12]={31,28,31,30,31,30,31,31,30,31,30,31};
+static int IsLeapYear(int year)
+{
+ if(year&3) return 0;
+ if(year%100) return 1;
+ if(year%400) return 0;
+ return 1;
+}
+
+static int CompareSystemTimes(SYSTEMTIME *st,SYSTEMTIME *switchDate)
+{
+ FILETIME ft1,ft2;
+
+ if(switchDate->wYear==0) { //strange day-in-month thing
+ SYSTEMTIME tempst;
+
+ //short-circuit if the months aren't the same
+ if(st->wMonth<switchDate->wMonth) return -1;
+ if(st->wMonth>switchDate->wMonth) return 1;
+
+ tempst=*switchDate;
+ tempst.wYear=st->wYear;
+ tempst.wDay=1;
+ SystemTimeToFileTime(&tempst,&ft1);
+ FileTimeToSystemTime(&ft1,&tempst); //gets the day of week of the first of the month
+ tempst.wDay=1+(7+switchDate->wDayOfWeek-tempst.wDayOfWeek)%7;
+ if(switchDate->wDay==5) { //last wDayOfWeek in month
+ if(tempst.wMonth==2) {
+ if(IsLeapYear(tempst.wYear)) daysInMonth[1]=29;
+ else daysInMonth[1]=28;
+ }
+ tempst.wDay+=7*3; //can't be less than 4 of that day in the month
+ if(tempst.wDay+7<=daysInMonth[switchDate->wMonth-1]) tempst.wDay+=7;
+ }
+ else tempst.wDay+=7*(switchDate->wDay-1); //nth of month
+ SystemTimeToFileTime(&tempst,&ft2);
+ }
+ else {
+ switchDate->wYear=st->wYear;
+ SystemTimeToFileTime(switchDate,&ft2);
+ }
+ SystemTimeToFileTime(st,&ft1);
+ return CompareFileTime(&ft1,&ft2);
+}
+
+static int TimestampToLocal(WPARAM wParam,LPARAM lParam)
+{
+ TIME_ZONE_INFORMATION tzInfo;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ int iReturn = 0;
+
+ GetTimeZoneInformation(&tzInfo);
+ if(tzInfo.StandardDate.wMonth==0)
+ {
+ //no daylight savings time
+ iReturn = (int)(wParam-tzInfo.Bias*60);
+ }
+ else
+ {
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart=((__int64)11644473600+(__int64)wParam)*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+
+ if(tzInfo.DaylightDate.wMonth<tzInfo.StandardDate.wMonth)
+ {
+ //northern hemisphere
+ if(CompareSystemTimes(&st,&tzInfo.DaylightDate)<0 ||
+ CompareSystemTimes(&st,&tzInfo.StandardDate)>0)
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.StandardBias)*60);
+ }
+ else
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.DaylightBias)*60);
+ }
+ }
+ else
+ {
+ //southern hemisphere
+ if(CompareSystemTimes(&st,&tzInfo.StandardDate)<0 ||
+ CompareSystemTimes(&st,&tzInfo.DaylightDate)>0)
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.DaylightBias)*60);
+ }
+ else
+ {
+ iReturn = (int)(wParam-(tzInfo.Bias+tzInfo.StandardBias)*60);
+ }
+ }
+ }
+
+ return iReturn;
+}
+
+static int TimestampToString(WPARAM wParam,LPARAM lParam)
+{
+ DBTIMETOSTRING *tts=(DBTIMETOSTRING*)lParam;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ char dateTimeStr[64];
+ char *pDest,*pFormat;
+ int destCharsLeft,dateTimeStrLen;
+
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart=((__int64)11644473600+(__int64)(DWORD)TimestampToLocal(wParam,0))*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ destCharsLeft=tts->cbDest;
+ for(pFormat=tts->szFormat,pDest=tts->szDest;*pFormat;pFormat++) {
+ switch(*pFormat) {
+ case 't':
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 's':
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'm':
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOMINUTESORSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'd':
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'D':
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_LONGDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ default:
+ if(destCharsLeft) {
+ *pDest++=*pFormat;
+ destCharsLeft--;
+ }
+ continue;
+ }
+ dateTimeStrLen=strlen(dateTimeStr);
+ if(destCharsLeft<dateTimeStrLen) dateTimeStrLen=destCharsLeft;
+ CopyMemory(pDest,dateTimeStr,dateTimeStrLen);
+ destCharsLeft-=dateTimeStrLen;
+ pDest+=dateTimeStrLen;
+ }
+ if(destCharsLeft) *pDest=0;
+ else tts->szDest[tts->cbDest-1]=0;
+ return 0;
+}
+
+#if defined( _UNICODE )
+static int TimestampToStringW(WPARAM wParam,LPARAM lParam)
+{
+ DBTIMETOSTRINGT *tts = ( DBTIMETOSTRINGT* )lParam;
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ TCHAR dateTimeStr[64];
+ TCHAR *pDest,*pFormat;
+ int destCharsLeft, dateTimeStrLen;
+
+ //this huge number is the difference between 1970 and 1601 in seconds
+ liFiletime.QuadPart = (11644473600i64+(__int64)(DWORD)TimestampToLocal(wParam,0))*10000000;
+ filetime.dwHighDateTime = liFiletime.HighPart;
+ filetime.dwLowDateTime = liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ destCharsLeft = tts->cbDest;
+ for ( pFormat = tts->szFormat, pDest=tts->szDest; *pFormat; pFormat++ ) {
+ switch(*pFormat) {
+ case 't':
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 's':
+ GetTimeFormat(LOCALE_USER_DEFAULT,0,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'm':
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOMINUTESORSECONDS,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'd':
+ GetDateFormat(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ case 'D':
+ GetDateFormat(LOCALE_USER_DEFAULT,DATE_LONGDATE,&st,NULL,dateTimeStr,SIZEOF(dateTimeStr));
+ break;
+ default:
+ if ( destCharsLeft ) {
+ *pDest++ = *pFormat;
+ destCharsLeft--;
+ }
+ continue;
+ }
+ dateTimeStrLen = _tcslen(dateTimeStr);
+ if (destCharsLeft < dateTimeStrLen) dateTimeStrLen = destCharsLeft;
+ CopyMemory(pDest, dateTimeStr, dateTimeStrLen*sizeof(TCHAR));
+ destCharsLeft -= dateTimeStrLen;
+ pDest += dateTimeStrLen;
+ }
+ if ( destCharsLeft ) *pDest=0;
+ else tts->szDest[ tts->cbDest-1 ] = 0;
+ return 0;
+}
+#endif
+
+int InitTime(void)
+{
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOLOCAL, TimestampToLocal);
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToString);
+ #if defined( _UNICODE )
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToStringW);
+ #else
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToString);
+ #endif
+ return 0;
+}
diff --git a/miranda-wine/src/modules/database/profilemanager.c b/miranda-wine/src/modules/database/profilemanager.c new file mode 100644 index 0000000..8eeaa09 --- /dev/null +++ b/miranda-wine/src/modules/database/profilemanager.c @@ -0,0 +1,696 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "profilemanager.h"
+#include <sys/stat.h>
+
+#define WM_INPUTCHANGED (WM_USER + 0x3000)
+#define WM_FOCUSTEXTBOX (WM_USER + 0x3001)
+
+typedef BOOL (__cdecl *ENUMPROFILECALLBACK) (char * fullpath, char * profile, LPARAM lParam);
+
+struct DetailsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DetailsPageData {
+ DLGTEMPLATE *pTemplate;
+ HINSTANCE hInst;
+ DLGPROC dlgProc;
+ HWND hwnd;
+ int changed;
+};
+
+struct DlgProfData {
+ PROPSHEETHEADER * psh;
+ HWND hwndOK; // handle to OK button
+ PROFILEMANAGERDATA * pd;
+};
+
+struct DetailsData {
+ HINSTANCE hInstIcmp;
+ HFONT hBoldFont;
+ int pageCount;
+ int currentPage;
+ struct DetailsPageData *opd;
+ RECT rcDisplay;
+ struct DlgProfData * prof;
+};
+
+extern char mirandabootini[MAX_PATH]; // bad bad bad bad!
+static char szDefaultMirandaProfile[MAX_PATH];
+
+static void ThemeDialogBackground(HWND hwnd) {
+ if (IsWinVerXPPlus()) {
+ static HMODULE hThemeAPI = NULL;
+ if (!hThemeAPI) hThemeAPI = GetModuleHandleA("uxtheme");
+ if (hThemeAPI) {
+ HRESULT (STDAPICALLTYPE *MyEnableThemeDialogTexture)(HWND,DWORD) = (HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(hThemeAPI,"EnableThemeDialogTexture");
+ if (MyEnableThemeDialogTexture)
+ MyEnableThemeDialogTexture(hwnd,0x00000002|0x00000004); //0x00000002|0x00000004=ETDT_ENABLETAB
+ }
+ }
+}
+
+static int findProfiles(char * szProfileDir, ENUMPROFILECALLBACK callback, LPARAM lParam)
+{
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+ char searchspec[MAX_PATH];
+ mir_snprintf(searchspec, SIZEOF(searchspec), "%s\\*.dat", szProfileDir);
+ hFind = FindFirstFileA(searchspec, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ do {
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) )
+ {
+ char buf[MAX_PATH];
+ mir_snprintf(buf,SIZEOF(buf),"%s\\%s",szProfileDir, ffd.cFileName);
+ if ( !callback(buf, ffd.cFileName, lParam) ) break;
+ }
+ } while ( FindNextFileA(hFind, &ffd) );
+ FindClose(hFind);
+ return 1;
+ }
+ return 0;
+}
+
+static LRESULT CALLBACK ProfileNameValidate(HWND edit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if ( msg==WM_CHAR ) {
+ if ( strchr(".?/\\#' ",(char)wParam&0xFF) != 0 ) return 0;
+ PostMessage(GetParent(edit),WM_INPUTCHANGED,0,0);
+ }
+ return CallWindowProc((WNDPROC)GetWindowLong(edit,GWL_USERDATA),edit,msg,wParam,lParam);
+}
+
+static int FindDbProviders(char * pluginname, DATABASELINK * dblink, LPARAM lParam)
+{
+ HWND hwndDlg = (HWND)lParam;
+ HWND hwndCombo = GetDlgItem(hwndDlg, IDC_PROFILEDRIVERS);
+ char szName[64];
+
+ if ( dblink->getFriendlyName(szName,SIZEOF(szName),1) == 0 ) {
+ // add to combo box
+ LRESULT index = SendMessageA(hwndCombo, CB_ADDSTRING, 0, (LPARAM)Translate(szName));
+ SendMessage(hwndCombo, CB_SETITEMDATA, index, (LPARAM)dblink);
+ }
+ return DBPE_CONT;
+}
+
+// returns 1 if autocreation of the profile is setup, profile has to be at least MAX_PATH!
+static int checkAutoCreateProfile(char * profile)
+{
+ char ac[MAX_PATH];
+ char env_profile[MAX_PATH];
+ GetPrivateProfileStringA("Database", "AutoCreate", "no", ac, SIZEOF(ac), mirandabootini);
+ if ( lstrcmpiA(ac,"yes") != 0 ) return 0;
+ GetPrivateProfileStringA("Database", "DefaultProfile", "", ac, SIZEOF(ac), mirandabootini);
+ ExpandEnvironmentStringsA(ac, env_profile, SIZEOF(env_profile));
+ if ( profile != NULL ) strcpy(profile, env_profile);
+ return lstrlenA(env_profile) > 0;
+}
+
+static BOOL CALLBACK DlgProfileNew(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DlgProfData * dat = (struct DlgProfData *)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ // lParam = (struct DlgProfData *)
+ SetWindowLong(hwndDlg, GWL_USERDATA, lParam);
+ dat=(struct DlgProfData *)lParam;
+ {
+ // fill in the db plugins present
+ PLUGIN_DB_ENUM dbe;
+ dbe.cbSize=sizeof(dbe);
+ dbe.pfnEnumCallback=(int(*)(char*,void*,LPARAM))FindDbProviders;
+ dbe.lParam=(LPARAM)hwndDlg;
+ if ( CallService(MS_PLUGINS_ENUMDBPLUGINS,0,(LPARAM)&dbe) == (-1) ) {
+ // no plugins?!
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROFILEDRIVERS),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROFILENAME),FALSE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_NODBDRIVERS),TRUE);
+ } //if
+ // default item
+ SendDlgItemMessage(hwndDlg, IDC_PROFILEDRIVERS, CB_SETCURSEL, 0, 0);
+ }
+ // subclass the profile name box
+ {
+ HWND hwndProfile=GetDlgItem(hwndDlg, IDC_PROFILENAME);
+ WNDPROC proc = (WNDPROC)GetWindowLong(hwndProfile, GWL_WNDPROC);
+ SetWindowLong(hwndProfile,GWL_USERDATA,(LONG)proc);
+ SetWindowLong(hwndProfile,GWL_WNDPROC,(LONG)ProfileNameValidate);
+ }
+ // decide if there is a default profile name given in the INI and if it should be used
+ {
+ char profile[MAX_PATH];
+ if ( checkAutoCreateProfile((char*)&profile) ) SetDlgItemTextA(hwndDlg, IDC_PROFILENAME, profile);
+ }
+ // focus on the textbox
+ PostMessage(hwndDlg,WM_FOCUSTEXTBOX,0,0);
+ return TRUE;
+ }
+ case WM_FOCUSTEXTBOX:
+ {
+ SetFocus(GetDlgItem(hwndDlg,IDC_PROFILENAME));
+ break;
+ }
+ case WM_INPUTCHANGED: // when input in the edit box changes
+ {
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ EnableWindow(dat->hwndOK, GetWindowTextLength(GetDlgItem(hwndDlg,IDC_PROFILENAME)) > 0 );
+ break;
+ }
+ case WM_SHOWWINDOW:
+ {
+ if ( wParam ) {
+ SetWindowText( dat->hwndOK, TranslateT("&Create"));
+ SendMessage(hwndDlg,WM_INPUTCHANGED,0,0);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR * hdr = (NMHDR *)lParam;
+ if ( hdr && hdr->code == PSN_APPLY && dat && IsWindowVisible(hwndDlg) ) {
+ char szName[MAX_PATH];
+ LRESULT curSel = SendDlgItemMessage(hwndDlg,IDC_PROFILEDRIVERS,CB_GETCURSEL,0,0);
+ if ( curSel == CB_ERR ) break; // should never happen
+ GetWindowTextA(GetDlgItem(hwndDlg,IDC_PROFILENAME),szName,SIZEOF(szName));
+ if ( lstrlenA(szName) == 0 ) break;
+ mir_snprintf(dat->pd->szProfile,MAX_PATH,"%s\\%s.dat",dat->pd->szProfileDir,szName);
+ dat->pd->newProfile=1;
+ dat->pd->dblink=(DATABASELINK *)SendDlgItemMessage(hwndDlg,IDC_PROFILEDRIVERS,CB_GETITEMDATA,(WPARAM)curSel,0);
+
+ if ( makeDatabase(dat->pd->szProfile, dat->pd->dblink, hwndDlg) == 0 ) {
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,PSNRET_INVALID_NOCHANGEPAGE);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+TCHAR* rtrim( TCHAR *string )
+{
+ TCHAR* p = string + _tcslen( string ) - 1;
+
+ while ( p >= string )
+ { if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+
+static int DetectDbProvider(char * pluginname, DATABASELINK * dblink, LPARAM lParam)
+{
+ char* fullPath = (char*)lParam;
+ int error;
+
+ if ( dblink->grokHeader( fullPath, &error ) == 0 ) {
+ dblink->getFriendlyName( fullPath, MAX_PATH, 1 );
+ //strncpy( fullPath, pluginname, MAX_PATH );
+ return DBPE_HALT;
+ }
+
+ return DBPE_CONT;
+}
+
+BOOL EnumProfilesForList(char * fullpath, char * profile, LPARAM lParam)
+{
+ HWND hwndDlg = (HWND) lParam;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+ char sizeBuf[64];
+ LVITEMA item;
+ int iItem=0;
+ struct stat statbuf;
+ int bFileExists = FALSE;
+ char * p = strrchr(profile, '.');
+ strcpy(sizeBuf, "0 KB");
+ if ( p != NULL ) *p=0;
+ ZeroMemory(&item,sizeof(item));
+ item.mask = LVIF_TEXT | LVIF_IMAGE;
+ item.pszText = profile;
+ item.iItem=0;
+ item.iImage=0;
+ {
+ FILE * fp = fopen(fullpath, "r+");
+ item.iImage = fp != NULL ? 0 : 1;
+ if ( stat(fullpath, &statbuf) == 0) {
+ mir_snprintf(sizeBuf,SIZEOF(sizeBuf),"%u KB", statbuf.st_size / 1024);
+ bFileExists = TRUE;
+ }
+ if ( fp ) fclose(fp);
+ }
+ iItem=SendMessageA( hwndList, LVM_INSERTITEMA, 0, (LPARAM)&item);
+ if ( lstrcmpiA(szDefaultMirandaProfile, profile) == 0 )
+ ListView_SetItemState(hwndList, iItem, LVIS_SELECTED, LVIS_SELECTED);
+
+ item.iItem = iItem;
+ item.iSubItem = 2;
+ item.pszText = sizeBuf;
+ SendMessageA( hwndList, LVM_SETITEMTEXTA, iItem, (LPARAM)&item );
+
+ if ( bFileExists ) {
+ PLUGIN_DB_ENUM dbe;
+ char szPath[ MAX_PATH ];
+
+ LVITEM item2;
+ item2.mask = LVIF_TEXT;
+ item2.iItem = iItem;
+
+ dbe.cbSize=sizeof(dbe);
+ dbe.pfnEnumCallback=(int(*)(char*,void*,LPARAM))DetectDbProvider;
+ dbe.lParam=(LPARAM)szPath;
+ strncpy( szPath, fullpath, sizeof(szPath));
+ if (CallService(MS_PLUGINS_ENUMDBPLUGINS,0,(LPARAM)&dbe)==1) {
+ HANDLE hFile;
+
+ hFile=CreateFileA(fullpath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ // file locked
+ item.pszText = Translate("<In Use>");
+ }
+ else {
+ CloseHandle(hFile);
+ item.pszText = szPath;
+ }
+ item.iSubItem = 1;
+ SendMessageA( hwndList, LVM_SETITEMTEXTA, iItem, (LPARAM)&item );
+ }
+
+ item2.iSubItem = 3;
+ item2.pszText = rtrim( _tctime( &statbuf.st_ctime ));
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 );
+
+ item2.iSubItem = 4;
+ item2.pszText = rtrim( _tctime( &statbuf.st_mtime ));
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 );
+ }
+ return TRUE;
+}
+
+static BOOL CALLBACK DlgProfileSelect(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DlgProfData * dat = (struct DlgProfData *)GetWindowLong(hwndDlg, GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+ HIMAGELIST hImgList=0;
+ LVCOLUMN col;
+
+ TranslateDialogDefault(hwndDlg);
+
+ dat = (struct DlgProfData *) lParam;
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+
+ // set columns
+ col.mask = LVCF_TEXT | LVCF_WIDTH;
+ col.pszText = TranslateT("Profile");
+ col.cx=122;
+ ListView_InsertColumn( hwndList, 0, &col );
+
+ col.pszText = TranslateT("Driver");
+ col.cx=100;
+ ListView_InsertColumn( hwndList, 1, &col );
+
+ col.pszText = TranslateT("Size");
+ col.cx=60;
+ ListView_InsertColumn( hwndList, 2, &col );
+
+ col.pszText = TranslateT("Created");
+ col.cx=145;
+ ListView_InsertColumn( hwndList, 3, &col );
+
+ col.pszText = TranslateT("Accessed");
+ col.cx=145;
+ ListView_InsertColumn( hwndList, 4, &col );
+
+ // icons
+ hImgList=ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 1, 1);
+ ImageList_AddIcon(hImgList, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_USERDETAILS)) );
+ ImageList_AddIcon(hImgList, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_DELETE)) );
+ // LV will destroy the image list
+ ListView_SetImageList(hwndList, hImgList, LVSIL_SMALL);
+ // find all the profiles
+ findProfiles(dat->pd->szProfileDir, EnumProfilesForList, (LPARAM)hwndDlg);
+ PostMessage(hwndDlg,WM_FOCUSTEXTBOX,0,0);
+ return TRUE;
+ }
+ case WM_FOCUSTEXTBOX:
+ {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PROFILELIST);
+ SetFocus(hwndList);
+ if ( lstrlenA(szDefaultMirandaProfile) == 0 || ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_PROFILELIST)) == 0 )
+ ListView_SetItemState(hwndList, 0, LVIS_SELECTED, LVIS_SELECTED);
+ break;
+ }
+ case WM_SHOWWINDOW:
+ {
+ if ( wParam ) {
+ SetWindowText(dat->hwndOK,TranslateT("&Run"));
+ EnableWindow(dat->hwndOK, ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_PROFILELIST))==1);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPNMHDR hdr = (LPNMHDR) lParam;
+ if ( hdr && hdr->code == PSN_INFOCHANGED) {
+ break;
+ }
+ if ( hdr && hdr->idFrom == IDC_PROFILELIST ) {
+ switch ( hdr->code ) {
+ case LVN_ITEMCHANGED:
+ {
+ EnableWindow(dat->hwndOK, ListView_GetSelectedCount(hdr->hwndFrom)==1);
+ }
+ case NM_DBLCLK:
+ {
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+ LVITEMA item;
+ char profile[MAX_PATH];
+
+ if ( dat == NULL ) break;
+ ZeroMemory(&item,sizeof(item));
+ item.mask = LVIF_TEXT;
+ item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL);
+ item.pszText = profile;
+ item.cchTextMax = SIZEOF(profile);
+ if ( SendMessageA(hwndList, LVM_GETITEMA, 0, (LPARAM)&item) && dat ) {
+ mir_snprintf(dat->pd->szProfile, MAX_PATH, "%s\\%s.dat", dat->pd->szProfileDir, profile);
+ if ( hdr->code == NM_DBLCLK ) EndDialog(GetParent(hwndDlg), 1);
+ }
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ } //switch
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProfileManager(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DetailsData *dat;
+
+ dat=(struct DetailsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ struct DlgProfData * prof = (struct DlgProfData *)lParam;
+ PROPSHEETHEADER *psh = prof->psh;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_USERDETAILS)));
+ dat=(struct DetailsData*)mir_alloc(sizeof(struct DetailsData));
+ dat->prof = prof;
+ prof->hwndOK=GetDlgItem(hwndDlg,IDOK);
+ EnableWindow(prof->hwndOK, FALSE);
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)dat);
+ SetDlgItemTextA(hwndDlg,IDC_NAME,"Miranda IM Profile Manager");
+ { LOGFONT lf;
+ HFONT hNormalFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_NAME,WM_GETFONT,0,0);
+ GetObject(hNormalFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,(WPARAM)dat->hBoldFont,0);
+ }
+ { OPTIONSDIALOGPAGE *odp;
+ int i;
+ TCITEM tci;
+
+ dat->currentPage=0;
+ dat->pageCount=psh->nPages;
+ dat->opd=(struct DetailsPageData*)mir_alloc(sizeof(struct DetailsPageData)*dat->pageCount);
+ odp=(OPTIONSDIALOGPAGE*)psh->ppsp;
+
+ tci.mask=TCIF_TEXT;
+ for(i=0;i<dat->pageCount;i++) {
+ dat->opd[i].pTemplate=(DLGTEMPLATE *)LockResource(LoadResource(odp[i].hInstance,FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5))));
+ dat->opd[i].dlgProc=odp[i].pfnDlgProc;
+ dat->opd[i].hInst=odp[i].hInstance;
+ dat->opd[i].hwnd=NULL;
+ dat->opd[i].changed=0;
+ tci.pszText=(TCHAR*)odp[i].ptszTitle;
+ if ( dat->prof->pd->noProfiles || checkAutoCreateProfile(NULL) ) dat->currentPage=1;
+ TabCtrl_InsertItem( GetDlgItem(hwndDlg,IDC_TABS), i, &tci );
+ } }
+
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_TABS),&dat->rcDisplay);
+ TabCtrl_AdjustRect(GetDlgItem(hwndDlg,IDC_TABS),FALSE,&dat->rcDisplay);
+ {
+ POINT pt={0,0};
+ ClientToScreen(hwndDlg,&pt);
+ OffsetRect(&dat->rcDisplay,-pt.x,-pt.y);
+ }
+
+ TabCtrl_SetCurSel(GetDlgItem(hwndDlg,IDC_TABS),dat->currentPage);
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,dat->rcDisplay.left,dat->rcDisplay.top,0,0,SWP_NOSIZE);
+ { PSHNOTIFY pshn;
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return TRUE;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_WHITERECT:
+ case IDC_LOGO:
+ case IDC_NAME:
+ case IDC_DESCRIPTION:
+ SetBkColor((HDC)wParam,RGB(255,255,255));
+ return (BOOL)GetStockObject(WHITE_BRUSH);
+ }
+ break;
+ case PSM_CHANGED:
+ dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+ case PSM_FORCECHANGED:
+ { PSHNOTIFY pshn;
+ int i;
+
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ for(i=0;i<dat->pageCount;i++) {
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(dat->opd[i].hwnd!=NULL)
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_TABS:
+ switch(((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TCN_SELCHANGE:
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=TabCtrl_GetCurSel(GetDlgItem(hwndDlg,IDC_TABS));
+ if(dat->currentPage!=-1) {
+ if(dat->opd[dat->currentPage].hwnd==NULL) {
+ PSHNOTIFY pshn;
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,dat->rcDisplay.left,dat->rcDisplay.top,0,0,SWP_NOSIZE);
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ EndDialog(hwndDlg,0);
+ break;
+ }
+ case IDOK:
+ {
+ int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ if(dat->currentPage!=-1) {
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ if ( GetWindowLong(dat->opd[i].hwnd,DWL_MSGRESULT) == PSNRET_INVALID_NOCHANGEPAGE) {
+ TabCtrl_SetCurSel(GetDlgItem(hwndDlg,IDC_TABS),i);
+ if(dat->currentPage!=-1) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ }
+ }
+ EndDialog(hwndDlg,1);
+ break;
+ }
+ }
+ break;
+ case WM_DESTROY:
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDC_WHITERECT,WM_GETFONT,0,0),0);
+ DeleteObject(dat->hBoldFont);
+ { int i;
+ for(i=0;i<dat->pageCount;i++)
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ }
+ mir_free(dat->opd);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int AddProfileManagerPage(struct DetailsPageInit * opi, OPTIONSDIALOGPAGE * odp)
+{
+ if(opi==NULL||odp==NULL);
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)) return 1;
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ opi->odp[opi->pageCount].cbSize=sizeof(OPTIONSDIALOGPAGE);
+ opi->odp[opi->pageCount].hInstance=odp->hInstance;
+ opi->odp[opi->pageCount].pfnDlgProc=odp->pfnDlgProc;
+ opi->odp[opi->pageCount].position=odp->position;
+ opi->odp[opi->pageCount].ptszTitle=LangPackPcharToTchar(odp->pszTitle);
+ if((DWORD)odp->pszTemplate&0xFFFF0000) opi->odp[opi->pageCount].pszTemplate=mir_strdup(odp->pszTemplate);
+ else opi->odp[opi->pageCount].pszTemplate=odp->pszTemplate;
+ opi->odp[opi->pageCount].pszGroup=NULL;
+ opi->odp[opi->pageCount].groupPosition=odp->groupPosition;
+ opi->odp[opi->pageCount].hGroupIcon=odp->hGroupIcon;
+ opi->odp[opi->pageCount].hIcon=odp->hIcon;
+ opi->pageCount++;
+ return 0;
+}
+
+
+int getProfileManager(PROFILEMANAGERDATA * pd)
+{
+ PROPSHEETHEADER psh;
+ struct DlgProfData prof;
+ struct DetailsPageInit opi;
+ int rc=0;
+ int i;
+
+ opi.pageCount=0;
+ opi.odp=NULL;
+
+ { // remember what the default profile is, if any.
+ char defaultProfile[MAX_PATH];
+ GetPrivateProfileStringA("Database", "DefaultProfile", "", defaultProfile, SIZEOF(defaultProfile), mirandabootini);
+ ExpandEnvironmentStringsA(defaultProfile, szDefaultMirandaProfile, SIZEOF(szDefaultMirandaProfile));
+ }
+
+ {
+ OPTIONSDIALOGPAGE odp;
+ ZeroMemory(&odp,sizeof(odp));
+ odp.cbSize=sizeof(odp);
+ odp.pszTitle=Translate("My Profiles");
+ odp.pfnDlgProc=DlgProfileSelect;
+ odp.pszTemplate=MAKEINTRESOURCEA(IDD_PROFILE_SELECTION);
+ odp.hInstance=GetModuleHandle(NULL);
+ AddProfileManagerPage(&opi, &odp);
+
+ odp.pszTitle=Translate("New Profile");
+ odp.pszTemplate=MAKEINTRESOURCEA(IDD_PROFILE_NEW);
+ odp.pfnDlgProc=DlgProfileNew;
+ AddProfileManagerPage(&opi, &odp);
+ }
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = 0;
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp;
+ prof.pd=pd;
+ prof.psh=&psh;
+ rc=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_PROFILEMANAGER),NULL,DlgProfileManager,(LPARAM)&prof);
+
+ if (rc != -1)
+ {
+ for(i=0;i<opi.pageCount;i++)
+ {
+ mir_free((char*)opi.odp[i].pszTitle);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ }
+ if ( opi.odp != NULL )
+ mir_free(opi.odp);
+
+ return rc;
+}
diff --git a/miranda-wine/src/modules/database/profilemanager.h b/miranda-wine/src/modules/database/profilemanager.h new file mode 100644 index 0000000..5cf9191 --- /dev/null +++ b/miranda-wine/src/modules/database/profilemanager.h @@ -0,0 +1,37 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+typedef struct {
+ char * szProfile; // in/out
+ char * szProfileDir; // in/out
+ BOOL noProfiles; // in
+ BOOL newProfile; // out
+ DATABASELINK * dblink; // out
+} PROFILEMANAGERDATA;
+
+int InitTime(void);
+int makeDatabase(char * profile, DATABASELINK * link, HWND hwndDlg);
+int getProfileManager(PROFILEMANAGERDATA * pd);
+int getProfilePath(char * buf, size_t cch);
+int isValidProfileName(char * name);
+
diff --git a/miranda-wine/src/modules/findadd/findadd.c b/miranda-wine/src/modules/findadd/findadd.c new file mode 100644 index 0000000..966152e --- /dev/null +++ b/miranda-wine/src/modules/findadd/findadd.c @@ -0,0 +1,902 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+// TODO: Remove this
+#include <m_icq.h>
+#include "findadd.h"
+
+#define TIMERID_THROBBER 111
+
+#define HM_SEARCHACK (WM_USER+10)
+#define M_SETGROUPVISIBILITIES (WM_USER+11)
+
+static HWND hwndFindAdd=NULL;
+static HANDLE hHookModulesLoaded = 0;
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam);
+
+wchar_t* a2u( char* src );
+
+void ListView_SetItemTextA( HWND hwndLV, int i, int iSubItem, char* pszText )
+{
+ LV_ITEMA _ms_lvi;
+ _ms_lvi.iSubItem = iSubItem;
+ _ms_lvi.pszText = pszText;
+ SendMessageA( hwndLV, LVM_SETITEMTEXTA, i, (LPARAM)&_ms_lvi);
+}
+
+// from msn_libstr.cpp
+static char* FindAddTrimR(char *s) {
+ char* p = s+strlen(s)-1;
+
+ while (p>=s) {
+ if (*p!=' '&&*p!='\t'&&*p!='\n'&&*p!='\r')
+ break;
+ *p--=0;
+ }
+ return s;
+}
+
+static int FindAddDlgResizer(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc)
+{
+ static int y,nextY,oldTop;
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)lParam;
+ switch(urc->wId) {
+ case IDC_RESULTS:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ case IDOK:
+ dat->minDlgHeight=nextY+urc->rcItem.bottom-urc->rcItem.top;
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDC_ADD:
+ case IDC_MOREOPTIONS:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM;
+ case IDC_STATUSBAR:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_PROTOIDGROUP: //the resize is always processed in template order
+ nextY=y=urc->rcItem.top;
+ if(dat->showProtoId) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ break;
+ case IDC_EMAILGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showEmail) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_NAMEGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showName) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_ADVANCEDGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showAdvanced) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_BYEMAIL:
+ case IDC_EMAIL:
+ case IDC_BYNAME:
+ case IDC_STNAMENICK:
+ case IDC_STNAMEFIRST:
+ case IDC_STNAMELAST:
+ case IDC_NAMENICK:
+ case IDC_NAMEFIRST:
+ case IDC_NAMELAST:
+ case IDC_BYADVANCED:
+ case IDC_ADVANCED:
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+static void RenderThrobber(HDC hdc,RECT *rcItem,int *throbbing,int *pivot)
+{
+ HBRUSH hBr;
+ HDC hMemDC;
+ HBITMAP hBitmap;
+ HPEN hPen;
+ RECT rc;
+ int x,width,height,height2;
+
+ InflateRect(rcItem,-1,0);
+ width=rcItem->right-rcItem->left;
+ height=rcItem->bottom-rcItem->top;
+ height2=height/2;
+
+ if (*throbbing)
+ {
+ /* create memdc */
+ hMemDC=CreateCompatibleDC(0);
+ hBitmap=SelectObject(hMemDC, CreateCompatibleBitmap(hdc,width,height));
+ /* flush it */
+ rc.left=rc.top=0;
+ rc.right=width;
+ rc.bottom=height;
+ hBr=GetSysColorBrush(COLOR_BTNFACE);
+ FillRect(hMemDC,&rc,hBr);
+ DeleteObject(hBr);
+ /* set up the pen */
+ hPen=SelectObject(hMemDC,CreatePen(PS_SOLID,4,GetSysColor(COLOR_BTNSHADOW)));
+ /* draw everything before the pivot */
+ x=*pivot;
+ while (x>(-height))
+ {
+ MoveToEx(hMemDC,x+height2,0,NULL);
+ LineTo(hMemDC,x-height2,height);
+ x-=12;
+ } //while
+ /* draw everything after the pivot */
+ x=*pivot;
+ while (x < width+height)
+ {
+ MoveToEx(hMemDC,x+height2,0,NULL);
+ LineTo(hMemDC,x-height2,height);
+ x+=12;
+ } //while
+ /* move the pivot */
+ *pivot+=2;
+ /* reset the pivot point if it gets past the rect */
+ if (*pivot>width) *pivot=0;
+ /* put back the old pen and delete the new one */
+ DeleteObject(SelectObject(hMemDC,hPen));
+ /* cap the top and bottom */
+ hPen=SelectObject(hMemDC,CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNFACE)));
+ MoveToEx(hMemDC,0,0,NULL);
+ LineTo(hMemDC,width,0);
+ MoveToEx(hMemDC,0,height-1,NULL);
+ LineTo(hMemDC,width,height-1);
+ /* select in the old pen and delete the new pen */
+ DeleteObject(SelectObject(hMemDC,hPen));
+ /* paint to screen */
+ BitBlt(hdc,rcItem->left,rcItem->top,width,height,hMemDC,0,0,SRCCOPY);
+ /* select back in the old bitmap and delete the created one, as well as freeing the mem dc. */
+ hBitmap=SelectObject(hMemDC,hBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hMemDC);
+ } else {
+ /* just flush the DC */
+ hBr=GetSysColorBrush(COLOR_BTNFACE);
+ FillRect(hdc,rcItem,hBr);
+ DeleteObject(hBr);
+ } //if
+}
+
+static void StartThrobber(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ dat->throbbing=1;
+ SetTimer(hwndDlg,TIMERID_THROBBER,25,NULL);
+}
+
+static void StopThrobber(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ KillTimer(hwndDlg,TIMERID_THROBBER);
+ dat->throbbing=0;
+ dat->pivot=0;
+ InvalidateRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),NULL,FALSE);
+}
+
+static void ShowAdvancedSearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ char *szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+ if(szProto==NULL) return;
+ if(dat->hwndAdvSearch==NULL) {
+ RECT rc;
+ dat->hwndAdvSearch=(HWND)CallProtoService(szProto,PS_CREATEADVSEARCHUI,0,(LPARAM)hwndDlg);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ SetWindowPos(dat->hwndAdvSearch,0,rc.left,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("USER32"),"AnimateWindow");
+ if(MyAnimateWindow) {
+ MyAnimateWindow(dat->hwndAdvSearch,150,AW_ACTIVATE|AW_SLIDE|AW_HOR_POSITIVE);
+ RedrawWindow(dat->hwndAdvSearch,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ } else ShowWindow(dat->hwndAdvSearch,SW_SHOW);
+ CheckDlgButton(hwndDlg,IDC_ADVANCED,BST_CHECKED);
+}
+
+static void HideAdvancedSearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+ if(dat->hwndAdvSearch==NULL) return;
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("USER32"),"AnimateWindow");
+ if(MyAnimateWindow && IsWinVerXPPlus()) //blending is quite slow on win2k
+ MyAnimateWindow(dat->hwndAdvSearch,150,AW_HIDE|AW_BLEND);
+ else ShowWindow(dat->hwndAdvSearch,SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_ADVANCED,BST_UNCHECKED);
+}
+
+void EnableResultButtons(HWND hwndDlg,int enable)
+{
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD),enable);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),enable);
+}
+
+static void CheckSearchTypeRadioButton(HWND hwndDlg,int idControl)
+{
+ int i;
+ int controls[]={IDC_BYPROTOID,IDC_BYEMAIL,IDC_BYNAME,IDC_BYADVANCED};
+ for( i=0; i < SIZEOF(controls); i++ )
+ CheckDlgButton(hwndDlg,controls[i],idControl==controls[i]?BST_CHECKED:BST_UNCHECKED);
+}
+
+static TCHAR sttErrMsg[] = _T( "You haven't filled in the search field. Please enter a search term and try again.");
+static TCHAR sttErrTitle[] = _T( "Search" );
+
+static void SetListItemText( HWND hwndDlg, int idx, int col, char* szText )
+{
+ if ( lstrlenA( szText ))
+ ListView_SetItemTextA( GetDlgItem(hwndDlg,IDC_RESULTS), idx, col, szText );
+ else
+ ListView_SetItemText( GetDlgItem(hwndDlg,IDC_RESULTS), idx, col, TranslateT("<not specified>"));
+}
+
+static BOOL CALLBACK DlgProcFindAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int protoCount,i,netProtoCount;
+ PROTOCOLDESCRIPTOR **protos;
+ COMBOBOXEXITEM cbei;
+ char szProtoName[64];
+ HICON hIcon;
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_FINDUSER)));
+ ListView_SetExtendedListViewStyle(GetDlgItem(hwndDlg,IDC_RESULTS),LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP);
+ dat=(struct FindAddDlgData*)mir_alloc(sizeof(struct FindAddDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hResultHook=NULL;
+ dat->notSearchedYet=1;
+ dat->search=NULL;
+ dat->searchCount=0;
+ dat->iLastColumnSortIndex=1;
+ dat->bSortAscending=1;
+ dat->hBmpSortUp=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_SORTCOLUP),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
+ dat->hBmpSortDown=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_SORTCOLDOWN),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
+ dat->throbbing=0;
+ dat->pivot=0;
+ dat->hwndAdvSearch=NULL;
+ SendDlgItemMessage(hwndDlg,IDC_MOREOPTIONS,BUTTONSETARROW,1,0);
+
+ { LVCOLUMN lvc;
+ RECT rc;
+ LVITEM lvi;
+
+ GetClientRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+ lvc.pszText = TranslateT("Results");
+ lvc.cx = rc.right-1;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_RESULTS), 0, &lvc);
+ lvi.mask=LVIF_TEXT;
+ lvi.iItem=0;
+ lvi.iSubItem=0;
+ lvi.pszText=TranslateT("There are no results to display.");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_RESULTS), &lvi);
+ }
+
+ // Allocate a reasonable amount of space in the status bar
+ { int partWidth[3];
+ SIZE textSize;
+ HDC hdc;
+
+ hdc=GetDC(GetDlgItem(hwndDlg,IDC_STATUSBAR));
+ SelectObject(hdc,(HFONT)SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,WM_GETFONT,0,0));
+ GetTextExtentPoint32(hdc,TranslateT("Searching"),lstrlen(TranslateT("Searching")),&textSize);
+ partWidth[0]=textSize.cx;
+ GetTextExtentPoint32(hdc,_T("01234567890123456789"), 20, &textSize );
+ partWidth[0]+=textSize.cx;
+ ReleaseDC(GetDlgItem(hwndDlg,IDC_STATUSBAR),hdc);
+ partWidth[1]=partWidth[0]+150;
+ partWidth[2]=-1;
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_SETPARTS,SIZEOF(partWidth),(LPARAM)partWidth);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_SETTEXT,1|SBT_OWNERDRAW,0);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ }
+ {
+ char *szProto = NULL;
+ int index = 0;
+ DBVARIANT dbv={0};
+ HDC hdc;
+ SIZE textSize;
+ RECT rect;
+ int cbwidth = 0;
+ DWORD caps;
+
+ if(!DBGetContactSetting(NULL, "FindAdd", "LastSearched", &dbv))
+ szProto=(char*)dbv.pszVal;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0,netProtoCount=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ caps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if (caps&PF1_BASICSEARCH || caps&PF1_EXTSEARCH || caps&PF1_SEARCHBYEMAIL || caps&PF1_SEARCHBYNAME)
+ netProtoCount++;
+ }
+ dat->himlComboIcons=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,netProtoCount+1,netProtoCount+1);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_SETIMAGELIST,0,(LPARAM)dat->himlComboIcons);
+ cbei.mask=CBEIF_IMAGE|CBEIF_SELECTEDIMAGE|CBEIF_TEXT|CBEIF_LPARAM;
+ cbei.iItem=0;
+ hdc=GetDC(hwndDlg);
+ SelectObject(hdc,(HFONT)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,WM_GETFONT,0,0));
+ if(netProtoCount>1) {
+ cbei.pszText=TranslateT("All Networks");
+ GetTextExtentPoint32(hdc,cbei.pszText,lstrlen(cbei.pszText),&textSize);
+ if (textSize.cx>cbwidth) cbwidth = textSize.cx;
+ cbei.iImage=cbei.iSelectedImage=ImageList_AddIcon(dat->himlComboIcons,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SEARCHALL)));
+ cbei.lParam=0;
+ SendDlgItemMessageA(hwndDlg,IDC_PROTOLIST,CBEM_INSERTITEM,0,(LPARAM)&cbei);
+ cbei.iItem++;
+ }
+ for(i=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ caps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if (!(caps&PF1_BASICSEARCH) && !(caps&PF1_EXTSEARCH) && !(caps&PF1_SEARCHBYEMAIL) && !(caps&PF1_SEARCHBYNAME))
+ continue;
+ CallProtoService(protos[i]->szName,PS_GETNAME,SIZEOF(szProtoName),(LPARAM)szProtoName);
+ #if !defined( _UNICODE )
+ cbei.pszText=(char*)szProtoName;
+ #else
+ { TCHAR wszProtoName[ 64 ];
+ MultiByteToWideChar( CP_ACP, 0, szProtoName, 64, wszProtoName, 64 );
+ cbei.pszText = wszProtoName;
+ }
+ #endif
+ GetTextExtentPoint32(hdc,cbei.pszText,lstrlen(cbei.pszText),&textSize);
+ if (textSize.cx>cbwidth) cbwidth = textSize.cx;
+ hIcon=(HICON)CallProtoService(protos[i]->szName,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ cbei.iImage=cbei.iSelectedImage=ImageList_AddIcon(dat->himlComboIcons,hIcon);
+ DestroyIcon(hIcon);
+ cbei.lParam=(LPARAM)protos[i]->szName;
+ SendDlgItemMessageA(hwndDlg,IDC_PROTOLIST,CBEM_INSERTITEM,0,(LPARAM)&cbei);
+ if (szProto && cbei.pszText && !lstrcmpA(szProto,szProtoName)) index=cbei.iItem;
+ cbei.iItem++;
+ }
+ cbwidth+=32;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rect);
+ if ((rect.right-rect.left)<cbwidth)
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETDROPPEDWIDTH,cbwidth,0);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETCURSEL,index,0);
+ DBFreeVariant(&dbv); /* free string szProto was fetched with */
+ }
+ SendMessage(hwndDlg,M_SETGROUPVISIBILITIES,0,0);
+ Utils_RestoreWindowPosition(hwndDlg,NULL,"FindAdd","");
+ return TRUE;
+ }
+ case WM_SIZE:
+ { UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=GetModuleHandle(NULL);
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_FINDADD);
+ urd.lParam=(LPARAM)dat;
+ urd.pfnResizer=FindAddDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,WM_SIZE,0,0);
+ if(dat->notSearchedYet) {
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ ListView_SetColumnWidth(GetDlgItem(hwndDlg,IDC_RESULTS),0,rc.right);
+ }
+ }
+ //fall through
+ case WM_MOVE:
+ { RECT rc;
+ if(dat->hwndAdvSearch==NULL) break;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ SetWindowPos(dat->hwndAdvSearch,0,rc.left,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ break;
+ }
+ case WM_GETMINMAXINFO:
+ { MINMAXINFO *mmi=(MINMAXINFO*)lParam;
+ RECT rc,rc2;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ GetWindowRect(hwndDlg,&rc2);
+ mmi->ptMinTrackSize.x=rc.left-rc2.left+10+GetSystemMetrics(SM_CXFRAME);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),&rc);
+ mmi->ptMinTrackSize.x+=rc.right+5;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_ADD),&rc);
+ mmi->ptMinTrackSize.x+=rc.right+5;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),&rc);
+ mmi->ptMinTrackSize.y=dat->minDlgHeight+20+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYFRAME);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),&rc);
+ mmi->ptMinTrackSize.y+=rc.bottom;
+ return 0;
+ }
+ case M_SETGROUPVISIBILITIES:
+ { char *szProto;
+ int protoCount,i;
+ PROTOCOLDESCRIPTOR **protos;
+ DWORD protoCaps;
+ MINMAXINFO mmi;
+ RECT rc;
+ int checkmarkVisible;
+
+ dat->showAdvanced=dat->showEmail=dat->showName=dat->showProtoId=0;
+ szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if ( szProto == (char *)CB_ERR ) break;
+ if(szProto==NULL) {
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ protoCaps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if(protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1;
+ if(protoCaps&PF1_SEARCHBYNAME) dat->showName=1;
+ }
+ }
+ else {
+ protoCaps=(DWORD)CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ if(protoCaps&PF1_BASICSEARCH) dat->showProtoId=1;
+ if(protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1;
+ if(protoCaps&PF1_SEARCHBYNAME) dat->showName=1;
+ if(protoCaps&PF1_EXTSEARCHUI) dat->showAdvanced=1;
+ if(protoCaps&PF1_USERIDISEMAIL && dat->showProtoId) {dat->showProtoId=0; dat->showEmail=1;}
+ if(dat->showProtoId) {
+ char *szUniqueId;
+ szUniqueId=(char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0);
+ if(szUniqueId) {
+ #if defined( _UNICODE )
+ TCHAR* p = a2u(szUniqueId);
+ SetDlgItemText(hwndDlg,IDC_BYPROTOID,p);
+ mir_free(p);
+ #else
+ SetDlgItemTextA(hwndDlg,IDC_BYPROTOID,szUniqueId);
+ #endif
+ }
+ else SetDlgItemText(hwndDlg,IDC_BYPROTOID,TranslateT("Handle"));
+ if(protoCaps&PF1_NUMERICUSERID) SetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE)|ES_NUMBER);
+ else SetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE)&~ES_NUMBER);
+ }
+ }
+#define en(id,t) ShowWindow(GetDlgItem(hwndDlg,IDC_##id),dat->show##t?SW_SHOW:SW_HIDE)
+ en(PROTOIDGROUP,ProtoId); en(BYPROTOID,ProtoId); en(PROTOID,ProtoId);
+ en(EMAILGROUP,Email); en(BYEMAIL,Email); en(EMAIL,Email);
+ en(NAMEGROUP,Name); en(BYNAME,Name);
+ en(STNAMENICK,Name); en(NAMENICK,Name);
+ en(STNAMEFIRST,Name); en(NAMEFIRST,Name);
+ en(STNAMELAST,Name); en(NAMELAST,Name);
+ en(ADVANCEDGROUP,Advanced); en(BYADVANCED,Advanced); en(ADVANCED,Advanced);
+#undef en
+ checkmarkVisible=(dat->showAdvanced && IsDlgButtonChecked(hwndDlg,IDC_BYADVANCED)) ||
+ (dat->showEmail && IsDlgButtonChecked(hwndDlg,IDC_BYEMAIL)) ||
+ (dat->showName && IsDlgButtonChecked(hwndDlg,IDC_BYNAME)) ||
+ (dat->showProtoId && IsDlgButtonChecked(hwndDlg,IDC_BYPROTOID));
+ if(!checkmarkVisible) {
+ if(dat->showProtoId) CheckSearchTypeRadioButton(hwndDlg,IDC_BYPROTOID);
+ else if(dat->showEmail) CheckSearchTypeRadioButton(hwndDlg,IDC_BYEMAIL);
+ else if(dat->showName) CheckSearchTypeRadioButton(hwndDlg,IDC_BYNAME);
+ else if(dat->showAdvanced) CheckSearchTypeRadioButton(hwndDlg,IDC_BYADVANCED);
+ }
+ SendMessage(hwndDlg,WM_SIZE,0,0);
+ SendMessage(hwndDlg,WM_GETMINMAXINFO,0,(LPARAM)&mmi);
+ GetWindowRect(hwndDlg,&rc);
+ if(rc.bottom-rc.top<mmi.ptMinTrackSize.y) SetWindowPos(hwndDlg,0,0,0,rc.right-rc.left,mmi.ptMinTrackSize.y,SWP_NOZORDER|SWP_NOMOVE);
+ break;
+ }
+ case WM_TIMER:
+ if(wParam==TIMERID_THROBBER) {
+ RECT rc;
+ HDC hdc;
+ int borders[3];
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_GETBORDERS,0,(LPARAM)borders);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_GETRECT,1,(LPARAM)&rc);
+ InflateRect(&rc,-borders[2]/2,-borders[1]/2);
+ hdc=GetDC(GetDlgItem(hwndDlg,IDC_STATUSBAR));
+ RenderThrobber(hdc,&rc,&dat->throbbing,&dat->pivot);
+ ReleaseDC(GetDlgItem(hwndDlg,IDC_STATUSBAR),hdc);
+ }
+ break;
+ case WM_DRAWITEM:
+ { DRAWITEMSTRUCT *dis=(DRAWITEMSTRUCT*)lParam;
+ if(dis->CtlID==IDC_STATUSBAR && dis->itemID==1) {
+ RenderThrobber(dis->hDC,&dis->rcItem,&dat->throbbing,&dat->pivot);
+ return TRUE;
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam)
+ {
+ case IDC_RESULTS:
+ switch(((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ { int count=ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS));
+ if(dat->notSearchedYet) count=0;
+ EnableResultButtons(hwndDlg,count);
+ break;
+ }
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW nmlv=(LPNMLISTVIEW)lParam;
+ HDITEM hdi;
+
+ hdi.mask=HDI_BITMAP|HDI_FORMAT;
+ hdi.fmt=HDF_LEFT|HDF_STRING;
+ Header_SetItem(ListView_GetHeader(GetDlgItem(hwndDlg,IDC_RESULTS)),dat->iLastColumnSortIndex,&hdi);
+
+ if(nmlv->iSubItem!=dat->iLastColumnSortIndex)
+ {
+ dat->bSortAscending=TRUE;
+ dat->iLastColumnSortIndex=nmlv->iSubItem;
+ }
+ else dat->bSortAscending=!dat->bSortAscending;
+
+ hdi.fmt=HDF_LEFT|HDF_BITMAP|HDF_STRING|HDF_BITMAP_ON_RIGHT;
+ hdi.hbm=dat->bSortAscending?dat->hBmpSortDown:dat->hBmpSortUp;
+ Header_SetItem(ListView_GetHeader(GetDlgItem(hwndDlg,IDC_RESULTS)),dat->iLastColumnSortIndex,&hdi);
+
+ ListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS), SearchResultsCompareFunc, (LPARAM)dat);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_PROTOLIST:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ if(dat->hwndAdvSearch) {
+ DestroyWindow(dat->hwndAdvSearch);
+ dat->hwndAdvSearch=NULL;
+ }
+ SendMessage(hwndDlg,M_SETGROUPVISIBILITIES,0,0);
+ }
+ break;
+ case IDC_BYPROTOID:
+ case IDC_BYEMAIL:
+ case IDC_BYNAME:
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ break;
+ case IDC_PROTOID:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYPROTOID);
+ }
+ break;
+ case IDC_EMAIL:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYEMAIL);
+ }
+ break;
+ case IDC_NAMENICK:
+ case IDC_NAMEFIRST:
+ case IDC_NAMELAST:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYNAME);
+ }
+ break;
+ case IDC_ADVANCED:
+ if(IsDlgButtonChecked(hwndDlg,IDC_ADVANCED))
+ ShowAdvancedSearchDlg(hwndDlg,dat);
+ else
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYADVANCED);
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDOK:
+ { char *szProto;
+
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ if(dat->searchCount) { //cancel search
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("&Search"));
+ if(dat->hResultHook) {UnhookEvent(dat->hResultHook); dat->hResultHook=NULL;}
+ if(dat->search) {mir_free(dat->search); dat->search=NULL;}
+ dat->searchCount=0;
+ StopThrobber(hwndDlg,dat);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ break;
+ }
+ szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if(dat->search) {mir_free(dat->search); dat->search=NULL;}
+ dat->searchCount=0;
+ dat->hResultHook=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_SEARCHACK);
+ if(IsDlgButtonChecked(hwndDlg,IDC_BYPROTOID)) {
+ char str[256];
+ GetDlgItemTextA(hwndDlg,IDC_PROTOID,str,SIZEOF(str));
+ FindAddTrimR(str);
+ if(str[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_BASICSEARCH,PF1_BASICSEARCH,str);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYEMAIL)) {
+ char str[256];
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,str,SIZEOF(str));
+ FindAddTrimR(str);
+ if(str[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYEMAIL,PF1_SEARCHBYEMAIL,str);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYNAME)) {
+ char nick[256],first[256],last[256];
+ PROTOSEARCHBYNAME psbn;
+ GetDlgItemTextA(hwndDlg,IDC_NAMENICK,nick,SIZEOF(nick));
+ GetDlgItemTextA(hwndDlg,IDC_NAMEFIRST,first,SIZEOF(first));
+ GetDlgItemTextA(hwndDlg,IDC_NAMELAST,last,SIZEOF(last));
+ psbn.pszFirstName=first;
+ psbn.pszLastName=last;
+ psbn.pszNick=nick;
+ if(nick[0]==0 && first[0]==0 && last[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYNAME,PF1_SEARCHBYNAME,&psbn);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYADVANCED)) {
+ if(dat->hwndAdvSearch==NULL)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYADVANCED,PF1_EXTSEARCHUI,dat->hwndAdvSearch);
+ }
+
+ if(dat->searchCount==0) {
+ if(dat->hResultHook) {UnhookEvent(dat->hResultHook); dat->hResultHook=NULL;}
+ break;
+ }
+
+ dat->notSearchedYet=0;
+ FreeSearchResults(GetDlgItem(hwndDlg,IDC_RESULTS));
+
+ CreateResultsColumns(GetDlgItem(hwndDlg,IDC_RESULTS),dat,szProto);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ SetStatusBarResultInfo(hwndDlg,dat);
+ StartThrobber(hwndDlg,dat);
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("Cancel"));
+ break;
+ }
+ case IDC_ADD:
+ { LVITEM lvi;
+ struct ListSearchResult *lsr;
+ ADDCONTACTSTRUCT acs;
+
+ if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED);
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+
+ acs.handle=NULL;
+ acs.handleType=HANDLE_SEARCHRESULT;
+ acs.szProto=lsr->szProto;
+ acs.psr=&lsr->psr;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ break;
+ }
+ case IDC_MOREOPTIONS:
+ { RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),&rc);
+ ShowMoreOptionsMenu(hwndDlg,rc.left,rc.bottom);
+ break;
+ }
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { POINT pt;
+ LVHITTESTINFO lvhti;
+
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ lvhti.pt=pt;
+ ScreenToClient(hwndDlg,&pt);
+ switch(GetDlgCtrlID(ChildWindowFromPoint(hwndDlg,pt))) {
+ case IDC_RESULTS:
+ if(dat->notSearchedYet) return TRUE;
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_RESULTS),&lvhti.pt);
+ if(ListView_HitTest(GetDlgItem(hwndDlg,IDC_RESULTS),&lvhti)==-1) break;
+ ShowMoreOptionsMenu(hwndDlg,(short)LOWORD(lParam),(short)HIWORD(lParam));
+ return TRUE;
+ }
+ break;
+ }
+ case HM_SEARCHACK:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ int i;
+
+ if(ack->type!=ACKTYPE_SEARCH) break;
+ for(i=0;i<dat->searchCount;i++)
+ if(dat->search[i].hProcess==ack->hProcess && dat->search[i].hProcess != NULL && !lstrcmpA(dat->search[i].szProto,ack->szModule)) break;
+ if(i==dat->searchCount) break;
+ if(ack->result==ACKRESULT_SUCCESS) {
+ dat->searchCount--;
+ memmove(dat->search+i,dat->search+i+1,sizeof(struct ProtoSearchInfo)*(dat->searchCount-i));
+ if(dat->searchCount==0) {
+ mir_free(dat->search);
+ dat->search=NULL;
+ UnhookEvent(dat->hResultHook);
+ dat->hResultHook=NULL;
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("&Search"));
+ StopThrobber(hwndDlg,dat);
+ }
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ }
+ else if(ack->result==ACKRESULT_DATA) {
+ LVITEM lvi={0};
+ int i,col;
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)ack->lParam;
+ struct ListSearchResult *lsr;
+ char *szComboProto;
+ COMBOBOXEXITEM cbei={0};
+
+ lsr=(struct ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult,psr)+psr->cbSize);
+ lsr->szProto=ack->szModule;
+ CopyMemory(&lsr->psr,psr,psr->cbSize);
+ lsr->psr.email=psr->email==NULL?NULL:mir_strdup(psr->email);
+ lsr->psr.nick=psr->nick==NULL?NULL:mir_strdup(psr->nick);
+ lsr->psr.firstName=psr->firstName==NULL?NULL:mir_strdup(psr->firstName);
+ lsr->psr.lastName=psr->lastName==NULL?NULL:mir_strdup(psr->lastName);
+ lvi.mask = LVIF_PARAM|LVIF_IMAGE;
+ lvi.lParam=(LPARAM)lsr;
+ for(i=SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ szComboProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,i,0);
+ if(szComboProto==NULL) continue;
+ if(!lstrcmpA(szComboProto,ack->szModule)) {
+ cbei.mask=CBEIF_IMAGE;
+ cbei.iItem=i;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_GETITEM,0,(LPARAM)&cbei);
+ lvi.iImage=cbei.iImage;
+ }
+ }
+ i=ListView_InsertItem(GetDlgItem(hwndDlg,IDC_RESULTS), &lvi);
+ col=1;
+ SetListItemText(hwndDlg, i, col++, psr->nick );
+ SetListItemText(hwndDlg, i, col++, psr->firstName );
+ SetListItemText(hwndDlg, i, col++, psr->lastName );
+ SetListItemText(hwndDlg, i, col++, psr->email );
+ if(!lstrcmpA(ack->szModule,"ICQ")) {
+ char str[15];
+ ICQSEARCHRESULT *isr=(ICQSEARCHRESULT*)psr;
+ wsprintfA(str, "%u", isr->uin);
+ ListView_SetItemTextA(GetDlgItem(hwndDlg,IDC_RESULTS),i,col++,str);
+ }
+ ListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS), SearchResultsCompareFunc, (LPARAM)dat);
+ SetStatusBarResultInfo(hwndDlg,dat);
+ }
+ break;
+ }
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ {
+ TCHAR *szProto;
+ int len = SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETLBTEXTLEN,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ szProto = ( TCHAR* )alloca( sizeof(TCHAR)*( len+1 ));
+ *szProto='\0';
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETLBTEXT,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),(LPARAM)szProto);
+ DBWriteContactSettingTString(NULL, "FindAdd", "LastSearched", szProto?szProto:_T(""));
+ }
+ SaveColumnSizes(GetDlgItem(hwndDlg,IDC_RESULTS));
+ if(dat->hResultHook!=NULL) UnhookEvent(dat->hResultHook);
+ FreeSearchResults(GetDlgItem(hwndDlg,IDC_RESULTS));
+ ImageList_Destroy(dat->himlComboIcons);
+ if(dat->search) mir_free(dat->search);
+ if(dat->hwndAdvSearch) {
+ DestroyWindow(dat->hwndAdvSearch);
+ dat->hwndAdvSearch=NULL;
+ }
+ DeleteObject(dat->hBmpSortDown);
+ DeleteObject(dat->hBmpSortUp);
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"FindAdd","");
+ break;
+ }
+ return FALSE;
+}
+
+static int FindAddCommand(WPARAM wParam,LPARAM lParam)
+{
+ if(IsWindow(hwndFindAdd)) {
+ ShowWindow(hwndFindAdd,SW_SHOWNORMAL);
+ SetForegroundWindow(hwndFindAdd);
+ SetFocus(hwndFindAdd);
+ }
+ else {
+ INITCOMMONCONTROLSEX icce={0};
+ int netProtoCount, protoCount, i;
+ PROTOCOLDESCRIPTOR **protos;
+
+ // Make sure we have some networks to search on. This is not ideal since
+ // this check will be repeated every time the dialog is requested, but it
+ // must be done since this service can be called from other places than the menu.
+ // One alternative would be to only create the service if we have network
+ // protocols loaded but that would delay the creation until MODULE_LOADED and
+ // that is not good either...
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0,netProtoCount=0;i<protoCount;i++)
+ if(protos[i]->type==PROTOTYPE_PROTOCOL) {
+ int protoCaps=CallProtoService(protos[i]->szName, PS_GETCAPS, PFLAGNUM_1, 0);
+ if ( protoCaps&PF1_BASICSEARCH || protoCaps&PF1_SEARCHBYEMAIL || protoCaps&PF1_SEARCHBYNAME
+ || protoCaps&PF1_EXTSEARCHUI ) netProtoCount++;
+ }
+ if (netProtoCount > 0) {
+ icce.dwSize=sizeof(icce);
+ icce.dwICC=ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icce);
+ hwndFindAdd=CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_FINDADD), NULL, DlgProcFindAdd);
+ }
+ }
+ return 0;
+}
+
+int FindAddPreShutdown(WPARAM wParam, LPARAM lParam)
+{
+ if (IsWindow(hwndFindAdd)) DestroyWindow(hwndFindAdd);
+ hwndFindAdd=NULL;
+ return 0;
+}
+
+int LoadFindAddModule(void)
+{
+
+ CreateServiceFunction(MS_FINDADD_FINDADD,FindAddCommand);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,FindAddPreShutdown);
+
+ return 0;
+}
+
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ int netProtoCount, protoCount, i;
+ PROTOCOLDESCRIPTOR **protos;
+
+ // Make sure we have some networks to search on.
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ for(i=0,netProtoCount=0;i<protoCount;i++)
+ if(protos[i]->type==PROTOTYPE_PROTOCOL) {
+ int protoCaps=CallProtoService(protos[i]->szName, PS_GETCAPS, PFLAGNUM_1, 0);
+ if ( protoCaps&PF1_BASICSEARCH || protoCaps&PF1_SEARCHBYEMAIL || protoCaps&PF1_SEARCHBYNAME
+ || protoCaps&PF1_EXTSEARCHUI ) netProtoCount++;
+ }
+
+ if (netProtoCount > 0) {
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = 500020000;
+ mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_FINDUSER));
+ mi.pszName = Translate("&Find/Add Contacts...");
+ mi.pszService = MS_FINDADD_FINDADD;
+ CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+ }
+
+ return 0;
+
+}
+
diff --git a/miranda-wine/src/modules/findadd/findadd.h b/miranda-wine/src/modules/findadd/findadd.h new file mode 100644 index 0000000..f8afb9c --- /dev/null +++ b/miranda-wine/src/modules/findadd/findadd.h @@ -0,0 +1,57 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+struct ListSearchResult {
+ const char *szProto;
+ PROTOSEARCHRESULT psr;
+};
+
+struct ProtoSearchInfo {
+ const char *szProto;
+ HANDLE hProcess;
+};
+
+struct FindAddDlgData {
+ HANDLE hResultHook;
+ int bSortAscending;
+ int iLastColumnSortIndex;
+ HIMAGELIST himlComboIcons;
+ int showProtoId,showEmail,showName,showAdvanced;
+ int minDlgHeight;
+ int notSearchedYet;
+ struct ProtoSearchInfo *search;
+ int searchCount;
+ HBITMAP hBmpSortUp,hBmpSortDown;
+ int throbbing;
+ int pivot;
+ HWND hwndAdvSearch;
+};
+
+int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+void FreeSearchResults(HWND hwndResults);
+int BeginSearch(HWND hwndDlg,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams);
+void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat);
+void SetStatusBarResultInfo(HWND hwndDlg,struct FindAddDlgData *dat);
+void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto);
+void EnableResultButtons(HWND hwndDlg,int enable);
+void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y);
+void SaveColumnSizes(HWND hwndResults);
diff --git a/miranda-wine/src/modules/findadd/searchresults.c b/miranda-wine/src/modules/findadd/searchresults.c new file mode 100644 index 0000000..025c90b --- /dev/null +++ b/miranda-wine/src/modules/findadd/searchresults.c @@ -0,0 +1,424 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+// TODO: Remove this
+#include <m_icq.h>
+#include "findadd.h"
+
+#define COLUMNID_PROTO 0
+#define COLUMNID_NICK 1
+#define COLUMNID_FIRST 2
+#define COLUMNID_LAST 3
+#define COLUMNID_EMAIL 4
+#define COLUMNID_HANDLE 5
+
+static int handleColumnAfter=COLUMNID_EMAIL;
+
+WCHAR* a2u( const char* );
+
+void SaveColumnSizes(HWND hwndResults)
+{
+ int columnOrder[COLUMNID_HANDLE+1];
+ int columnCount;
+ char szSetting[32];
+ int i;
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(GetParent(hwndResults),GWL_USERDATA);
+ columnCount=Header_GetItemCount(ListView_GetHeader(hwndResults));
+ if(columnCount<=COLUMNID_EMAIL || columnCount>COLUMNID_HANDLE+1) return;
+ ListView_GetColumnOrderArray(hwndResults,columnCount,columnOrder);
+ if(columnCount<=COLUMNID_HANDLE) {
+ if(handleColumnAfter==-1) {
+ memmove(columnOrder+1,columnOrder,sizeof(columnOrder[0])*columnCount);
+ columnOrder[0]=COLUMNID_HANDLE;
+ }
+ else {
+ for(i=0;i<columnCount;i++) {
+ if(handleColumnAfter==columnOrder[i]) {
+ memmove(columnOrder+i+2,columnOrder+i+1,sizeof(columnOrder[0])*(columnCount-i-1));
+ columnOrder[i+1]=COLUMNID_HANDLE;
+ break;
+ }
+ }
+ }
+ }
+ for(i=0;i<=COLUMNID_HANDLE;i++) {
+ wsprintfA(szSetting,"ColOrder%d",i);
+ DBWriteContactSettingByte(NULL,"FindAdd",szSetting,(BYTE)columnOrder[i]);
+ if(i>=columnCount) continue;
+ wsprintfA(szSetting,"ColWidth%d",i);
+ DBWriteContactSettingWord(NULL,"FindAdd",szSetting,(WORD)ListView_GetColumnWidth(hwndResults,i));
+ }
+ DBWriteContactSettingByte(NULL,"FindAdd","SortColumn",(BYTE)dat->iLastColumnSortIndex);
+ DBWriteContactSettingByte(NULL,"FindAdd","SortAscending",(BYTE)dat->bSortAscending);
+}
+
+static const TCHAR *szColumnNames[] = { NULL, _T("Nick"), _T("First Name"), _T("Last Name"), _T("E-mail"), NULL };
+static int defaultColumnSizes[]={0,100,100,100,200,90};
+void LoadColumnSizes(HWND hwndResults,const char *szProto)
+{
+ HDITEM hdi;
+ int columnOrder[COLUMNID_HANDLE+1];
+ int columnCount;
+ char szSetting[32];
+ int i;
+ struct FindAddDlgData *dat;
+ int colOrdersValid;
+
+ defaultColumnSizes[COLUMNID_PROTO]=GetSystemMetrics(SM_CXSMICON)+4;
+ dat=(struct FindAddDlgData*)GetWindowLong(GetParent(hwndResults),GWL_USERDATA);
+
+ if(szProto && !lstrcmpA(szProto,"ICQ"))
+ columnCount=COLUMNID_HANDLE+1;
+ else
+ columnCount=COLUMNID_EMAIL+1;
+
+ colOrdersValid=1;
+ for(i=0;i<=COLUMNID_HANDLE;i++) {
+ LVCOLUMN lvc;
+ if( i < columnCount ) {
+ int bNeedsFree = FALSE;
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+ if( szColumnNames[i] != NULL )
+ lvc.pszText = TranslateTS( szColumnNames[i] );
+ else if( i == COLUMNID_HANDLE ) {
+ #if defined( _UNICODE )
+ bNeedsFree = TRUE;
+ lvc.pszText = a2u((char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0));
+ #else
+ lvc.pszText = (char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0);
+ #endif
+ }
+ else lvc.mask &= ~LVCF_TEXT;
+ wsprintfA(szSetting,"ColWidth%d",i);
+ lvc.cx = DBGetContactSettingWord(NULL,"FindAdd",szSetting,defaultColumnSizes[i]);
+ ListView_InsertColumn( hwndResults, i, (LPARAM)&lvc );
+ #if defined( _UNICODE )
+ if ( bNeedsFree )
+ mir_free(lvc.pszText);
+ #endif
+ }
+ wsprintfA(szSetting,"ColOrder%d",i);
+ columnOrder[i]=DBGetContactSettingByte(NULL,"FindAdd",szSetting,-1);
+ if(columnOrder[i]==-1) colOrdersValid=0;
+ if(columnOrder[i]==COLUMNID_HANDLE) handleColumnAfter=i?columnOrder[i-1]:-1;
+ }
+ if(colOrdersValid) {
+ if(columnCount<=COLUMNID_HANDLE)
+ for(i=0;i<columnCount;i++)
+ if(columnOrder[i]==COLUMNID_HANDLE) {
+ memmove(columnOrder+i,columnOrder+i+1,sizeof(columnOrder[0])*(columnCount-i));
+ break;
+ }
+ ListView_SetColumnOrderArray(hwndResults,columnCount,columnOrder);
+ }
+ else handleColumnAfter=COLUMNID_EMAIL;
+
+ dat->iLastColumnSortIndex=DBGetContactSettingByte(NULL,"FindAdd","SortColumn",COLUMNID_NICK);
+ if(dat->iLastColumnSortIndex>=columnCount) dat->iLastColumnSortIndex=COLUMNID_NICK;
+ dat->bSortAscending=DBGetContactSettingByte(NULL,"FindAdd","SortAscending",TRUE);
+
+ hdi.mask=HDI_BITMAP|HDI_FORMAT;
+ hdi.fmt=HDF_LEFT|HDF_BITMAP|HDF_STRING|HDF_BITMAP_ON_RIGHT;
+ hdi.hbm=dat->bSortAscending?dat->hBmpSortDown:dat->hBmpSortUp;
+ Header_SetItem(ListView_GetHeader(hwndResults),dat->iLastColumnSortIndex,&hdi);
+}
+
+int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ struct FindAddDlgData *dat=(struct FindAddDlgData*)lParamSort;
+ int sortMultiplier;
+ int sortCol;
+ struct ListSearchResult *lsr1=(struct ListSearchResult*)lParam1,*lsr2=(struct ListSearchResult*)lParam2;
+
+ sortMultiplier=dat->bSortAscending?1:-1;
+ sortCol=dat->iLastColumnSortIndex;
+ if ( lsr1 == NULL || lsr2 == NULL ) return 0;
+ switch(sortCol)
+ {
+ case COLUMNID_PROTO:
+ return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier;
+ case COLUMNID_NICK:
+ return lstrcmpiA(lsr1->psr.nick, lsr2->psr.nick)*sortMultiplier;
+ case COLUMNID_FIRST:
+ return lstrcmpiA(lsr1->psr.firstName, lsr2->psr.firstName)*sortMultiplier;
+ case COLUMNID_LAST:
+ return lstrcmpiA(lsr1->psr.lastName, lsr2->psr.lastName)*sortMultiplier;
+ case COLUMNID_EMAIL:
+ return lstrcmpiA(lsr1->psr.email, lsr2->psr.email)*sortMultiplier;
+ case COLUMNID_HANDLE:
+ if(!lstrcmpA(lsr1->szProto,lsr2->szProto)) {
+ if(!lstrcmpA(lsr1->szProto,"ICQ")) {
+ if(((ICQSEARCHRESULT*)&lsr1->psr)->uin<((ICQSEARCHRESULT*)&lsr2->psr)->uin) return -sortMultiplier;
+ return sortMultiplier;
+ }
+ else return 0;
+ }
+ else return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier;
+ }
+ return 0;
+}
+
+void FreeSearchResults(HWND hwndResults)
+{
+ LV_ITEM lvi;
+ struct ListSearchResult *lsr;
+ for(lvi.iItem=ListView_GetItemCount(hwndResults)-1;lvi.iItem>=0;lvi.iItem--) {
+ lvi.mask=LVIF_PARAM;
+ ListView_GetItem(hwndResults,&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ if(lsr==NULL) continue;
+ mir_free(lsr->psr.email);
+ mir_free(lsr->psr.nick);
+ mir_free(lsr->psr.firstName);
+ mir_free(lsr->psr.lastName);
+ mir_free(lsr);
+ }
+ ListView_DeleteAllItems(hwndResults);
+ EnableResultButtons(GetParent(hwndResults),0);
+}
+
+// on its own thread
+static void BeginSearchFailed(void * arg)
+{
+ TCHAR buf[128];
+ if ( arg != NULL ) {
+ TCHAR* protoName = LangPackPcharToTchar(( const char* )arg );
+ mir_sntprintf(buf,SIZEOF(buf),TranslateT("Could not start a search on '%s', there was a problem - is %s connected?"),protoName,protoName);
+ mir_free((char*)arg);
+ }
+ else lstrcpyn(buf,TranslateT("Could not search on any of the protocols, are you online?"),SIZEOF(buf));
+ MessageBox(0,buf,TranslateT("Problem with search"),MB_OK | MB_ICONERROR);
+}
+
+int BeginSearch(HWND hwndDlg,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams)
+{
+ int protoCount,i;
+ PROTOCOLDESCRIPTOR **protos;
+
+ if(szProto==NULL) {
+ int failures=0;
+ DWORD caps;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protos);
+ dat->searchCount=0;
+ dat->search=(struct ProtoSearchInfo*)mir_calloc(sizeof(struct ProtoSearchInfo) * protoCount);
+ for(i=0;i<protoCount;i++) {
+ if(protos[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ caps=(DWORD)CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_1,0);
+ if(!(caps&requiredCapability)) continue;
+ dat->search[dat->searchCount].hProcess=(HANDLE)CallProtoService(protos[i]->szName,szSearchService,0,(LPARAM)pvSearchParams);
+ dat->search[dat->searchCount].szProto=protos[i]->szName;
+ if(dat->search[dat->searchCount].hProcess==NULL) failures++;
+ else dat->searchCount++;
+ }
+ if(failures) {
+ //infuriatingly vague error message. fixme.
+ if(dat->searchCount==0) {
+ forkthread(BeginSearchFailed,0,NULL);
+ mir_free(dat->search);
+ dat->search=NULL;
+ return 1;
+ } }
+ }
+ else {
+ dat->search=(struct ProtoSearchInfo*)mir_alloc(sizeof(struct ProtoSearchInfo));
+ dat->searchCount=1;
+ dat->search[0].hProcess=(HANDLE)CallProtoService(szProto,szSearchService,0,(LPARAM)pvSearchParams);
+ dat->search[0].szProto=szProto;
+ if(dat->search[0].hProcess==NULL) {
+ //infuriatingly vague error message. fixme.
+ forkthread(BeginSearchFailed,0,(void*)mir_strdup(szProto));
+ mir_free(dat->search);
+ dat->search=NULL;
+ dat->searchCount=0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat)
+{
+ TCHAR str[256];
+
+ if (dat->searchCount != 0 ) {
+ char szProtoName[64];
+ int i;
+
+ lstrcpy( str, TranslateT("Searching"));
+ for( i=0; i <dat->searchCount; i++ ) {
+ lstrcat(str, i ? _T(",") : _T( " " ));
+ CallProtoService(dat->search[i].szProto,PS_GETNAME,SIZEOF(szProtoName),(LPARAM)szProtoName);
+ #if !defined( _UNICODE )
+ lstrcatA( str, szProtoName );
+ #else
+ { TCHAR* p = a2u(szProtoName);
+ lstrcat(str, p);
+ mir_free(p);
+ }
+ #endif
+ } }
+ else lstrcpy(str, TranslateT("Idle"));
+
+ SendMessage( hwndStatus, SB_SETTEXT, 0, (LPARAM)str );
+}
+
+struct ProtoResultsSummary {
+ const char *szProto;
+ int count;
+};
+void SetStatusBarResultInfo(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ HWND hwndStatus=GetDlgItem(hwndDlg,IDC_STATUSBAR);
+ HWND hwndResults=GetDlgItem(hwndDlg,IDC_RESULTS);
+ LV_ITEM lvi;
+ struct ListSearchResult *lsr;
+ struct ProtoResultsSummary *subtotal=NULL;
+ int subtotalCount=0;
+ int i,total;
+ TCHAR str[256];
+
+ total=ListView_GetItemCount(hwndResults);
+ for(lvi.iItem=total-1;lvi.iItem>=0;lvi.iItem--) {
+ lvi.mask=LVIF_PARAM;
+ ListView_GetItem(hwndResults,&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ if(lsr==NULL) continue;
+ for(i=0;i<subtotalCount;i++) {
+ if(subtotal[i].szProto==lsr->szProto) {
+ subtotal[i].count++;
+ break;
+ }
+ }
+ if(i==subtotalCount) {
+ subtotal=(struct ProtoResultsSummary*)mir_realloc(subtotal,sizeof(struct ProtoResultsSummary)*(subtotalCount+1));
+ subtotal[subtotalCount].szProto=lsr->szProto;
+ subtotal[subtotalCount++].count=1;
+ }
+ }
+ if ( total != 0 ) {
+ char szProtoName[64];
+ TCHAR substr[64];
+ TCHAR* ptszProto;
+
+ CallProtoService( subtotal[0].szProto, PS_GETNAME, SIZEOF(szProtoName), (LPARAM)szProtoName );
+ #if defined( _UNICODE )
+ ptszProto = a2u( szProtoName );
+ #else
+ ptszProto = szProtoName;
+ #endif
+
+ if ( subtotalCount == 1 ) {
+ if(total==1) mir_sntprintf( str, SIZEOF(str), TranslateT("1 %s user found"), ptszProto );
+ else mir_sntprintf( str, SIZEOF(str), TranslateT("%d %s users found"), total, ptszProto );
+ }
+ else {
+ mir_sntprintf( str, SIZEOF(str), TranslateT("%d users found ("),total);
+ for( i=0; i < subtotalCount; i++ ) {
+ if(i) {
+ CallProtoService(subtotal[i].szProto,PS_GETNAME,SIZEOF(szProtoName),(LPARAM)szProtoName);
+ #if defined( _UNICODE )
+ mir_free( ptszProto );
+ ptszProto = a2u( szProtoName );
+ #else
+ ptszProto = szProtoName;
+ #endif
+ lstrcat( str, _T(", "));
+ }
+ mir_sntprintf( substr, SIZEOF(substr), _T("%d %s"), subtotal[i].count, ptszProto );
+ lstrcat( str, substr );
+ }
+ lstrcat( str, _T(")"));
+ }
+ mir_free(subtotal);
+ #if defined( _UNICODE )
+ mir_free( ptszProto );
+ #endif
+ }
+ else lstrcpy(str, TranslateT("No users found"));
+ SendMessage(hwndStatus, SB_SETTEXT, 2, (LPARAM)str );
+}
+
+void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto)
+{
+ SaveColumnSizes(hwndResults);
+ while(ListView_DeleteColumn(hwndResults,0));
+ ListView_SetImageList(hwndResults,dat->himlComboIcons,LVSIL_SMALL);
+ LoadColumnSizes(hwndResults,szProto);
+}
+
+void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y)
+{
+ struct FindAddDlgData *dat;
+ HMENU hPopupMenu,hMenu;
+ int commandId;
+ struct ListSearchResult *lsr;
+
+ dat=(struct FindAddDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ { LVITEM lvi;
+ if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) return;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED);
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ }
+
+ hMenu=LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CONTEXT));
+ hPopupMenu=GetSubMenu(hMenu,4);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hPopupMenu,0);
+ commandId=TrackPopupMenu(hPopupMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,x,y,0,hwndDlg,NULL);
+ if(commandId) {
+ switch(commandId) {
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs;
+
+ acs.handle=NULL;
+ acs.handleType=HANDLE_SEARCHRESULT;
+ acs.szProto=lsr->szProto;
+ acs.psr=&lsr->psr;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ break;
+ }
+ case IDC_DETAILS:
+ { HANDLE hContact;
+ hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr);
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hContact,0);
+ break;
+ }
+ case IDC_SENDMESSAGE:
+ { HANDLE hContact;
+ hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr);
+ CallService(MS_MSG_SENDMESSAGE,(WPARAM)hContact,(LPARAM)(const char*)NULL);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ DestroyMenu(hPopupMenu);
+ DestroyMenu(hMenu);
+}
+
diff --git a/miranda-wine/src/modules/help/about.c b/miranda-wine/src/modules/help/about.c new file mode 100644 index 0000000..9116d54 --- /dev/null +++ b/miranda-wine/src/modules/help/about.c @@ -0,0 +1,143 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#if defined( _UNICODE )
+ #define STR_VERSION_FORMAT "%s %S"
+#else
+ #define STR_VERSION_FORMAT "%s %s"
+#endif
+
+BOOL CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iState = 0;
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { int h;
+ LOGFONT lf;
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_GETFONT,0,0);
+ int iState=0;
+ GetObject(hFont,sizeof(lf),&lf);
+ h=lf.lfHeight;
+ lf.lfHeight=(int)(lf.lfHeight*1.5);
+ lf.lfWeight=FW_BOLD;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_SETFONT,(WPARAM)hFont,0);
+ lf.lfHeight=h;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_SETFONT,(WPARAM)hFont,0);
+ }
+ {
+ char filename[MAX_PATH],*productCopyright;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSizeA(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo);
+ VerQueryValueA(pVerInfo,"\\StringFileInfo\\000004b0\\LegalCopyright",(void*)&productCopyright,&blockSize);
+ SetDlgItemTextA(hwndDlg,IDC_DEVS,productCopyright);
+ mir_free(pVerInfo);
+ }
+ { char productVersion[56];
+ TCHAR str[64];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(productVersion),(LPARAM)productVersion);
+ mir_sntprintf(str,SIZEOF(str),_T(STR_VERSION_FORMAT), TranslateT("Version"), productVersion);
+ SetDlgItemText(hwndDlg,IDC_VERSION,str);
+ mir_sntprintf(str,SIZEOF(str),TranslateT("Built %s %s"),_T(__DATE__),_T(__TIME__));
+ SetDlgItemText(hwndDlg,IDC_BUILDTIME,str);
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_HIDE);
+ { char* pszMsg = LockResource(LoadResource(GetModuleHandle(NULL),FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CREDITS),_T("TEXT"))));
+ #if defined( _UNICODE )
+ TCHAR* ptszMsg = alloca(2000*sizeof(TCHAR));
+ MultiByteToWideChar(1252,0,pszMsg,-1,ptszMsg,2000);
+ SetDlgItemText(hwndDlg,IDC_CREDITSFILE, ptszMsg);
+ #else
+ SetDlgItemText(hwndDlg,IDC_CREDITSFILE, pszMsg);
+ #endif
+ }
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MIRANDA)));
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_CONTRIBLINK:
+ {
+ if (iState) {
+ iState = 0;
+ SetDlgItemText(hwndDlg, IDC_CONTRIBLINK, TranslateT("Credits >"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DEVS), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BUILDTIME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_HIDE);
+ }
+ else {
+ iState = 1;
+ SetDlgItemText(hwndDlg, IDC_CONTRIBLINK, TranslateT("< About"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DEVS), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BUILDTIME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_SHOW);
+ }
+ break;
+ }
+ }
+ break;
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ if((HWND)lParam==GetDlgItem(hwndDlg,IDC_WHITERECT)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_MIRANDA)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_VERSION)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_BUILDTIME)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_LOGO)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_CREDITSFILE)
+ || (HWND)lParam==GetDlgItem(hwndDlg,IDC_DEVS)) {
+ if((HWND)lParam==GetDlgItem(hwndDlg,IDC_MIRANDA))
+ SetTextColor((HDC)wParam,RGB(180,10,10));
+ else if((HWND)lParam==GetDlgItem(hwndDlg,IDC_VERSION))
+ SetTextColor((HDC)wParam,RGB(70,70,70));
+ else
+ SetTextColor((HDC)wParam,RGB(0,0,0));
+ SetBkColor((HDC)wParam,RGB(255,255,255));
+ return (BOOL)GetStockObject(WHITE_BRUSH);
+ }
+ break;
+ case WM_DESTROY:
+ { HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_GETFONT,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_MIRANDA,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDOK,WM_GETFONT,0,0),0);
+ DeleteObject(hFont);
+
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_GETFONT,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDOK,WM_GETFONT,0,0),0);
+ DeleteObject(hFont);
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/help/help.c b/miranda-wine/src/modules/help/help.c new file mode 100644 index 0000000..9646095 --- /dev/null +++ b/miranda-wine/src/modules/help/help.c @@ -0,0 +1,104 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+BOOL CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+HWND hAboutDlg=NULL;
+
+static int AboutCommand(WPARAM wParam,LPARAM lParam)
+{
+ if (IsWindow(hAboutDlg)) {
+ SetForegroundWindow(hAboutDlg);
+ SetFocus(hAboutDlg);
+ return 0;
+ }
+ hAboutDlg=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ABOUT),(HWND)wParam,DlgProcAbout);
+ return 0;
+}
+
+static int IndexCommand(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://www.miranda-im.org/support/");
+ return 0;
+}
+
+static int WebsiteCommand(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://www.miranda-im.org");
+ return 0;
+}
+
+static int BugCommand(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://bugs.miranda-im.org/");
+ return 0;
+}
+
+
+int ShutdownHelpModule(WPARAM wParam, LPARAM lParam)
+{
+ if (IsWindow(hAboutDlg)) DestroyWindow(hAboutDlg);
+ hAboutDlg=NULL;
+ return 0;
+}
+
+int LoadHelpModule(void)
+{
+ CLISTMENUITEM mi;
+
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownHelpModule);
+
+ CreateServiceFunction("Help/AboutCommand",AboutCommand);
+ CreateServiceFunction("Help/IndexCommand",IndexCommand);
+ CreateServiceFunction("Help/WebsiteCommand",WebsiteCommand);
+ CreateServiceFunction("Help/BugCommand",BugCommand);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MIRANDA));
+ mi.pszPopupName=Translate("&Help");
+ mi.popupPosition=2000090000;
+ mi.position=2000090000;
+ mi.pszName=Translate("&About...");
+ mi.pszService="Help/AboutCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HELP));
+ mi.position=-500050000;
+ mi.pszName=Translate("&Support\tF1");
+ mi.hotKey=MAKELPARAM(0,VK_F1);
+ mi.pszService="Help/IndexCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MIRANDAWEBSITE));
+ mi.position=2000050000;
+ mi.pszName=Translate("&Miranda IM Homepage");
+ mi.hotKey=0;
+ mi.pszService="Help/WebsiteCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_URL));
+ mi.position=2000040000;
+ mi.pszName=Translate("&Report Bug");
+ mi.hotKey=0;
+ mi.pszService="Help/BugCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/history/history.c b/miranda-wine/src/modules/history/history.c new file mode 100644 index 0000000..202b1c8 --- /dev/null +++ b/miranda-wine/src/modules/history/history.c @@ -0,0 +1,434 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#define SUMMARY 0
+#define DETAIL 1
+#define DM_FINDNEXT (WM_USER+10)
+#define DM_HREBUILD (WM_USER+11)
+
+static BOOL CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HANDLE hWindowList=0;
+
+static int UserHistoryCommand(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ return 0;
+ }
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_HISTORY),NULL,DlgProcHistory,wParam);
+ return 0;
+}
+
+static int HistoryContactDelete(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ hwnd=WindowList_Find(hWindowList,(HANDLE)wParam);
+ if(hwnd!=NULL) DestroyWindow(hwnd);
+ return 0;
+}
+
+int PreShutdownHistoryModule(WPARAM wParam, LPARAM lParam)
+{
+ if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0);
+ return 0;
+}
+
+int LoadHistoryModule(void)
+{
+ CLISTMENUITEM mi;
+
+ //bit of a fudge that the one service works for both global requests and
+ //the contact list's menu processing stuff
+ CreateServiceFunction(MS_HISTORY_SHOWCONTACTHISTORY,UserHistoryCommand);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=1000090000;
+ mi.flags=0;
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY));
+ mi.pszContactOwner=NULL; //all contacts
+ mi.pszName=Translate("View &History");
+ mi.pszService=MS_HISTORY_SHOWCONTACTHISTORY;
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ HookEvent(ME_DB_CONTACT_DELETED,HistoryContactDelete);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,PreShutdownHistoryModule);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Fills the events list
+
+static void GetMessageDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ char* pszSrc = ( char* )dbei->pBlob;
+ #if defined( _UNICODE )
+ unsigned len = strlen(( char* )dbei->pBlob )+1;
+ if ( dbei->cbBlob != len ) {
+ int len2 = dbei->cbBlob - len;
+ if ( len2 > cbBuf )
+ len2 = cbBuf - sizeof( TCHAR );
+
+ memcpy( buf, &dbei->pBlob[ len ], len2 );
+ return;
+ }
+ #endif
+
+ #if !defined( _UNICODE )
+ strncpy( buf, ( const char* )pszSrc, cbBuf );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )pszSrc, -1, buf, cbBuf );
+ #endif
+ buf[ cbBuf-1 ] = 0;
+}
+
+static void GetUrlDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ int len = dbei->cbBlob;
+ if ( len >= cbBuf )
+ len = cbBuf-1;
+
+ #if !defined( _UNICODE )
+ memcpy( buf, dbei->pBlob, len );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob, len, buf, cbBuf );
+ #endif
+ buf[ len ] = 0;
+
+ if ( len < cbBuf-3 )
+ _tcscat( buf, _T( "\r\n" ));
+}
+
+static void GetFileDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ int len = dbei->cbBlob - sizeof( DWORD );
+ if ( len >= cbBuf )
+ len = cbBuf-1;
+
+ #if !defined( _UNICODE )
+ memcpy( buf, dbei->pBlob + sizeof( DWORD ), len );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob + sizeof( DWORD ), len, buf, cbBuf );
+ #endif
+ buf[ len ] = 0;
+
+ if ( len < cbBuf-3 )
+ _tcscat( buf, _T( "\r\n" ));
+}
+
+static void GetObjectDescription( DBEVENTINFO *dbei, TCHAR* str, int cbStr )
+{
+ switch( dbei->eventType ) {
+ case EVENTTYPE_MESSAGE:
+ GetMessageDescription( dbei, str, cbStr );
+ break;
+
+ case EVENTTYPE_URL:
+ GetUrlDescription( dbei, str, cbStr );
+ break;
+
+ case EVENTTYPE_FILE:
+ GetFileDescription( dbei, str, cbStr );
+ break;
+
+ default:
+ str[ 0 ] = 0;
+} }
+
+static void GetObjectSummary( DBEVENTINFO *dbei, TCHAR* str, int cbStr )
+{
+ TCHAR* pszSrc;
+
+ switch( dbei->eventType ) {
+ case EVENTTYPE_MESSAGE:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing Message" );
+ else pszSrc = TranslateT( "Incoming Message" );
+ break;
+
+ case EVENTTYPE_URL:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing URL" );
+ else pszSrc = TranslateT( "Incoming URL" );
+ break;
+
+ case EVENTTYPE_FILE:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing File" );
+ else pszSrc = TranslateT( "Incoming File" );
+ break;
+
+ default:
+ str[ 0 ] = 0;
+ return;
+ }
+
+ _tcsncpy( str, ( const TCHAR* )pszSrc, cbStr );
+ str[ cbStr-1 ] = 0;
+}
+
+typedef struct {
+ HANDLE hContact;
+ HWND hwnd;
+} THistoryThread;
+
+static void FillHistoryThread(THistoryThread *hInfo)
+{
+ TCHAR str[200], eventText[256], strdatetime[64];
+ HANDLE hDbEvent;
+ DBEVENTINFO dbei;
+ int newBlobSize,oldBlobSize,i;
+ DBTIMETOSTRINGT dbtts;
+ HWND hwndList;
+
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_RESETCONTENT,0,0);
+ i=CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)hInfo->hContact,0);
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_INITSTORAGE,i,i*40);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.pBlob=NULL;
+ oldBlobSize=0;
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDLAST,(WPARAM)hInfo->hContact,0);
+ dbtts.cbDest = SIZEOF(strdatetime);
+ dbtts.szDest = strdatetime;
+ dbtts.szFormat = _T("d t");
+ hwndList=GetDlgItem(hInfo->hwnd,IDC_LIST);
+ while(hDbEvent!=NULL) {
+ if (!IsWindow(hInfo->hwnd)) break;
+ newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if(newBlobSize>oldBlobSize) {
+ dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob,newBlobSize);
+ oldBlobSize=newBlobSize;
+ }
+ dbei.cbBlob = oldBlobSize;
+ CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei );
+ GetObjectSummary(&dbei,str,SIZEOF(str));
+ if(str[0]) {
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp,( LPARAM )&dbtts );
+ mir_sntprintf( eventText, SIZEOF(eventText), _T("%s: %s"), strdatetime, str );
+ i = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)eventText );
+ SendMessage(hwndList, LB_SETITEMDATA, i, (LPARAM)hDbEvent);
+ }
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDPREV,(WPARAM)hDbEvent,0);
+ }
+ if(dbei.pBlob!=NULL) mir_free(dbei.pBlob);
+
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_SETCURSEL,0,0);
+ SendMessage(hInfo->hwnd,WM_COMMAND,MAKEWPARAM(IDC_LIST,LBN_SELCHANGE),0);
+ EnableWindow(GetDlgItem(hInfo->hwnd, IDC_LIST), TRUE);
+ mir_free(hInfo);
+}
+
+static int HistoryDlgResizer(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc) {
+ switch(urc->wId) {
+ case IDC_LIST:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ case IDC_EDIT:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_FIND:
+ case IDC_DELETEHISTORY:
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDOK:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+static BOOL CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact;
+
+ hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCHAR* contactName, str[200];
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ hContact = (HANDLE)lParam;
+ WindowList_Add(hWindowList,hwndDlg,hContact);
+ Utils_RestoreWindowPosition(hwndDlg,hContact,"History","");
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,GCDNF_TCHAR);
+ mir_sntprintf(str,SIZEOF(str),TranslateT("History for %s"),contactName);
+ SetWindowText(hwndDlg,str);
+ SendMessage(hwndDlg,WM_SETICON,ICON_BIG,(LPARAM)LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY)));
+ SendMessage(hwndDlg,DM_HREBUILD,0,0);
+ return TRUE;
+ }
+ case DM_HREBUILD:
+ {
+ THistoryThread *hInfo = (THistoryThread*)mir_alloc(sizeof(THistoryThread));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LIST), FALSE);
+ hInfo->hContact = hContact;
+ hInfo->hwnd = hwndDlg;
+ forkthread(FillHistoryThread, 0, hInfo);
+ return TRUE;
+ }
+ case WM_DESTROY:
+ {
+ Utils_SaveWindowPosition(hwndDlg,hContact,"History","");
+ WindowList_Remove(hWindowList,hwndDlg);
+ return TRUE;
+ }
+ case WM_GETMINMAXINFO:
+ {
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.x=300;
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.y=230;
+ }
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=GetModuleHandle(NULL);
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_HISTORY);
+ urd.lParam=(LPARAM)NULL;
+ urd.pfnResizer=HistoryDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_FIND:
+ ShowWindow(CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_HISTORY_FIND), hwndDlg, DlgProcHistoryFind, (LPARAM)hwndDlg), SW_SHOW);
+ return TRUE;
+ case IDC_DELETEHISTORY:
+ {
+ HANDLE hDbevent;
+ int index;
+ index = SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if(index==LB_ERR) break;
+ if (MessageBox(hwndDlg,TranslateT("Are you sure you want to delete this history item?"),TranslateT("Delete History"),MB_YESNO|MB_ICONQUESTION)==IDYES) {
+ hDbevent = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,index,0);
+ CallService(MS_DB_EVENT_DELETE,(WPARAM)hContact,(LPARAM)hDbevent);
+ SendMessage(hwndDlg,DM_HREBUILD,0,0);
+ }
+ return TRUE;
+ }
+ case IDC_LIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ { TCHAR str[8192],*contactName;
+ HANDLE hDbEvent;
+ DBEVENTINFO dbei;
+ int sel;
+ sel=SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if(sel==LB_ERR) { EnableWindow(GetDlgItem(hwndDlg,IDC_DELETEHISTORY),FALSE); break; }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DELETEHISTORY),TRUE);
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,GCDNF_TCHAR);
+ hDbEvent=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,sel,0);
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ GetObjectDescription(&dbei,str,SIZEOF(str));
+ mir_free(dbei.pBlob);
+ if(str[0]) SetDlgItemText(hwndDlg, IDC_EDIT, str);
+ }
+ return TRUE;
+ }
+ break;
+ case DM_FINDNEXT:
+ { TCHAR str[1024];
+ HANDLE hDbEvent,hDbEventStart;
+ DBEVENTINFO dbei;
+ int newBlobSize,oldBlobSize;
+
+ int index = SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if ( index == LB_ERR )
+ break;
+
+ hDbEventStart=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,index,0);
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.pBlob=NULL;
+ oldBlobSize=0;
+ for(;;) {
+ hDbEvent = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,++index,0);
+ if(hDbEvent == ( HANDLE )LB_ERR) {
+ index = -1;
+ continue;
+ }
+ if(hDbEvent==hDbEventStart) break;
+ newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if(newBlobSize>oldBlobSize) {
+ dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob,newBlobSize);
+ oldBlobSize=newBlobSize;
+ }
+ dbei.cbBlob=oldBlobSize;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ GetObjectDescription(&dbei,str,SIZEOF(str));
+ if(str[0]) {
+ CharUpperBuff(str,lstrlen(str));
+ if( _tcsstr(str,(const TCHAR*)lParam)!=NULL) {
+ SendDlgItemMessage(hwndDlg,IDC_LIST,LB_SETCURSEL,index,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_LIST,LBN_SELCHANGE),0);
+ break;
+ } } }
+
+ mir_free(dbei.pBlob);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg, GWL_USERDATA, lParam);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK://find Next
+ { HWND hwndParent;
+ TCHAR str[128];
+
+ hwndParent=(HWND)GetWindowLong(hwndDlg, GWL_USERDATA);
+ GetDlgItemText(hwndDlg, IDC_FINDWHAT, str, SIZEOF(str));
+ CharUpperBuff(str,lstrlen(str));
+ SendMessage(hwndParent,DM_FINDNEXT,0,(LPARAM)str);
+ return TRUE;
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/idle/idle.c b/miranda-wine/src/modules/idle/idle.c new file mode 100644 index 0000000..396fab9 --- /dev/null +++ b/miranda-wine/src/modules/idle/idle.c @@ -0,0 +1,415 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#define IDLEMOD "Idle"
+#define IDL_USERIDLECHECK "UserIdleCheck"
+#define IDL_IDLEMETHOD "IdleMethod"
+#define IDL_IDLETIME1ST "IdleTime1st"
+#define IDL_IDLEONSAVER "IdleOnSaver" // IDC_SCREENSAVER
+#define IDL_IDLEONLOCK "IdleOnLock" // IDC_LOCKED
+#define IDL_IDLEONTSDC "IdleOnTerminalDisconnect" //
+#define IDL_IDLEPRIVATE "IdlePrivate" // IDC_IDLEPRIVATE
+#define IDL_IDLESTATUSLOCK "IdleStatusLock" // IDC_IDLESTATUSLOCK
+#define IDL_AAENABLE "AAEnable"
+#define IDL_AASTATUS "AAStatus"
+
+#define IdleObject_IsIdle(obj) (obj->state&0x1)
+#define IdleObject_SetIdle(obj) (obj->state|=0x1)
+#define IdleObject_ClearIdle(obj) (obj->state&=~0x1)
+
+// either use meth 0,1 or figure out which one
+#define IdleObject_UseMethod0(obj) (obj->state&=~0x2)
+#define IdleObject_UseMethod1(obj) (obj->state|=0x2)
+#define IdleObject_GetMethod(obj) (obj->state&0x2)
+
+#define IdleObject_IdleCheckSaver(obj) (obj->state&0x4)
+#define IdleObject_SetSaverCheck(obj) (obj->state|=0x4)
+
+#define IdleObject_IdleCheckWorkstation(obj) (obj->state&0x8)
+#define IdleObject_SetWorkstationCheck(obj) (obj->state|=0x8)
+
+#define IdleObject_IsPrivacy(obj) (obj->state&0x10)
+#define IdleObject_SetPrivacy(obj) (obj->state|=0x10)
+
+#define IdleObject_SetStatusLock(obj) (obj->state|=0x20)
+
+#define IdleObject_IdleCheckTerminal(obj) (obj->state|=0x40)
+#define IdleObject_SetTerminalCheck(obj) (obj->state|=0x40)
+
+//#include <Wtsapi32.h>
+
+#ifndef _INC_WTSAPI
+
+#define WTS_CURRENT_SERVER_HANDLE ((HANDLE)NULL)
+#define WTS_CURRENT_SESSION ((DWORD)-1)
+
+typedef enum _WTS_CONNECTSTATE_CLASS {
+ WTSActive, // User logged on to WinStation
+ WTSConnected, // WinStation connected to client
+ WTSConnectQuery, // In the process of connecting to client
+ WTSShadow, // Shadowing another WinStation
+ WTSDisconnected, // WinStation logged on without client
+ WTSIdle, // Waiting for client to connect
+ WTSListen, // WinStation is listening for connection
+ WTSReset, // WinStation is being reset
+ WTSDown, // WinStation is down due to error
+ WTSInit, // WinStation in initialization
+} WTS_CONNECTSTATE_CLASS;
+
+
+typedef enum _WTS_INFO_CLASS {
+ WTSInitialProgram,
+ WTSApplicationName,
+ WTSWorkingDirectory,
+ WTSOEMId,
+ WTSSessionId,
+ WTSUserName,
+ WTSWinStationName,
+ WTSDomainName,
+ WTSConnectState,
+ WTSClientBuildNumber,
+ WTSClientName,
+ WTSClientDirectory,
+ WTSClientProductId,
+ WTSClientHardwareId,
+ WTSClientAddress,
+ WTSClientDisplay,
+ WTSClientProtocolType,
+} WTS_INFO_CLASS;
+
+#endif
+
+VOID (WINAPI *_WTSFreeMemory)(PVOID);
+BOOL (WINAPI *_WTSQuerySessionInformation)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*);
+
+BOOL WTSAPI = FALSE;
+
+BOOL InitWTSAPI()
+{
+ HMODULE hDll = LoadLibraryA("wtsapi32.dll");
+ if (hDll) {
+ _WTSFreeMemory = (VOID (WINAPI *)(PVOID))GetProcAddress(hDll, "WTSFreeMemory");
+ #ifdef UNICODE
+ _WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationW");
+ #else
+ _WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationA");
+ #endif
+
+ if (_WTSFreeMemory && _WTSQuerySessionInformation) return 1;
+ }
+ return 0;
+}
+
+BOOL IsTerminalDisconnected()
+{
+ PVOID pBuffer = NULL;
+ DWORD pBytesReturned = 0;
+ BOOL result = FALSE;
+
+ if (!WTSAPI) return FALSE;
+
+ if (_WTSQuerySessionInformation(
+ WTS_CURRENT_SERVER_HANDLE,
+ WTS_CURRENT_SESSION,
+ WTSConnectState,
+ &pBuffer,
+ &pBytesReturned)
+ ) {
+
+ if (*(PDWORD)pBuffer == WTSDisconnected)
+ result = TRUE;
+
+ _WTSFreeMemory(pBuffer);
+ }
+ return result;
+}
+
+typedef struct {
+ UINT hTimer;
+ unsigned int useridlecheck;
+ unsigned int state;
+ unsigned int minutes; // user setting, number of minutes of inactivity to wait for
+ POINT mousepos;
+ unsigned int mouseidle;
+ int aastatus;
+} IdleObject;
+
+static int aa_Status[] = {ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH};
+
+static IdleObject gIdleObject;
+static HANDLE hIdleEvent;
+static BOOL (WINAPI * MyGetLastInputInfo)(PLASTINPUTINFO);
+
+void CALLBACK IdleTimer(HWND hwnd, UINT umsg, UINT idEvent, DWORD dwTime);
+static BOOL IsWorkstationLocked(void);
+static BOOL IsScreenSaverRunning(void);
+
+static void IdleObject_ReadSettings(IdleObject * obj)
+{
+ obj->useridlecheck = DBGetContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, 0);
+ obj->minutes = DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, 10);
+ obj->aastatus = !DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? 0 : DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, 0) ) IdleObject_UseMethod1(obj);
+ else IdleObject_UseMethod0(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, 0) ) IdleObject_SetSaverCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, 0 ) ) IdleObject_SetWorkstationCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, 0) ) IdleObject_SetPrivacy(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, 0) ) IdleObject_SetStatusLock(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, 0) ) IdleObject_SetTerminalCheck(obj);
+}
+
+static void IdleObject_Create(IdleObject * obj)
+{
+ ZeroMemory(obj, sizeof(IdleObject));
+ obj->hTimer=SetTimer(NULL, 0, 2000, IdleTimer);
+ IdleObject_ReadSettings(obj);
+}
+
+static void IdleObject_Destroy(IdleObject * obj)
+{
+ if (IdleObject_IsIdle(obj)) NotifyEventHooks(hIdleEvent, 0, 0);
+ IdleObject_ClearIdle(obj);
+ KillTimer(NULL, obj->hTimer);
+}
+
+static int IdleObject_IsUserIdle(IdleObject * obj)
+{
+ DWORD dwTick;
+ if ( IdleObject_GetMethod(obj) ) {
+ CallService(MS_SYSTEM_GETIDLE, 0, (DWORD)&dwTick);
+ return GetTickCount() - dwTick > (obj->minutes * 60 * 1000);
+ } else {
+ if ( MyGetLastInputInfo != NULL ) {
+ LASTINPUTINFO ii;
+ ZeroMemory(&ii,sizeof(ii));
+ ii.cbSize=sizeof(ii);
+ if ( MyGetLastInputInfo(&ii) ) return GetTickCount() - ii.dwTime > (obj->minutes * 60 * 1000);
+ } else {
+ POINT pt;
+ GetCursorPos(&pt);
+ if ( pt.x != obj->mousepos.x || pt.y != obj->mousepos.y ) {
+ obj->mousepos=pt;
+ obj->mouseidle=0;
+ } else obj->mouseidle += 2;
+ if ( obj->mouseidle ) return obj->mouseidle * 1000 >= (obj->minutes * 60 * 1000);
+ }
+ return FALSE;
+ }
+}
+
+static void IdleObject_Tick(IdleObject * obj)
+{
+ BOOL idle = ( obj->useridlecheck ? IdleObject_IsUserIdle(obj) : FALSE )
+ || ( IdleObject_IdleCheckSaver(obj) ? IsScreenSaverRunning() : FALSE )
+ || ( IdleObject_IdleCheckWorkstation(obj) ? IsWorkstationLocked() : FALSE )
+ || (IdleObject_IdleCheckTerminal(obj) ? IsTerminalDisconnected() : FALSE );
+
+ unsigned int flags = IdleObject_IsPrivacy(obj) ? IDF_PRIVACY : 0;
+
+ if ( !IdleObject_IsIdle(obj) && idle ) {
+ IdleObject_SetIdle(obj);
+ NotifyEventHooks(hIdleEvent, 0, IDF_ISIDLE | flags);
+ }
+ if ( IdleObject_IsIdle(obj) && !idle ) {
+ IdleObject_ClearIdle(obj);
+ NotifyEventHooks(hIdleEvent, 0, flags);
+ }
+}
+
+void CALLBACK IdleTimer(HWND hwnd, UINT umsg, UINT idEvent, DWORD dwTime)
+{
+ if ( gIdleObject.hTimer == idEvent ) {
+ IdleObject_Tick(&gIdleObject);
+ }
+}
+
+// delphi code here http://www.swissdelphicenter.ch/torry/printcode.php?id=2048
+static BOOL IsWorkstationLocked(void)
+{
+ BOOL rc=0;
+ HDESK hDesk = OpenDesktop( _T("default"), 0, FALSE, DESKTOP_SWITCHDESKTOP);
+ if ( hDesk != 0 ) {
+ rc = SwitchDesktop(hDesk) == FALSE;
+ CloseDesktop(hDesk);
+ }
+ return rc;
+}
+
+static BOOL IsScreenSaverRunning()
+{
+ BOOL rc = FALSE;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &rc, FALSE);
+ return rc;
+}
+
+int IdleGetStatusIndex(WORD status)
+{
+ int j;
+ for (j = 0; j < SIZEOF(aa_Status); j++ ) {
+ if (aa_Status[j]==status) return j;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK IdleOptsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ int j;
+ int method = DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEMETHOD, 0);
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_IDLESHORT, DBGetContactSettingByte(NULL,IDLEMOD,IDL_USERIDLECHECK,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEONWINDOWS, method == 0 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEONMIRANDA, method ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SCREENSAVER, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONSAVER,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_LOCKED, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONLOCK,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEPRIVATE, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEPRIVATE,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLESTATUSLOCK, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLESTATUSLOCK,0) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_IDLE1STTIME), 0);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETRANGE32, 1, 60);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLETIME1ST, 10), 0));
+ SendDlgItemMessage(hwndDlg, IDC_IDLE1STTIME, EM_LIMITTEXT, (WPARAM)2, 0);
+
+ CheckDlgButton(hwndDlg, IDC_AASHORTIDLE, DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? BST_CHECKED:BST_UNCHECKED);
+ for ( j = 0; j < SIZEOF(aa_Status); j++ ) {
+ TCHAR* szDesc = LangPackPcharToTchar(( LPCSTR )CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)aa_Status[j], 0));
+ SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_ADDSTRING, 0, (LPARAM)szDesc );
+ mir_free( szDesc );
+ }
+
+ j = IdleGetStatusIndex((WORD)(DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0)));
+ SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_SETCURSEL, j, 0);
+ SendMessage(hwndDlg, WM_USER+2, 0, 0);
+ return TRUE;
+ }
+ case WM_USER+2:
+ {
+ BOOL checked = IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONWINDOWS), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONMIRANDA), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLE1STTIME), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AASTATUS), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLESTATUSLOCK), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0);
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR * hdr = (NMHDR *)lParam;
+ if ( hdr && hdr->code == PSN_APPLY ) {
+ int method = IsDlgButtonChecked(hwndDlg, IDC_IDLEONWINDOWS) == BST_CHECKED;
+ int mins = SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_GETPOS, 0, 0);
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, (BYTE)(HIWORD(mins) == 0 ? LOWORD(mins) : 10));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, (BYTE)(method ? 0 : 1));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SCREENSAVER) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_LOCKED) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLEPRIVATE) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESTATUSLOCK)==BST_CHECKED?1:0));
+ {
+ int curSel = SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_GETCURSEL, 0, 0);
+ if ( curSel != CB_ERR ) {
+ DBWriteContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, (WORD)(aa_Status[curSel]));
+ }
+ }
+ // destroy any current idle and reset settings.
+ IdleObject_Destroy(&gIdleObject);
+ IdleObject_Create(&gIdleObject);
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_IDLE1STTIME:
+ {
+ int min;
+ if ( (HWND)lParam != GetFocus() || HIWORD(wParam) != EN_CHANGE ) return FALSE;
+ min=GetDlgItemInt(hwndDlg, IDC_IDLE1STTIME, NULL, FALSE);
+ if ( min == 0 && GetWindowTextLength(GetDlgItem(hwndDlg, IDC_IDLE1STTIME)) )
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) 1, 0));
+ break;
+ }
+ case IDC_IDLESHORT:
+ case IDC_AASHORTIDLE:
+ SendMessage(hwndDlg, WM_USER+2, 0, 0);
+ break;
+
+ case IDC_AASTATUS:
+ if ( HIWORD(wParam) != CBN_SELCHANGE )
+ return TRUE;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ return FALSE;
+}
+
+static int IdleOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 100000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IDLE);
+ odp.pszGroup = "Status";
+ odp.pszTitle = "Idle";
+ odp.pfnDlgProc = IdleOptsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int IdleGetInfo(WPARAM wParam, LPARAM lParam)
+{
+ MIRANDA_IDLE_INFO *mii = (MIRANDA_IDLE_INFO*)lParam;
+
+ if (!mii || mii->cbSize!=sizeof(MIRANDA_IDLE_INFO)) return 1;
+ mii->idleTime = gIdleObject.minutes;
+ mii->privacy = gIdleObject.state&0x10;
+ mii->aaStatus = gIdleObject.aastatus;
+ mii->aaLock = gIdleObject.state&0x20;
+ return 0;
+}
+
+static int UnloadIdleModule(WPARAM wParam, LPARAM lParam)
+{
+ IdleObject_Destroy(&gIdleObject);
+ DestroyHookableEvent(hIdleEvent);
+ hIdleEvent=NULL;
+ return 0;
+}
+
+int LoadIdleModule(void)
+{
+ WTSAPI = InitWTSAPI();
+ MyGetLastInputInfo=(BOOL (WINAPI *)(LASTINPUTINFO*))GetProcAddress(GetModuleHandleA("user32"), "GetLastInputInfo");
+ hIdleEvent=CreateHookableEvent(ME_IDLE_CHANGED);
+ IdleObject_Create(&gIdleObject);
+ CreateServiceFunction(MS_IDLE_GETIDLEINFO, IdleGetInfo);
+ HookEvent(ME_SYSTEM_SHUTDOWN, UnloadIdleModule);
+ HookEvent(ME_OPT_INITIALISE, IdleOptInit);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/ignore/ignore.c b/miranda-wine/src/modules/ignore/ignore.c new file mode 100644 index 0000000..192cb3d --- /dev/null +++ b/miranda-wine/src/modules/ignore/ignore.c @@ -0,0 +1,449 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#define IGNOREEVENT_MAX 6
+
+static const DWORD ignoreIdToPf1[IGNOREEVENT_MAX]={PF1_IMRECV,PF1_URLRECV,PF1_FILERECV,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
+
+static DWORD GetMask(HANDLE hContact)
+{
+ DWORD mask=DBGetContactSettingDword(hContact,"Ignore","Mask1",(DWORD)(-1));
+ if(mask==(DWORD)(-1)) {
+ if(hContact==NULL) mask=0;
+ else {
+ if(DBGetContactSettingByte(hContact,"CList","Hidden",0) || DBGetContactSettingByte(hContact,"CList","NotOnList",0))
+ mask=DBGetContactSettingDword(NULL,"Ignore","Mask1",0);
+ else
+ mask=DBGetContactSettingDword(NULL,"Ignore","Default1",0);
+ }
+ }
+ return mask;
+}
+
+static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
+{
+ int typeOfFirst;
+ int iconOn[IGNOREEVENT_MAX]={1,1,1,1,1,1};
+ int childCount[IGNOREEVENT_MAX]={0,0,0,0,0,0},i;
+ int iImage;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
+ for(i=0; i < SIZEOF(iconOn); i++)
+ if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ for( i=0; i < SIZEOF(iconOn); i++ ) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
+ if(iconOn[i] && iImage==0) iconOn[i]=0;
+ if(iImage!=0xFF) childCount[i]++;
+ }
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+ //set icons
+ for( i=0; i < SIZEOF(iconOn); i++ ) {
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+3:0):0xFF));
+ if(groupChildCount) groupChildCount[i]+=childCount[i];
+ }
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(IGNOREEVENT_MAX,1));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(IGNOREEVENT_MAX+1,2));
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+static void ResetListOptions(HWND hwndList)
+{
+ int i;
+
+ SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL);
+ SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0);
+ SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
+ SendMessage(hwndList,CLM_SETLEFTMARGIN,4,0);
+ SendMessage(hwndList,CLM_SETINDENT,10,0);
+ SendMessage(hwndList,CLM_SETHIDEEMPTYGROUPS,1,0);
+ for(i=0;i<=FONTID_MAX;i++)
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+}
+
+static void SetIconsForColumn(HWND hwndList,HANDLE hItem,HANDLE hItemAll,int iColumn,int iImage)
+{
+ int itemType;
+
+ itemType=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hItem,0);
+ if(itemType==CLCIT_CONTACT) {
+ int oldiImage = SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if (oldiImage!=0xFF&&oldiImage!=iImage)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ }
+ else if(itemType==CLCIT_INFO) {
+ if(hItem==hItemAll) SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ else SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage)); //hItemUnknown
+ }
+ else if(itemType==CLCIT_GROUP) {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hItem) SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ }
+}
+
+static void InitialiseItem(HWND hwndList,HANDLE hContact,HANDLE hItem,DWORD protoCaps)
+{
+ DWORD mask;
+ int i;
+
+ mask=GetMask(hContact);
+ for(i=0;i<IGNOREEVENT_MAX;i++)
+ if(ignoreIdToPf1[i]==0xFFFFFFFF || protoCaps&ignoreIdToPf1[i])
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,mask&(1<<i)?i+3:0));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX,1));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX+1,2));
+}
+
+static void SaveItemMask(HWND hwndList,HANDLE hContact,HANDLE hItem,const char *pszSetting)
+{
+ DWORD mask;
+ int i,iImage;
+
+ mask=0;
+ for(i=0;i<IGNOREEVENT_MAX;i++) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,0));
+ if(iImage && iImage!=0xFF) mask|=1<<i;
+ }
+ DBWriteContactSettingDword(hContact,"Ignore",pszSetting,mask);
+}
+
+static void SetAllContactIcons(HWND hwndList)
+{
+ HANDLE hContact,hItem;
+ DWORD protoCaps;
+ char *szProto;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX,0))==0xFF) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if(szProto==NULL) protoCaps=0;
+ else protoCaps=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ InitialiseItem(hwndList,hContact,hItem,protoCaps);
+ if(!DBGetContactSettingByte(hContact,"CList","Hidden",0))
+ SendMessage(hwndList,CLM_SETCHECKMARK,(WPARAM)hItem,1);
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+}
+
+static BOOL CALLBACK DlgProcIgnoreOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HICON hIcons[IGNOREEVENT_MAX+2];
+ static HANDLE hItemAll,hItemUnknown;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { HIMAGELIST hIml;
+ int i;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3+IGNOREEVENT_MAX,3+IGNOREEVENT_MAX);
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SMALLDOT)));
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_FILLEDBLOB)));
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_EMPTYBLOB)));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_EVENT_URL));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_EVENT_FILE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_OTHER_USERONLINE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT)));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hIml);
+ for( i=0; i < SIZEOF(hIcons); i++ )
+ hIcons[i]=ImageList_GetIcon(hIml,1+i,ILD_NORMAL);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_ALLICON,STM_SETICON,(WPARAM)hIcons[0],0);
+ SendDlgItemMessage(hwndDlg,IDC_NONEICON,STM_SETICON,(WPARAM)hIcons[1],0);
+ SendDlgItemMessage(hwndDlg,IDC_MSGICON,STM_SETICON,(WPARAM)hIcons[2],0);
+ SendDlgItemMessage(hwndDlg,IDC_URLICON,STM_SETICON,(WPARAM)hIcons[3],0);
+ SendDlgItemMessage(hwndDlg,IDC_FILEICON,STM_SETICON,(WPARAM)hIcons[4],0);
+ SendDlgItemMessage(hwndDlg,IDC_ONLINEICON,STM_SETICON,(WPARAM)hIcons[5],0);
+ SendDlgItemMessage(hwndDlg,IDC_AUTHICON,STM_SETICON,(WPARAM)hIcons[6],0);
+ SendDlgItemMessage(hwndDlg,IDC_ADDED,STM_SETICON,(WPARAM)hIcons[7],0);
+
+ if(!SendMessage(GetParent(hwndDlg),PSM_ISEXPERT,0,0)) {
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)&~(CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_AUTOREBUILD,0,0);
+ }
+
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,IGNOREEVENT_MAX+2,0);
+
+ { CLCINFOITEM cii={0};
+ cii.cbSize=sizeof(cii);
+ cii.flags=CLCIIF_GROUPFONT;
+ cii.pszText=TranslateT("** All contacts **");
+ hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+
+ cii.pszText=TranslateT("** Unknown contacts **");
+ hItemUnknown=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+ InitialiseItem(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemUnknown,0xFFFFFFFF);
+ }
+
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ return TRUE;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case CLN_CHECKCHANGED:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case NM_CLICK:
+ { HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+
+ if(nm->iColumn==-1) break;
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_HITTEST,(WPARAM)&hitFlags,MAKELPARAM(nm->pt.x,nm->pt.y));
+ if(hItem==NULL) break;
+ if(!(hitFlags&CLCHT_ONITEMEXTRA)) break;
+ if(nm->iColumn==IGNOREEVENT_MAX) { //ignore all
+ for(iImage=0;iImage<IGNOREEVENT_MAX;iImage++)
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,iImage,iImage+3);
+ }
+ else if(nm->iColumn==IGNOREEVENT_MAX+1) { //ignore none
+ for(iImage=0;iImage<IGNOREEVENT_MAX;iImage++)
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,iImage,0);
+ }
+ else {
+ iImage=SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn,0));
+ if(iImage==0) iImage=nm->iColumn+3;
+ else if(iImage!=0xFF) iImage=0;
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,nm->iColumn,iImage);
+ }
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { HANDLE hContact,hItem;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),hContact,hItem,"Mask1");
+ if(SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETCHECKMARK,(WPARAM)hItem,0))
+ DBDeleteContactSetting(hContact,"CList","Hidden");
+ else
+ DBWriteContactSettingByte(hContact,"CList","Hidden",1);
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+ SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemAll,"Default1");
+ SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemUnknown,"Mask1");
+ return TRUE;
+ }
+ case PSN_EXPERTCHANGED:
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE,((PSHNOTIFY*)lParam)->lParam?GetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)|CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN:GetWindowLong(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)&~(CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_AUTOREBUILD,0,0);
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int i;
+ HIMAGELIST hIml;
+ for( i=0; i < SIZEOF(hIcons); i++ )
+ DestroyIcon(hIcons[i]);
+ hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_STCHECKMARKS};
+static int IgnoreOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IGNORE);
+ odp.pszTitle = "Ignore";
+ odp.pszGroup = "Events";
+ odp.pfnDlgProc = DlgProcIgnoreOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp);
+ return 0;
+}
+
+static int IsIgnored(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if(lParam<1 || lParam>IGNOREEVENT_MAX) return 1;
+ return (mask>>(lParam-1))&1;
+}
+
+static int Ignore(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if((lParam<1 || lParam>IGNOREEVENT_MAX) && lParam!=IGNOREEVENT_ALL) return 1;
+ if(lParam==IGNOREEVENT_ALL) mask=(1<<IGNOREEVENT_MAX)-1;
+ else mask|=1<<(lParam-1);
+ DBWriteContactSettingDword((HANDLE)wParam,"Ignore","Mask1",mask);
+ return 0;
+}
+
+static int Unignore(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if((lParam<1 || lParam>IGNOREEVENT_MAX) && lParam!=IGNOREEVENT_ALL) return 1;
+ if(lParam==IGNOREEVENT_ALL) mask=0;
+ else mask&=~(1<<(lParam-1));
+ DBWriteContactSettingDword((HANDLE)wParam,"Ignore","Mask1",mask);
+ return 0;
+}
+
+static int IgnoreContactAdded(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_PROTO_ADDTOCONTACT,wParam,(LPARAM)"Ignore");
+ return 0;
+}
+
+static int IgnoreRecvMessage(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_MESSAGE)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreRecvUrl(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_URL)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreRecvFile(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_FILE)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreRecvAuth(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_AUTHORIZATION)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreAddedNotify(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ if (dbei && dbei->eventType==EVENTTYPE_ADDED && dbei->pBlob!=NULL) {
+ HANDLE hContact;
+
+ hContact=*((PHANDLE)(dbei->pBlob+sizeof(DWORD)));
+ if (CallService(MS_DB_CONTACT_IS,(WPARAM)hContact,0) && IsIgnored((WPARAM)hContact,IGNOREEVENT_YOUWEREADDED))
+ return 1;
+ }
+ return 0;
+}
+
+int LoadIgnoreModule(void)
+{
+ PROTOCOLDESCRIPTOR pd;
+ HANDLE hContact;
+
+ ZeroMemory(&pd,sizeof(pd));
+ pd.cbSize=sizeof(pd);
+ pd.szName="Ignore";
+ pd.type=PROTOTYPE_IGNORE;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact!=NULL) {
+ if(!CallService(MS_PROTO_ISPROTOONCONTACT,(WPARAM)hContact,(LPARAM)"Ignore"))
+ CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)hContact,(LPARAM)"Ignore");
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+ HookEvent(ME_DB_CONTACT_ADDED,IgnoreContactAdded);
+ HookEvent(ME_DB_EVENT_FILTER_ADD,IgnoreAddedNotify);
+ CreateServiceFunction("Ignore"PSR_MESSAGE,IgnoreRecvMessage);
+ CreateServiceFunction("Ignore"PSR_URL,IgnoreRecvUrl);
+ CreateServiceFunction("Ignore"PSR_FILE,IgnoreRecvFile);
+ CreateServiceFunction("Ignore"PSR_AUTH,IgnoreRecvAuth);
+ HookEvent(ME_OPT_INITIALISE,IgnoreOptInitialise);
+ CreateServiceFunction(MS_IGNORE_ISIGNORED,IsIgnored);
+ CreateServiceFunction(MS_IGNORE_IGNORE,Ignore);
+ CreateServiceFunction(MS_IGNORE_UNIGNORE,Unignore);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/langpack/langpack.c b/miranda-wine/src/modules/langpack/langpack.c new file mode 100644 index 0000000..c816025 --- /dev/null +++ b/miranda-wine/src/modules/langpack/langpack.c @@ -0,0 +1,362 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+int LoadLangPackServices(void);
+
+struct LangPackEntry {
+ unsigned linePos;
+ DWORD englishHash;
+ char *english; //not currently used, the hash does everything
+ char *local;
+ wchar_t *wlocal;
+};
+
+struct LangPackStruct {
+ TCHAR filename[MAX_PATH];
+ char language[64];
+ char lastModifiedUsing[64];
+ char authors[256];
+ char authorEmail[128];
+ struct LangPackEntry *entry;
+ int entryCount;
+ LCID localeID;
+ DWORD defaultANSICp;
+} static langPack;
+
+static void TrimString(char *str)
+{
+ int len,start;
+ len=lstrlenA(str);
+ while(str[0] && (unsigned char)str[len-1]<=' ') str[--len]=0;
+ for(start=0;str[start] && (unsigned char)str[start]<=' ';start++);
+ MoveMemory(str,str+start,len-start+1);
+}
+
+static void TrimStringSimple(char *str)
+{
+ if (str[lstrlenA(str)-1] == '\n') str[lstrlenA(str)-1] = '\0';
+ if (str[lstrlenA(str)-1] == '\r') str[lstrlenA(str)-1] = '\0';
+}
+
+static int IsEmpty(char *str)
+{
+ int i = 0;
+
+ while (str[i])
+ {
+ if (str[i]!=' '&&str[i]!='\r'&&str[i]!='\n')
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+static void ConvertBackslashes(char *str)
+{
+ char *pstr;
+ for(pstr=str;*pstr;pstr=CharNextA(pstr)) {
+ if(*pstr=='\\') {
+ switch(pstr[1]) {
+case 'n': *pstr='\n'; break;
+case 't': *pstr='\t'; break;
+case 'r': *pstr='\r'; break;
+default: *pstr=pstr[1]; break;
+ }
+ MoveMemory(pstr+1,pstr+2,lstrlenA(pstr+2)+1);
+ }
+ }
+}
+
+static DWORD LangPackHash(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined __GNUC__
+ __asm { //this is mediocrely optimised, but I'm sure it's good enough
+ xor edx,edx
+ mov esi,szStr
+ xor cl,cl
+lph_top:
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ inc esi
+ test al,al
+ jz lph_end
+ rol eax,cl
+ add cl,5
+ xor edx,eax
+ jmp lph_top
+lph_end:
+ mov eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i++) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) hash^=(szStr[i]>>(32-shift))&0x7F;
+ shift=(shift+5)&0x1F;
+ }
+ return hash;
+#endif
+}
+
+static DWORD LangPackHashW(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined __GNUC__
+ __asm { //this is mediocrely optimised, but I'm sure it's good enough
+ xor edx,edx
+ mov esi,szStr
+ xor cl,cl
+lph_top:
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ inc esi
+ inc esi
+ test al,al
+ jz lph_end
+ rol eax,cl
+ add cl,5
+ xor edx,eax
+ jmp lph_top
+lph_end:
+ mov eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i+=2) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) hash^=(szStr[i]>>(32-shift))&0x7F;
+ shift=(shift+5)&0x1F;
+ }
+ return hash;
+#endif
+}
+
+static int SortLangPackHashesProc(struct LangPackEntry *arg1,struct LangPackEntry *arg2)
+{
+ if(arg1->englishHash<arg2->englishHash) return -1;
+ if(arg1->englishHash>arg2->englishHash) return 1;
+ /* both source strings of the same hash (may not be the same string thou) put
+ the one that was written first to be found first */
+ if(arg1->linePos<arg2->linePos) return -1;
+ if(arg1->linePos>arg2->linePos) return 1;
+ return 0;
+}
+
+
+static int SortLangPackHashesProc2(struct LangPackEntry *arg1,struct LangPackEntry *arg2)
+{
+ if(arg1->englishHash<arg2->englishHash) return -1;
+ if(arg1->englishHash>arg2->englishHash) return 1;
+ return 0;
+}
+
+static int LoadLangPack(const TCHAR *szLangPack)
+{
+ FILE *fp;
+ char line[4096];
+ char *pszColon;
+ char *pszLine;
+ int entriesAlloced;
+ int startOfLine=0;
+ unsigned int linePos=1;
+ USHORT langID;
+
+ lstrcpy(langPack.filename,szLangPack);
+ fp = _tfopen(szLangPack,_T("rt"));
+ if(fp==NULL) return 1;
+ fgets(line,SIZEOF(line),fp);
+ TrimString(line);
+ if(lstrcmpA(line,"Miranda Language Pack Version 1")) {fclose(fp); return 2;}
+ //headers
+ while(!feof(fp)) {
+ startOfLine=ftell(fp);
+ if(fgets(line,SIZEOF(line),fp)==NULL) break;
+ TrimString(line);
+ if(IsEmpty(line) || line[0]==';' || line[0]==0) continue;
+ if(line[0]=='[') break;
+ pszColon=strchr(line,':');
+ if(pszColon==NULL) {fclose(fp); return 3;}
+ *pszColon=0;
+ if(!lstrcmpA(line,"Language")) {mir_snprintf(langPack.language,sizeof(langPack.language),"%s",pszColon+1); TrimString(langPack.language);}
+ else if(!lstrcmpA(line,"Last-Modified-Using")) {mir_snprintf(langPack.lastModifiedUsing,sizeof(langPack.lastModifiedUsing),"%s",pszColon+1); TrimString(langPack.lastModifiedUsing);}
+ else if(!lstrcmpA(line,"Authors")) {mir_snprintf(langPack.authors,sizeof(langPack.authors),"%s",pszColon+1); TrimString(langPack.authors);}
+ else if(!lstrcmpA(line,"Author-email")) {mir_snprintf(langPack.authorEmail,sizeof(langPack.authorEmail),"%s",pszColon+1); TrimString(langPack.authorEmail);}
+ else if(!lstrcmpA(line, "Locale")) {
+ char szBuf[20], *stopped;
+
+ TrimString(pszColon + 1);
+ langID = (USHORT)strtol(pszColon + 1, &stopped, 16);
+ langPack.localeID = MAKELCID(langID, 0);
+ GetLocaleInfoA(langPack.localeID, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10);
+ szBuf[5] = 0; // codepages have max. 5 digits
+ langPack.defaultANSICp = atoi(szBuf);
+ }
+ }
+ //body
+ fseek(fp,startOfLine,SEEK_SET);
+ entriesAlloced=0;
+ while(!feof(fp)) {
+ if(fgets(line,SIZEOF(line),fp)==NULL) break;
+ if(IsEmpty(line) || line[0]==';' || line[0]==0) continue;
+ TrimStringSimple(line);
+ ConvertBackslashes(line);
+ if(line[0]=='[' && line[lstrlenA(line)-1]==']') {
+ if(langPack.entryCount && langPack.entry[langPack.entryCount-1].local==NULL) {
+ if(langPack.entry[langPack.entryCount-1].english!=NULL) mir_free(langPack.entry[langPack.entryCount-1].english);
+ langPack.entryCount--;
+ }
+ pszLine = line+1;
+ line[lstrlenA(line)-1]='\0';
+ TrimStringSimple(line);
+ if(++langPack.entryCount>entriesAlloced) {
+ entriesAlloced+=128;
+ langPack.entry=(struct LangPackEntry*)mir_realloc(langPack.entry,sizeof(struct LangPackEntry)*entriesAlloced);
+ }
+ langPack.entry[langPack.entryCount-1].english=NULL;
+ langPack.entry[langPack.entryCount-1].englishHash=LangPackHash(pszLine);
+ langPack.entry[langPack.entryCount-1].local=NULL;
+ langPack.entry[langPack.entryCount-1].wlocal = NULL;
+ langPack.entry[langPack.entryCount-1].linePos=linePos++;
+ }
+ else if(langPack.entryCount) {
+ struct LangPackEntry* E = &langPack.entry[langPack.entryCount-1];
+
+ if(E->local==NULL) {
+ E->local=mir_strdup(line);
+ {
+ int iNeeded = MultiByteToWideChar(langPack.defaultANSICp, 0, line, -1, 0, 0);
+ E->wlocal = (wchar_t *)mir_alloc((iNeeded+1) * sizeof(wchar_t));
+ MultiByteToWideChar(langPack.defaultANSICp, 0, line, -1, E->wlocal, iNeeded);
+ }
+ }
+ else {
+ E->local=(char*)mir_realloc(E->local,lstrlenA(E->local)+lstrlenA(line)+2);
+ lstrcatA(E->local,"\n");
+ lstrcatA(E->local,line);
+ {
+ int iNeeded = MultiByteToWideChar(langPack.defaultANSICp, 0, line, -1, 0, 0);
+ int iOldLen = wcslen(E->wlocal);
+ E->wlocal = (wchar_t*)mir_realloc(E->wlocal, ( sizeof(wchar_t) * ( iOldLen + iNeeded + 2)));
+ wcscat(E->wlocal, L"\n");
+ MultiByteToWideChar( langPack.defaultANSICp, 0, line, -1, E->wlocal + iOldLen+1, iNeeded);
+ }
+ }
+ }
+ }
+ qsort(langPack.entry,langPack.entryCount,sizeof(struct LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc);
+ fclose(fp);
+ return 0;
+}
+
+char *LangPackTranslateString(const char *szEnglish, const int W)
+{
+ struct LangPackEntry key,*entry;
+
+ if ( langPack.entryCount == 0 || szEnglish == NULL ) return (char*)szEnglish;
+
+ key.englishHash = W ? LangPackHashW(szEnglish) : LangPackHash(szEnglish);
+ entry=(struct LangPackEntry*)bsearch(&key,langPack.entry,langPack.entryCount,sizeof(struct LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc2);
+ if(entry==NULL) return (char*)szEnglish;
+ while(entry>langPack.entry)
+ {
+ entry--;
+ if(entry->englishHash!=key.englishHash) {
+ entry++;
+ return W ? (char *)entry->wlocal : entry->local;
+ }
+ }
+ return W ? (char *)entry->wlocal : entry->local;
+}
+
+int LangPackGetDefaultCodePage()
+{
+ return (langPack.defaultANSICp == 0) ? CP_ACP : langPack.defaultANSICp;
+}
+
+int LangPackGetDefaultLocale()
+{
+ return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID;
+}
+
+TCHAR* LangPackPcharToTchar( const char* pszStr )
+{
+ if ( pszStr == NULL )
+ return NULL;
+
+ #if defined( _UNICODE )
+ { int len = strlen( pszStr );
+ TCHAR* result = ( TCHAR* )alloca(( len+1 )*sizeof( TCHAR ));
+ MultiByteToWideChar( LangPackGetDefaultCodePage(), 0, pszStr, -1, result, len );
+ result[len] = 0;
+ return mir_wstrdup( TranslateW( result ));
+ }
+ #else
+ return mir_strdup( Translate( pszStr ));
+ #endif
+}
+
+static int LangPackShutdown(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<langPack.entryCount;i++) {
+ if(langPack.entry[i].english!=NULL) mir_free(langPack.entry[i].english);
+ if(langPack.entry[i].local!=NULL) { mir_free(langPack.entry[i].local); }
+ if(langPack.entry[i].wlocal!=NULL) { mir_free(langPack.entry[i].wlocal); }
+ }
+ if(langPack.entryCount) {
+ mir_free(langPack.entry);
+ langPack.entry=0;
+ langPack.entryCount=0;
+ }
+ return 0;
+}
+
+int LoadLangPackModule(void)
+{
+ HANDLE hFind;
+ TCHAR szSearch[MAX_PATH],*str2,szLangPack[MAX_PATH];
+ WIN32_FIND_DATA fd;
+
+ ZeroMemory(&langPack,sizeof(langPack));
+ HookEvent(ME_SYSTEM_SHUTDOWN,LangPackShutdown);
+ LoadLangPackServices();
+ GetModuleFileName(GetModuleHandle(NULL),szSearch,SIZEOF(szSearch));
+ str2=_tcsrchr(szSearch,'\\');
+ if(str2!=NULL) *str2=0;
+ else str2=szSearch;
+ lstrcat( szSearch, _T("\\langpack_*.txt"));
+ hFind = FindFirstFile( szSearch, &fd );
+ if( hFind != INVALID_HANDLE_VALUE ) {
+ lstrcpy(str2+1,fd.cFileName);
+ lstrcpy(szLangPack,szSearch);
+ FindClose(hFind);
+ LoadLangPack(szLangPack);
+ }
+ return 0;
+}
diff --git a/miranda-wine/src/modules/langpack/lpservices.c b/miranda-wine/src/modules/langpack/lpservices.c new file mode 100644 index 0000000..4ebe764 --- /dev/null +++ b/miranda-wine/src/modules/langpack/lpservices.c @@ -0,0 +1,128 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#if defined( _UNICODE )
+ #define FLAGS LANG_UNICODE
+#else
+ #define FLAGS 0
+#endif
+
+static int TranslateString(WPARAM wParam,LPARAM lParam)
+{
+ return (int)LangPackTranslateString((const char *)lParam, (wParam & LANG_UNICODE) ? 1 : 0);
+}
+
+static int TranslateMenu(WPARAM wParam,LPARAM lParam)
+{
+ HMENU hMenu = ( HMENU )wParam;
+ int i;
+ MENUITEMINFO mii;
+ TCHAR str[256];
+
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ for ( i = GetMenuItemCount( hMenu )-1; i >= 0; i--) {
+ mii.fMask = MIIM_TYPE|MIIM_SUBMENU;
+ mii.dwTypeData = ( TCHAR* )str;
+ mii.cch = SIZEOF(str);
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+
+ if ( mii.cch && mii.dwTypeData ) {
+ TCHAR* result = ( TCHAR* )LangPackTranslateString(( const char* )mii.dwTypeData, FLAGS );
+ if ( result != mii.dwTypeData ) {
+ mii.dwTypeData = result;
+ mii.fMask = MIIM_TYPE;
+ SetMenuItemInfo( hMenu, i, TRUE, &mii );
+ } }
+
+ if ( mii.hSubMenu != NULL ) TranslateMenu(( WPARAM )mii.hSubMenu, lParam);
+ }
+ return 0;
+}
+
+static void TranslateWindow( HWND hwnd, int flags )
+{
+ TCHAR title[2048];
+ GetWindowText(hwnd, title, SIZEOF( title ));
+ {
+ TCHAR* result = ( TCHAR* )LangPackTranslateString(( const char* )title, FLAGS );
+ if ( result != title )
+ SetWindowText(hwnd, result );
+} }
+
+static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd,LPARAM lParam)
+{
+ LANGPACKTRANSLATEDIALOG *lptd=(LANGPACKTRANSLATEDIALOG*)lParam;
+ TCHAR szClass[32];
+ int i,id = GetDlgCtrlID( hwnd );
+
+ if(lptd->ignoreControls != NULL)
+ for(i=0;lptd->ignoreControls[i];i++) if(lptd->ignoreControls[i]==id) return TRUE;
+
+ GetClassName(hwnd,szClass,SIZEOF(szClass));
+ if(!lstrcmpi(szClass,_T("static")) || !lstrcmpi(szClass,_T("hyperlink")) || !lstrcmpi(szClass,_T("button")) || !lstrcmpi(szClass,_T("MButtonClass")))
+ TranslateWindow(hwnd, lptd->flags);
+ else if(!lstrcmpi(szClass,_T("edit"))) {
+ if(lptd->flags&LPTDF_NOIGNOREEDIT || GetWindowLong(hwnd,GWL_STYLE)&ES_READONLY)
+ TranslateWindow(hwnd, lptd->flags);
+ }
+ return TRUE;
+}
+
+static int TranslateDialog(WPARAM wParam,LPARAM lParam)
+{
+ LANGPACKTRANSLATEDIALOG *lptd=(LANGPACKTRANSLATEDIALOG*)lParam;
+ if(lptd==NULL||lptd->cbSize!=sizeof(LANGPACKTRANSLATEDIALOG)) return 1;
+ if(!(lptd->flags&LPTDF_NOTITLE))
+ TranslateWindow( lptd->hwndDlg, wParam );
+
+ EnumChildWindows(lptd->hwndDlg,TranslateDialogEnumProc,lParam);
+ return 0;
+}
+
+static int GetDefaultCodePage(WPARAM wParam,LPARAM lParam)
+{
+ return LangPackGetDefaultCodePage();
+}
+
+static int GetDefaultLocale(WPARAM wParam,LPARAM lParam)
+{
+ return LangPackGetDefaultLocale();
+}
+
+static int PcharToTchar(WPARAM wParam,LPARAM lParam)
+{
+ return ( int )LangPackPcharToTchar((char*)lParam );
+}
+
+int LoadLangPackServices(void)
+{
+ CreateServiceFunction(MS_LANGPACK_TRANSLATESTRING,TranslateString);
+ CreateServiceFunction(MS_LANGPACK_TRANSLATEMENU,TranslateMenu);
+ CreateServiceFunction(MS_LANGPACK_TRANSLATEDIALOG,TranslateDialog);
+ CreateServiceFunction(MS_LANGPACK_GETCODEPAGE,GetDefaultCodePage);
+ CreateServiceFunction(MS_LANGPACK_GETLOCALE,GetDefaultLocale);
+ CreateServiceFunction(MS_LANGPACK_PCHARTOTCHAR,PcharToTchar);
+ return 0;
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlib.c b/miranda-wine/src/modules/netlib/netlib.c new file mode 100644 index 0000000..72a0370 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlib.c @@ -0,0 +1,503 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+struct NetlibUser **netlibUser=NULL;
+int netlibUserCount=0;
+CRITICAL_SECTION csNetlibUser;
+HANDLE hConnectionHeaderMutex;
+DWORD g_LastConnectionTick; // protected by csNetlibUser
+
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings)
+{
+ if(settings->szIncomingPorts) mir_free(settings->szIncomingPorts);
+ if(settings->szOutgoingPorts) mir_free(settings->szOutgoingPorts);
+ if(settings->szProxyAuthPassword) mir_free(settings->szProxyAuthPassword);
+ if(settings->szProxyAuthUser) mir_free(settings->szProxyAuthUser);
+ if(settings->szProxyServer) mir_free(settings->szProxyServer);
+}
+
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ nlncs->dwOwningThreadId= 0;
+ nlncs->lockCount=0;
+ nlncs->hMutex=CreateMutex(NULL,FALSE,NULL);
+}
+
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ CloseHandle(nlncs->hMutex);
+}
+
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which)
+{
+ struct NetlibNestedCriticalSection *nlncs;
+ DWORD dwCurrentThreadId=GetCurrentThreadId();
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(nlc==NULL || nlc->handleType!=NLH_CONNECTION) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ nlncs=which==NLNCS_SEND?&nlc->ncsSend:&nlc->ncsRecv;
+ if(nlncs->lockCount && (nlc->ncsRecv.dwOwningThreadId==dwCurrentThreadId || nlc->ncsSend.dwOwningThreadId==dwCurrentThreadId)) {
+ nlncs->lockCount++;
+ ReleaseMutex(hConnectionHeaderMutex);
+ return 1;
+ }
+ InterlockedIncrement(&nlc->dontCloseNow);
+ ResetEvent(nlc->hOkToCloseEvent);
+ ReleaseMutex(hConnectionHeaderMutex);
+ WaitForSingleObject(nlncs->hMutex,INFINITE);
+ nlncs->dwOwningThreadId=dwCurrentThreadId;
+ nlncs->lockCount=1;
+ if(InterlockedDecrement(&nlc->dontCloseNow)==0)
+ SetEvent(nlc->hOkToCloseEvent);
+ return 1;
+}
+
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ if(--nlncs->lockCount==0) {
+ nlncs->dwOwningThreadId=0;
+ ReleaseMutex(nlncs->hMutex);
+ }
+}
+
+static int GetNetlibUserSettingInt(const char *szUserModule,const char *szSetting,int defValue)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv))
+ return defValue;
+ if(dbv.type==DBVT_BYTE) return dbv.bVal;
+ if(dbv.type==DBVT_WORD) return dbv.wVal;
+ return dbv.dVal;
+}
+
+static char *GetNetlibUserSettingString(const char *szUserModule,const char *szSetting,int decode)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv)) {
+ return NULL;
+ }
+ else {
+ char *szRet;
+ if(decode) CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM)dbv.pszVal);
+ szRet=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if(szRet==NULL) SetLastError(ERROR_OUTOFMEMORY);
+ return szRet;
+ }
+}
+
+static int NetlibRegisterUser(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSER *nlu=(NETLIBUSER*)lParam;
+ struct NetlibUser *thisUser;
+ int i;
+
+ if(nlu==NULL || nlu->cbSize!=sizeof(NETLIBUSER) || nlu->szSettingsModule==NULL
+ || (!(nlu->flags&NUF_NOOPTIONS) && nlu->szDescriptiveName==NULL)
+ || (nlu->flags&NUF_HTTPGATEWAY && (nlu->pfnHttpGatewayInit==NULL))) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0;i<netlibUserCount;i++)
+ if(!lstrcmpA(netlibUser[i]->user.szSettingsModule,nlu->szSettingsModule)) {
+ LeaveCriticalSection(&csNetlibUser);
+ SetLastError(ERROR_DUP_NAME);
+ return (int)(HANDLE)NULL;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+
+ thisUser=(struct NetlibUser*)mir_calloc(sizeof(struct NetlibUser));
+ thisUser->handleType=NLH_USER;
+ thisUser->user=*nlu;
+ if((thisUser->user.szSettingsModule=mir_strdup(nlu->szSettingsModule))==NULL
+ || (nlu->szDescriptiveName && (thisUser->user.szDescriptiveName=mir_strdup(nlu->szDescriptiveName))==NULL)
+ || (nlu->szHttpGatewayUserAgent && (thisUser->user.szHttpGatewayUserAgent=mir_strdup(nlu->szHttpGatewayUserAgent))==NULL)) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(HANDLE)NULL;
+ }
+ if (nlu->szHttpGatewayHello)
+ thisUser->user.szHttpGatewayHello=mir_strdup(nlu->szHttpGatewayHello);
+ else
+ thisUser->user.szHttpGatewayHello=NULL;
+
+ thisUser->settings.cbSize=sizeof(NETLIBUSERSETTINGS);
+ thisUser->settings.useProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxy",0);
+ thisUser->settings.proxyType=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyType",PROXYTYPE_SOCKS5);
+ if(thisUser->user.flags&NUF_NOHTTPSOPTION && thisUser->settings.proxyType==PROXYTYPE_HTTPS)
+ thisUser->settings.proxyType=PROXYTYPE_HTTP;
+ if(!(thisUser->user.flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) && thisUser->settings.proxyType==PROXYTYPE_HTTP) {
+ thisUser->settings.useProxy=0;
+ thisUser->settings.proxyType=PROXYTYPE_SOCKS5;
+ }
+ thisUser->settings.szProxyServer=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyServer",0);
+ thisUser->settings.wProxyPort=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyPort",1080);
+ thisUser->settings.useProxyAuth=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuth",0);
+ thisUser->settings.szProxyAuthUser=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthUser",0);
+ thisUser->settings.szProxyAuthPassword=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthPassword",1);
+ thisUser->settings.useProxyAuthNtlm=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuthNtlm",0);
+ thisUser->settings.dnsThroughProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLDnsThroughProxy",1);
+ thisUser->settings.specifyIncomingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyIncomingPorts",0);
+ thisUser->settings.szIncomingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLIncomingPorts",0);
+ thisUser->settings.specifyOutgoingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyOutgoingPorts",0);
+ thisUser->settings.szOutgoingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLOutgoingPorts",0);
+
+ EnterCriticalSection(&csNetlibUser);
+ netlibUser=(struct NetlibUser**)mir_realloc(netlibUser,sizeof(struct NetlibUser*)*++netlibUserCount);
+ netlibUser[netlibUserCount-1]=thisUser;
+ LeaveCriticalSection(&csNetlibUser);
+ return (int)thisUser;
+}
+
+static int NetlibGetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ *nlus=nlu->settings;
+ return 1;
+}
+
+static int NetlibSetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ NetlibSaveUserSettingsStruct(nlu->user.szSettingsModule,nlus);
+ return 1;
+}
+
+int NetlibCloseHandle(WPARAM wParam,LPARAM lParam)
+{
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_USER:
+ { struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ int i;
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0;i<netlibUserCount;i++)
+ if(!lstrcmpA(netlibUser[i]->user.szSettingsModule,nlu->user.szSettingsModule)) {
+ netlibUserCount--;
+ memmove(netlibUser+i,netlibUser+i+1,(netlibUserCount-i)*sizeof(struct NetlibUser*));
+ break;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ if(nlu->user.szSettingsModule) mir_free(nlu->user.szSettingsModule);
+ if(nlu->user.szDescriptiveName) mir_free(nlu->user.szDescriptiveName);
+ if(nlu->user.szHttpGatewayHello) mir_free(nlu->user.szHttpGatewayHello);
+ if(nlu->user.szHttpGatewayUserAgent) mir_free(nlu->user.szHttpGatewayUserAgent);
+ if(nlu->szStickyHeaders) mir_free(nlu->szStickyHeaders);
+ break;
+ }
+ case NLH_CONNECTION:
+ { struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ HANDLE waitHandles[4];
+ DWORD waitResult;
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if (nlc->usingHttpGateway) + { + struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue; + while (p != NULL) { + struct NetlibHTTPProxyPacketQueue *t = p; + + p = p->next; + + mir_free(t->dataBuffer); + mir_free(t); + } + } + else + { + if(nlc->handleType!=NLH_CONNECTION || nlc->s==INVALID_SOCKET) { + ReleaseMutex(hConnectionHeaderMutex); + SetLastError(ERROR_INVALID_PARAMETER); //already been closed + return 0; + } + closesocket(nlc->s); + nlc->s=INVALID_SOCKET; + }
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ waitHandles[0]=hConnectionHeaderMutex;
+ waitHandles[1]=nlc->hOkToCloseEvent;
+ waitHandles[2]=nlc->ncsRecv.hMutex;
+ waitHandles[3]=nlc->ncsSend.hMutex;
+ waitResult=WaitForMultipleObjects( SIZEOF(waitHandles),waitHandles,TRUE,INFINITE);
+ if(waitResult<WAIT_OBJECT_0 || waitResult >= WAIT_OBJECT_0 + SIZEOF(waitHandles)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER); //already been closed
+ return 0;
+ }
+ nlc->handleType=0;
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->dataBuffer) mir_free(nlc->dataBuffer);
+ if(nlc->hInstSecurityDll) FreeLibrary(nlc->hInstSecurityDll);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ ReleaseMutex(hConnectionHeaderMutex);
+ Netlib_Logf(nlc->nlu,"(%p:%u) Connection closed",nlc,nlc->s);
+ break;
+ }
+ case NLH_BOUNDPORT:
+ return NetlibFreeBoundPort((struct NetlibBoundPort*)wParam);
+ case NLH_PACKETRECVER:
+ { struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ mir_free(nlpr->packetRecver.buffer);
+ break;
+ }
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ mir_free((void*)wParam);
+ return 1;
+}
+
+static int NetlibGetSocket(WPARAM wParam,LPARAM lParam)
+{
+ SOCKET s;
+ if((void*)wParam==NULL) {
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else {
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_CONNECTION:
+ s=(int)((struct NetlibConnection*)wParam)->s;
+ break;
+ case NLH_BOUNDPORT:
+ s=(int)((struct NetlibBoundPort*)wParam)->s;
+ break;
+ default:
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ break;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ }
+ return s;
+}
+
+static char szHexDigits[]="0123456789ABCDEF";
+int NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam)
+{
+ unsigned char *szOutput,*szInput=(unsigned char*)lParam;
+ unsigned char *pszIn,*pszOut;
+ int outputLen;
+
+ if(szInput==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(char*)NULL;
+ }
+ for(outputLen=0,pszIn=szInput;*pszIn;pszIn++) {
+ if(isalnum(*pszIn) || *pszIn==' ') outputLen++;
+ else outputLen+=3;
+ }
+ szOutput=(unsigned char*)HeapAlloc(GetProcessHeap(),0,outputLen+1);
+ if(szOutput==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(unsigned char*)NULL;
+ }
+ for(pszOut=szOutput,pszIn=szInput;*pszIn;pszIn++) {
+ if(isalnum(*pszIn)) *pszOut++=*pszIn;
+ else if(*pszIn==' ') *pszOut++='+';
+ else {
+ *pszOut++='%';
+ *pszOut++=szHexDigits[*pszIn>>4];
+ *pszOut++=szHexDigits[*pszIn&0xF];
+ }
+ }
+ *pszOut='\0';
+ return (int)szOutput;
+}
+
+static char base64chars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+int NetlibBase64Encode(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ int iIn;
+ char *pszOut;
+ PBYTE pbIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded<Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded);
+ for(iIn=0,pbIn=nlb64->pbDecoded,pszOut=nlb64->pszEncoded;iIn<nlb64->cbDecoded;iIn+=3,pbIn+=3,pszOut+=4) {
+ pszOut[0]=base64chars[pbIn[0]>>2];
+ if(nlb64->cbDecoded-iIn==1) {
+ pszOut[1]=base64chars[(pbIn[0]&3)<<4];
+ pszOut[2]='=';
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[1]=base64chars[((pbIn[0]&3)<<4)|(pbIn[1]>>4)];
+ if(nlb64->cbDecoded-iIn==2) {
+ pszOut[2]=base64chars[(pbIn[1]&0xF)<<2];
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[2]=base64chars[((pbIn[1]&0xF)<<2)|(pbIn[2]>>6)];
+ pszOut[3]=base64chars[pbIn[2]&0x3F];
+ }
+ pszOut[0]='\0';
+ return 1;
+}
+
+static BYTE Base64CharToInt(char c)
+{
+ if(c>='A' && c<='Z') return c-'A';
+ if(c>='a' && c<='z') return c-'a'+26;
+ if(c>='0' && c<='9') return c-'0'+52;
+ if(c=='+') return 62;
+ if(c=='/') return 63;
+ if(c=='=') return 64;
+ return 255;
+}
+
+int NetlibBase64Decode(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ char *pszIn;
+ PBYTE pbOut;
+ BYTE b1,b2,b3,b4;
+ int iIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded&3) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(nlb64->cbDecoded<Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded);
+ for(iIn=0,pszIn=nlb64->pszEncoded,pbOut=nlb64->pbDecoded;iIn<nlb64->cchEncoded;iIn+=4,pszIn+=4,pbOut+=3) {
+ b1=Base64CharToInt(pszIn[0]);
+ b2=Base64CharToInt(pszIn[1]);
+ b3=Base64CharToInt(pszIn[2]);
+ b4=Base64CharToInt(pszIn[3]);
+ if(b1==255 || b1==64 || b2==255 || b2==64 || b3==255 || b4==255) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ pbOut[0]=(b1<<2)|(b2>>4);
+ if(b3==64) {nlb64->cbDecoded-=2; break;}
+ pbOut[1]=(b2<<4)|(b3>>2);
+ if(b4==64) {nlb64->cbDecoded--; break;}
+ pbOut[2]=b4|(b3<<6);
+ }
+ return 1;
+}
+
+static int NetlibShutdown(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ NetlibLogShutdown();
+ for(i=netlibUserCount;i>0;i--)
+ NetlibCloseHandle((WPARAM)netlibUser[i-1],0);
+ if(netlibUser) mir_free(netlibUser);
+ CloseHandle(hConnectionHeaderMutex);
+ DeleteCriticalSection(&csNetlibUser);
+ WSACleanup();
+ return 0;
+}
+
+static int NetlibModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,NetlibShutdown); // get shutdown hook _after_ all the other plugins
+ return 0;
+}
+
+int LoadNetlibModule(void)
+{
+ WSADATA wsadata;
+
+ //HookEvent(ME_SYSTEM_SHUTDOWN,NetlibShutdown); // hooked later to be called last after plugins
+ HookEvent(ME_SYSTEM_MODULESLOADED, NetlibModulesLoaded);
+ HookEvent(ME_OPT_INITIALISE,NetlibOptInitialise);
+ WSAStartup(MAKEWORD(1,1), &wsadata);
+ InitializeCriticalSection(&csNetlibUser);
+ hConnectionHeaderMutex=CreateMutex(NULL,FALSE,NULL);
+ g_LastConnectionTick=GetTickCount();
+ NetlibLogInit();
+ CreateServiceFunction(MS_NETLIB_REGISTERUSER,NetlibRegisterUser);
+ CreateServiceFunction(MS_NETLIB_GETUSERSETTINGS,NetlibGetUserSettings);
+ CreateServiceFunction(MS_NETLIB_SETUSERSETTINGS,NetlibSetUserSettings);
+ CreateServiceFunction(MS_NETLIB_CLOSEHANDLE,NetlibCloseHandle);
+ CreateServiceFunction(MS_NETLIB_BINDPORT,NetlibBindPort);
+ CreateServiceFunction(MS_NETLIB_OPENCONNECTION,NetlibOpenConnection);
+ CreateServiceFunction(MS_NETLIB_SETHTTPPROXYINFO,NetlibHttpGatewaySetInfo);
+ CreateServiceFunction(MS_NETLIB_SETSTICKYHEADERS,NetlibHttpSetSticky);
+ CreateServiceFunction(MS_NETLIB_GETSOCKET,NetlibGetSocket);
+ CreateServiceFunction(MS_NETLIB_URLENCODE,NetlibHttpUrlEncode);
+ CreateServiceFunction(MS_NETLIB_BASE64ENCODE,NetlibBase64Encode);
+ CreateServiceFunction(MS_NETLIB_BASE64DECODE,NetlibBase64Decode);
+ CreateServiceFunction(MS_NETLIB_SENDHTTPREQUEST,NetlibHttpSendRequest);
+ CreateServiceFunction(MS_NETLIB_RECVHTTPHEADERS,NetlibHttpRecvHeaders);
+ CreateServiceFunction(MS_NETLIB_FREEHTTPREQUESTSTRUCT,NetlibHttpFreeRequestStruct);
+ CreateServiceFunction(MS_NETLIB_HTTPTRANSACTION,NetlibHttpTransaction);
+ CreateServiceFunction(MS_NETLIB_SEND,NetlibSend);
+ CreateServiceFunction(MS_NETLIB_RECV,NetlibRecv);
+ CreateServiceFunction(MS_NETLIB_SELECT,NetlibSelect);
+ CreateServiceFunction(MS_NETLIB_SELECTEX,NetlibSelectEx);
+ CreateServiceFunction(MS_NETLIB_CREATEPACKETRECVER,NetlibPacketRecverCreate);
+ CreateServiceFunction(MS_NETLIB_GETMOREPACKETS,NetlibPacketRecverGetMore);
+ CreateServiceFunction(MS_NETLIB_SETPOLLINGTIMEOUT,NetlibHttpSetPollingTimeout);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/netlib/netlib.h b/miranda-wine/src/modules/netlib/netlib.h new file mode 100644 index 0000000..8314397 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlib.h @@ -0,0 +1,157 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#define GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID)
+#define NLH_INVALID 0
+#define NLH_USER 'USER'
+#define NLH_CONNECTION 'CONN'
+#define NLH_BOUNDPORT 'BIND'
+#define NLH_PACKETRECVER 'PCKT'
+
+struct NetlibUser {
+ int handleType;
+ NETLIBUSER user;
+ NETLIBUSERSETTINGS settings;
+ char * szStickyHeaders;
+};
+
+struct NetlibNestedCriticalSection {
+ HANDLE hMutex;
+ DWORD dwOwningThreadId;
+ int lockCount;
+};
+
+struct NetlibHTTPProxyPacketQueue {
+ struct NetlibHTTPProxyPacketQueue *next;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+};
+
+struct NetlibConnection {
+ int handleType;
+ SOCKET s;
+ int usingHttpGateway;
+ struct NetlibUser *nlu;
+ SOCKADDR_IN sinProxy;
+ NETLIBHTTPPROXYINFO nlhpi;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+ DWORD dwLastGetSentTime;
+ CRITICAL_SECTION csHttpSequenceNums;
+ HANDLE hOkToCloseEvent;
+ LONG dontCloseNow;
+ struct NetlibNestedCriticalSection ncsSend,ncsRecv;
+ HINSTANCE hInstSecurityDll;
+ struct NetlibHTTPProxyPacketQueue * pHttpProxyPacketQueue;
+ int pollingTimeout;
+};
+
+struct NetlibBoundPort {
+ int handleType;
+ SOCKET s;
+ WORD wPort;
+ WORD wExPort;
+ struct NetlibUser *nlu;
+ NETLIBNEWCONNECTIONPROC_V2 pfnNewConnectionV2;
+ HANDLE hThread;
+ void *pExtra;
+};
+
+struct NetlibPacketRecver {
+ int handleType;
+ struct NetlibConnection *nlc;
+ NETLIBPACKETRECVER packetRecver;
+};
+
+//netlib.c
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings);
+int NetlibCloseHandle(WPARAM wParam,LPARAM lParam);
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs);
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs);
+#define NLNCS_SEND 0
+#define NLNCS_RECV 1
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which);
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs);
+int NetlibBase64Encode(WPARAM wParam,LPARAM lParam);
+int NetlibBase64Decode(WPARAM wParam,LPARAM lParam);
+int NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam);
+
+//netlibbind.c
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp);
+int NetlibBindPort(WPARAM wParam,LPARAM lParam);
+int StringToPortsMask(const char *szPorts,BYTE *mask);
+
+//netlibhttp.c
+int NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam);
+int NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam);
+int NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam);
+int NetlibHttpTransaction(WPARAM wParam,LPARAM lParam);
+void NetlibHttpSetLastErrorUsingHttpResult(int result);
+
+//netlibhttpproxy.c
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc);
+int NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam);
+int NetlibHttpSetPollingTimeout(WPARAM wParam,LPARAM lParam);
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags);
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags);
+int NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam);
+
+//netliblog.c
+void NetlibLogShowOptions(void);
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags);
+void NetlibLogInit(void);
+void NetlibLogShutdown(void);
+
+//netlibopenconn.c
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost);
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout);
+int NetlibOpenConnection(WPARAM wParam,LPARAM lParam);
+
+//netlibopts.c
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam);
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings);
+
+//netlibpktrecver.c
+int NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam);
+int NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam);
+
+//netlibsock.c
+int NetlibSend(WPARAM wParam,LPARAM lParam);
+int NetlibRecv(WPARAM wParam,LPARAM lParam);
+int NetlibSelect(WPARAM wParam,LPARAM lParam);
+int NetlibSelectEx(WPARAM wParam,LPARAM lParam);
+
+//netlibupnp.c
+BOOL NetlibUPnPAddPortMapping(WORD intport, char *proto,
+ WORD *extport, DWORD *extip, BOOL search);
+void NetlibUPnPDeletePortMapping(WORD extport, char* proto);
+
+static __inline int NLSend(struct NetlibConnection *nlc,const char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={(char*)buf,len,flags};
+ return NetlibSend((WPARAM)nlc,(LPARAM)&nlb);
+}
+static __inline int NLRecv(struct NetlibConnection *nlc,char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={buf,len,flags};
+ return NetlibRecv((WPARAM)nlc,(LPARAM)&nlb);
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibbind.c b/miranda-wine/src/modules/netlib/netlibbind.c new file mode 100644 index 0000000..383159f --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibbind.c @@ -0,0 +1,247 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+//mask must be 8192 bytes, returns number of bits set
+#define PortInMask(mask,p) ((mask)[((p)&0xFFFF)>>3]&(1<<((p)&7)))
+int StringToPortsMask(const char *szPorts,BYTE *mask)
+{
+ const char *psz;
+ char *pszEnd;
+ int portMin,portMax,port;
+ int bitCount=0;
+
+ ZeroMemory(mask,8192);
+ for(psz=szPorts;*psz;) {
+ while(*psz==' ' && *psz==',') psz++;
+ portMin=strtol(psz,&pszEnd,0);
+ if(pszEnd==psz) break;
+ while(*pszEnd==' ') pszEnd++;
+ if(*pszEnd=='-') {
+ psz=pszEnd+1;
+ portMax=strtol(psz,&pszEnd,0);
+ if(pszEnd==psz) portMax=65535;
+ if(portMin>portMax) {
+ port=portMin;
+ portMin=portMax;
+ portMax=port;
+ }
+ }
+ else portMax=portMin;
+ if(portMax>=1) {
+ if(portMin<=0) portMin=1;
+ for(port=portMin;port<=portMax;port++) {
+ if(port>65535) break;
+ if((port&7)==0 && portMax-port>=7) {mask[port>>3]=0xFF; port+=7; bitCount+=8;}
+ else {mask[port>>3]|=1<<(port&7); bitCount++;}
+ }
+ }
+ psz=pszEnd;
+ }
+ return bitCount;
+}
+
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
+{
+ closesocket(nlbp->s);
+ WaitForSingleObject(nlbp->hThread,INFINITE);
+ CloseHandle(nlbp->hThread);
+ NetlibUPnPDeletePortMapping(nlbp->wExPort, "TCP");
+ mir_free(nlbp);
+ return 1;
+}
+
+static DWORD __stdcall NetlibBindAcceptThread(struct NetlibBoundPort *nlbp)
+{
+ SOCKET s;
+ SOCKADDR_IN sin;
+ int sinLen;
+ struct NetlibConnection *nlc;
+
+ srand((unsigned int)time(NULL));
+ Netlib_Logf(nlbp->nlu,"(%d) Port %u opened for incoming connections",nlbp->s,nlbp->wPort);
+ for(;;) {
+ sinLen=sizeof(sin);
+ s=accept(nlbp->s,(struct sockaddr*)&sin,&sinLen);
+ if(s==INVALID_SOCKET) break;
+ Netlib_Logf(nlbp->nlu,"New incoming connection on port %u from %s (%d)",nlbp->wPort, inet_ntoa(sin.sin_addr),s);
+ nlc=(struct NetlibConnection*)mir_alloc(sizeof(struct NetlibConnection));
+ memset(nlc,0,sizeof(struct NetlibConnection));
+ nlc->handleType=NLH_CONNECTION;
+ nlc->nlu=nlbp->nlu;
+ nlc->s=s;
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ nlbp->pfnNewConnectionV2((HANDLE)nlc,ntohl(sin.sin_addr.S_un.S_addr), nlbp->pExtra);
+ }
+ return 0;
+}
+
+int NetlibBindPort(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBIND *nlb=(NETLIBBIND*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibBoundPort *nlbp;
+ SOCKADDR_IN sin;
+ int foundPort=0;
+ DWORD dwThreadId;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_INCOMING) || nlb==NULL || nlb->pfnNewConnection==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+ if ( nlb->cbSize != sizeof(NETLIBBIND) &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V2 &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V1 )
+ {
+ return (int)(HANDLE)NULL;
+ }
+ nlbp=(struct NetlibBoundPort*)mir_alloc(sizeof(struct NetlibBoundPort));
+ nlbp->handleType=NLH_BOUNDPORT;
+ nlbp->nlu=nlu;
+ nlbp->pfnNewConnectionV2=nlb->pfnNewConnectionV2;
+ nlbp->s=socket(AF_INET,SOCK_STREAM,0);
+ nlbp->pExtra= (nlb->cbSize == sizeof(NETLIBBIND)) ? nlb->pExtra : NULL;
+ if(nlbp->s==INVALID_SOCKET) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=htonl(INADDR_ANY);
+ sin.sin_port=0;
+ /* if the netlib user wanted a free port given in the range, then
+ they better have given wPort==0, let's hope so */
+ if(nlu->settings.specifyIncomingPorts && nlb->wPort==0) {
+ int startPort,portNum,i,j;
+ BYTE portsMask[8192];
+ int portsCount;
+
+ portsCount=StringToPortsMask(nlu->settings.szIncomingPorts,portsMask);
+ if(portsCount==0) {
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ SetLastError(WSAEADDRINUSE);
+ return (int)(HANDLE)NULL;
+ }
+ startPort=rand()%portsCount;
+ for(i=0;i<8192;i++) {
+ if(portsMask[i]==0) continue;
+ if(portsMask[i]==0xFF && startPort>=8) {startPort-=8; continue;}
+ for(j=0;j<8;j++)
+ if(portsMask[i]&(1<<j))
+ if(startPort--==0) {
+ portNum=(i<<3)+j;
+ break;
+ }
+ if(startPort==-1) break;
+ }
+ if(i==8192) return (int)(HANDLE)NULL; //can't happen
+ startPort=portNum;
+ do
+ {
+ sin.sin_port=htons((WORD)portNum);
+ if(bind(nlbp->s,(SOCKADDR *)&sin,sizeof(sin))==0) {
+ foundPort=1;
+ break;
+ }
+ for(portNum++;!PortInMask(portsMask,portNum);portNum++)
+ if(portNum==65535) portNum=0;
+ } while(portNum!=startPort);
+ }
+ else {
+ /* if ->wPort==0 then they'll get any free port, otherwise they'll
+ be asking for whatever was in nlb->wPort*/
+ if (nlb->wPort!=0) {
+ Netlib_Logf(nlu,"%s %d: trying to bind port %d, this 'feature' can be abused, please be sure you want to allow it.",__FILE__,__LINE__,nlb->wPort);
+ sin.sin_port=htons(nlb->wPort);
+ }
+ if(bind(nlbp->s,(SOCKADDR *)&sin,sizeof(sin))==0) foundPort=1;
+ }
+ if(!foundPort) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"bind",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+
+ if(listen(nlbp->s,5)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+
+ { int len;
+ DWORD extIP;
+
+ ZeroMemory(&sin,sizeof(sin));
+ len=sizeof(sin);
+ if(getsockname(nlbp->s,(SOCKADDR *)&sin,&len)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"getsockname",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return (int)(HANDLE)NULL;
+ }
+ nlb->wPort=ntohs(sin.sin_port);
+ nlbp->wPort=nlb->wPort;
+ nlb->dwInternalIP=ntohl(sin.sin_addr.S_un.S_addr);
+
+ if (nlb->dwInternalIP == 0)
+ {
+ char hostname[64];
+ struct hostent *he;
+
+ gethostname(hostname,SIZEOF(hostname));
+ he=gethostbyname(hostname);
+ if(he->h_addr_list[0])
+ nlb->dwInternalIP=ntohl(*(PDWORD)he->h_addr_list[0]);
+ }
+ if (NetlibUPnPAddPortMapping(nlb->wPort, "TCP", &nlbp->wExPort,
+ &extIP, nlb->cbSize > NETLIBBIND_SIZEOF_V2))
+ {
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlbp->wExPort;
+ nlb->dwExternalIP = extIP;
+ }
+ }
+ else
+ {
+ nlbp->wExPort = 0;
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlb->wPort;
+ nlb->dwExternalIP = nlb->dwInternalIP;
+ }
+ }
+
+ }
+ nlbp->hThread=(HANDLE)forkthreadex(NULL,0,NetlibBindAcceptThread,nlbp,0,&dwThreadId);
+ return (int)nlbp;
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibhttp.c b/miranda-wine/src/modules/netlib/netlibhttp.c new file mode 100644 index 0000000..5e47116 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibhttp.c @@ -0,0 +1,729 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#define SECURITY_WIN32
+#include <security.h>
+#include "netlib.h"
+
+// Old versions of ssapi.h defines "FreeCredentialHandle()", but the
+// function has since then been redefined to "FreeCredentialsHandle()"
+#ifndef FreeCredentialsHandle
+#define FreeCredentialsHandle FreeCredentialHandle
+#endif
+
+#define HTTPRECVHEADERSTIMEOUT 60000 //in ms
+
+struct ResizableCharBuffer {
+ char *sz;
+ int iEnd,cbAlloced;
+};
+
+static void AppendToCharBuffer(struct ResizableCharBuffer *rcb,const char *fmt,...)
+{
+ va_list va;
+ int charsDone;
+
+ if(rcb->cbAlloced==0) {
+ rcb->cbAlloced=512;
+ rcb->sz=(char*)mir_alloc(rcb->cbAlloced);
+ }
+ va_start(va,fmt);
+ for(;;) {
+ charsDone=mir_vsnprintf(rcb->sz+rcb->iEnd,rcb->cbAlloced-rcb->iEnd,fmt,va);
+ if(charsDone>=0) break;
+ rcb->cbAlloced+=512;
+ rcb->sz=(char*)mir_realloc(rcb->sz,rcb->cbAlloced);
+ }
+ va_end(va);
+ rcb->iEnd+=charsDone;
+}
+
+
+static PSecurityFunctionTableA pSecurityFunctions=NULL;
+static PSecPkgInfoA ntlmSecurityPackageInfo=NULL;
+static CtxtHandle hNtlmClientContext;
+static CredHandle hNtlmClientCredential;
+//mir_free() the return value
+static void NtlmDestroy(void)
+{
+ if (pSecurityFunctions)
+ {
+ pSecurityFunctions->DeleteSecurityContext(&hNtlmClientContext);
+ pSecurityFunctions->FreeCredentialsHandle(&hNtlmClientCredential);
+ } //if
+ if(ntlmSecurityPackageInfo) pSecurityFunctions->FreeContextBuffer(ntlmSecurityPackageInfo);
+ ntlmSecurityPackageInfo=NULL;
+}
+
+static char *NtlmInitialiseAndGetDomainPacket(HINSTANCE hInstSecurityDll)
+{
+ PSecurityFunctionTableA (*MyInitSecurityInterface)(VOID);
+ SECURITY_STATUS securityStatus;
+ SecBufferDesc outputBufferDescriptor;
+ SecBuffer outputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64;
+
+ MyInitSecurityInterface=(PSecurityFunctionTableA (*)(VOID))GetProcAddress(hInstSecurityDll,"InitSecurityInterfaceA");
+ if(MyInitSecurityInterface==NULL) {NtlmDestroy(); return NULL;}
+ pSecurityFunctions=MyInitSecurityInterface();
+ if(pSecurityFunctions==NULL) {NtlmDestroy(); return NULL;}
+
+ securityStatus=pSecurityFunctions->QuerySecurityPackageInfoA("NTLM",&ntlmSecurityPackageInfo);
+ if(securityStatus!=SEC_E_OK) {NtlmDestroy(); return NULL;}
+ securityStatus=pSecurityFunctions->AcquireCredentialsHandleA(NULL,"NTLM",SECPKG_CRED_OUTBOUND,NULL,NULL,NULL,NULL,&hNtlmClientCredential,&tokenExpiration);
+ if(securityStatus!=SEC_E_OK) {NtlmDestroy(); return NULL;}
+
+ outputBufferDescriptor.cBuffers=1;
+ outputBufferDescriptor.pBuffers=&outputSecurityToken;
+ outputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ outputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer=ntlmSecurityPackageInfo->cbMaxToken;
+ outputSecurityToken.pvBuffer=mir_alloc(outputSecurityToken.cbBuffer);
+ if(outputSecurityToken.pvBuffer==NULL) {NtlmDestroy(); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ securityStatus=pSecurityFunctions->InitializeSecurityContextA(&hNtlmClientCredential,NULL,NULL,0,0,SECURITY_NATIVE_DREP,NULL,0,&hNtlmClientContext,&outputBufferDescriptor,&contextAttributes,&tokenExpiration);
+ if(securityStatus!=SEC_I_CONTINUE_NEEDED) {mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); return NULL;}
+
+ nlb64.cbDecoded=outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded=outputSecurityToken.pvBuffer;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL) {mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Encode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pszEncoded); mir_free(outputSecurityToken.pvBuffer); NtlmDestroy(); return NULL;}
+ mir_free(outputSecurityToken.pvBuffer);
+ return nlb64.pszEncoded;
+}
+
+//mir_free() the result value
+static char *NtlmCreateResponseFromChallenge(char *szChallenge)
+{
+ SECURITY_STATUS securityStatus;
+ SecBufferDesc outputBufferDescriptor,inputBufferDescriptor;
+ SecBuffer outputSecurityToken,inputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64;
+
+ nlb64.cchEncoded=lstrlenA(szChallenge);
+ nlb64.pszEncoded=szChallenge;
+ nlb64.cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
+ nlb64.pbDecoded=(PBYTE)mir_alloc(nlb64.cbDecoded);
+ if(nlb64.pbDecoded==NULL) {SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Decode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pbDecoded); return NULL;}
+
+ inputBufferDescriptor.cBuffers=1;
+ inputBufferDescriptor.pBuffers=&inputSecurityToken;
+ inputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ inputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ inputSecurityToken.cbBuffer=nlb64.cbDecoded;
+ inputSecurityToken.pvBuffer=nlb64.pbDecoded;
+ outputBufferDescriptor.cBuffers=1;
+ outputBufferDescriptor.pBuffers=&outputSecurityToken;
+ outputBufferDescriptor.ulVersion=SECBUFFER_VERSION;
+ outputSecurityToken.BufferType=SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer=ntlmSecurityPackageInfo->cbMaxToken;
+ outputSecurityToken.pvBuffer=mir_alloc(outputSecurityToken.cbBuffer);
+ if(outputSecurityToken.pvBuffer==NULL) {mir_free(nlb64.pbDecoded); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ securityStatus=pSecurityFunctions->InitializeSecurityContextA(&hNtlmClientCredential,&hNtlmClientContext,NULL,0,0,SECURITY_NATIVE_DREP,&inputBufferDescriptor,0,&hNtlmClientContext,&outputBufferDescriptor,&contextAttributes,&tokenExpiration);
+ mir_free(nlb64.pbDecoded);
+ if(securityStatus!=SEC_E_OK) {mir_free(outputSecurityToken.pvBuffer); return NULL;}
+
+ nlb64.cbDecoded=outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded=outputSecurityToken.pvBuffer;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL) {mir_free(outputSecurityToken.pvBuffer); SetLastError(ERROR_OUTOFMEMORY); return NULL;}
+ if(!NetlibBase64Encode(0,(LPARAM)&nlb64))
+ {mir_free(nlb64.pszEncoded); mir_free(outputSecurityToken.pvBuffer); return NULL;}
+ mir_free(outputSecurityToken.pvBuffer);
+ return nlb64.pszEncoded;
+}
+
+static int RecvWithTimeoutTime(struct NetlibConnection *nlc,DWORD dwTimeoutTime,char *buf,int len,int flags)
+{
+ DWORD dwTimeNow;
+
+ dwTimeNow=GetTickCount();
+ if(dwTimeNow>=dwTimeoutTime
+ || !WaitUntilReadable(nlc->s,dwTimeoutTime-dwTimeNow)) {
+ if(dwTimeNow>=dwTimeoutTime) SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ return NLRecv(nlc,buf,len,flags);
+}
+
+static int HttpPeekFirstResponseLine(struct NetlibConnection *nlc,DWORD dwTimeoutTime,DWORD recvFlags,int *resultCode,char **ppszResultDescr,int *length)
+{
+ int bytesPeeked=0;
+ char buffer[1024];
+ char *peol;
+
+ for(;;) {
+ bytesPeeked=RecvWithTimeoutTime(nlc,dwTimeoutTime,buffer,SIZEOF(buffer)-1,MSG_PEEK|recvFlags);
+ if(bytesPeeked==0 || bytesPeeked==SOCKET_ERROR) {
+ if(bytesPeeked==0) SetLastError(ERROR_HANDLE_EOF);
+ return 0;
+ }
+ buffer[bytesPeeked]='\0';
+ peol=strchr(buffer,'\n');
+ if(peol==NULL) {
+ if(lstrlenA(buffer)<bytesPeeked) {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ if(bytesPeeked==SIZEOF(buffer)-1) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ Sleep(10);
+ continue;
+ }
+ if(peol==buffer || *--peol!='\r') {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ *peol='\0';
+ {
+ char *pResultCode,*pResultDescr,*pHttpMajor,*pHttpMinor;
+ int tokenLen;
+ int httpMajorVer,httpMinorVer;
+ if(peol==buffer
+ || _strnicmp(buffer,"http/",5)
+ || (httpMajorVer=strtol(pHttpMajor=buffer+5,&pHttpMinor,10))<0
+ || pHttpMajor==pHttpMinor
+ || httpMajorVer>1
+ || *pHttpMinor++!='.'
+ || (httpMinorVer=strtol(pHttpMinor,&pResultCode,10))<0
+ || pResultCode==pHttpMinor
+ || (tokenLen=strspn(pResultCode," \t"))==0
+ || (*resultCode=strtol(pResultCode+=tokenLen,&pResultDescr,10))==0
+ || pResultDescr==pResultCode
+ || (tokenLen=strspn(pResultDescr," \t"))==0
+ || *(pResultDescr+=tokenLen)=='\0') {
+ SetLastError(peol==buffer?ERROR_BAD_FORMAT:ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(ppszResultDescr) *ppszResultDescr=mir_strdup(pResultDescr);
+ if(length) *length=peol-buffer+2;
+ }
+ return 1;
+ }
+}
+
+static int SendHttpRequestAndData(struct NetlibConnection *nlc,struct ResizableCharBuffer *httpRequest,NETLIBHTTPREQUEST *nlhr,int sendContentLengthHeader)
+{
+ int bytesSent;
+
+ if((nlhr->requestType==REQUEST_POST)) {
+ if(sendContentLengthHeader)
+ AppendToCharBuffer(httpRequest,"Content-Length: %d\r\n\r\n",nlhr->dataLength);
+ else
+ AppendToCharBuffer(httpRequest,"\r\n");
+ bytesSent=NLSend(nlc,httpRequest->sz,httpRequest->iEnd,MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ mir_free(httpRequest->sz);
+ if (nlhr->dataLength) {
+ int sendResult;
+
+ if(bytesSent==SOCKET_ERROR
+ || SOCKET_ERROR==(sendResult=NLSend(nlc,nlhr->pData,nlhr->dataLength,(nlhr->flags&NLHRF_DUMPASTEXT?MSG_DUMPASTEXT:0)|(nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0))))) {
+ return SOCKET_ERROR;
+ }
+ bytesSent+=sendResult;
+ }
+ }
+ else {
+ AppendToCharBuffer(httpRequest,"\r\n");
+ bytesSent=NLSend(nlc,httpRequest->sz,httpRequest->iEnd,MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ mir_free(httpRequest->sz);
+ }
+ return bytesSent;
+}
+
+int NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+ struct ResizableCharBuffer httpRequest={0};
+ char *pszRequest,*szHost,*pszUrl;
+ char *pszProxyAuthorizationHeader;
+ int i,doneHostHeader,doneContentLengthHeader,doneProxyAuthHeader,usingNtlmAuthentication;
+ int useProxyHttpAuth,bytesSent;
+
+ if(nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl==NULL || nlhr->szUrl[0]=='\0') {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ switch(nlhr->requestType) {
+ case REQUEST_GET: pszRequest="GET"; break;
+ case REQUEST_POST: pszRequest="POST"; break;
+ case REQUEST_CONNECT: pszRequest="CONNECT"; break;
+ case REQUEST_HEAD:pszRequest="HEAD"; break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_SEND)) return SOCKET_ERROR;
+
+ //first line: "GET /index.html HTTP/1.0\r\n"
+ szHost=NULL;
+ if(nlhr->flags&(NLHRF_SMARTREMOVEHOST|NLHRF_REMOVEHOST|NLHRF_GENERATEHOST)){
+ char *ppath,*phost;
+ phost=strstr(nlhr->szUrl,"://");
+ if(phost==NULL) phost=nlhr->szUrl;
+ else phost+=3;
+ ppath=strchr(phost,'/');
+ if(ppath==NULL) ppath=phost+lstrlenA(phost);
+ if(nlhr->flags&NLHRF_GENERATEHOST) {
+ szHost=(char*)mir_alloc(ppath-phost+1);
+ lstrcpynA(szHost,phost,ppath-phost+1);
+ }
+ if(nlhr->flags&NLHRF_REMOVEHOST
+ || (nlhr->flags&NLHRF_SMARTREMOVEHOST
+ && (!nlc->nlu->settings.useProxy
+ || !(nlc->nlu->settings.proxyType==PROXYTYPE_HTTP || nlc->nlu->settings.proxyType==PROXYTYPE_HTTPS)))) {
+ pszUrl=ppath;
+ }
+ else pszUrl=nlhr->szUrl;
+ }
+ else pszUrl=nlhr->szUrl;
+ AppendToCharBuffer(&httpRequest, "%s %s HTTP/1.%d\r\n", pszRequest, pszUrl, (nlhr->flags & NLHRF_HTTP11) != 0); +
+ //if (nlhr->dataLength > 0)
+ // AppendToCharBuffer(&httpRequest,"Content-Length: %d\r\n",nlhr->dataLength);
+
+ //proxy auth initialization + useProxyHttpAuth=nlhr->flags&NLHRF_SMARTAUTHHEADER && nlc->nlu->settings.useProxy && nlc->nlu->settings.useProxyAuth && (nlc->nlu->settings.proxyType==PROXYTYPE_HTTP || nlc->nlu->settings.proxyType==PROXYTYPE_HTTPS);
+ usingNtlmAuthentication=0;
+ if(useProxyHttpAuth) {
+ if(nlc->nlu->settings.useProxyAuthNtlm) {
+ char *pszNtlmAuth;
+ pszNtlmAuth=NtlmInitialiseAndGetDomainPacket(nlc->hInstSecurityDll);
+ if(pszNtlmAuth==NULL) {useProxyHttpAuth=0; pszProxyAuthorizationHeader=NULL;}
+ else {
+ pszProxyAuthorizationHeader=(char*)mir_alloc(lstrlenA(pszNtlmAuth)+6);
+ lstrcpyA(pszProxyAuthorizationHeader,"NTLM ");
+ lstrcatA(pszProxyAuthorizationHeader,pszNtlmAuth);
+ mir_free(pszNtlmAuth);
+ usingNtlmAuthentication=1;
+ }
+ }
+ else {
+ NETLIBBASE64 nlb64;
+ char szAuth[512];
+ mir_snprintf(szAuth,SIZEOF(szAuth),"%s:%s",nlc->nlu->settings.szProxyAuthUser,nlc->nlu->settings.szProxyAuthPassword);
+ nlb64.cbDecoded=lstrlenA(szAuth);
+ nlb64.pbDecoded=szAuth;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ NetlibBase64Encode(0,(LPARAM)&nlb64);
+ pszProxyAuthorizationHeader=(char*)mir_alloc(lstrlenA(nlb64.pszEncoded)+7);
+ lstrcpyA(pszProxyAuthorizationHeader,"Basic ");
+ lstrcatA(pszProxyAuthorizationHeader,nlb64.pszEncoded);
+ mir_free(nlb64.pszEncoded);
+ }
+ }
+ else pszProxyAuthorizationHeader=NULL;
+
+ //HTTP headers
+ doneHostHeader=doneContentLengthHeader=doneProxyAuthHeader=0;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"Host")) doneHostHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Content-Length")) doneContentLengthHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Proxy-Authorization")) doneProxyAuthHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Connection") && usingNtlmAuthentication) continue;
+ if(nlhr->headers[i].szValue==NULL) continue;
+ AppendToCharBuffer(&httpRequest,"%s: %s\r\n",nlhr->headers[i].szName,nlhr->headers[i].szValue);
+ }
+ if(szHost && !doneHostHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Host",szHost);
+ if(pszProxyAuthorizationHeader) {
+ if(!doneProxyAuthHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Proxy-Authorization",pszProxyAuthorizationHeader);
+ mir_free(pszProxyAuthorizationHeader);
+ if(usingNtlmAuthentication) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Connection","Keep-Alive");
+ }
+
+ // Add Sticky Headers
+ if (nlc->nlu->szStickyHeaders != NULL) {
+ AppendToCharBuffer(&httpRequest,"%s\r\n", nlc->nlu->szStickyHeaders);
+ }
+
+ //send it
+ bytesSent=SendHttpRequestAndData(nlc,&httpRequest,nlhr,!doneContentLengthHeader);
+ if(bytesSent==SOCKET_ERROR) {
+ if(usingNtlmAuthentication) NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+
+ //ntlm reply
+ if(usingNtlmAuthentication) {
+ int resultCode=0;
+
+ if(!HttpPeekFirstResponseLine(nlc,GetTickCount()+5000,MSG_PEEK|MSG_DUMPASTEXT|(nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)),&resultCode,NULL,NULL)
+ || ((resultCode<200 || resultCode>=300) && resultCode!=407)) {
+ NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ if(resultCode) NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ return SOCKET_ERROR;
+ }
+ if(resultCode==407) { //proxy auth required
+ NETLIBHTTPREQUEST *nlhrReply;
+ int i,error,contentLength=0;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,nlhr->flags&(NLHRF_NODUMP|NLHRF_NODUMPHEADERS)?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0));
+ if(nlhrReply==NULL) {
+ NtlmDestroy();
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ if(resultCode) NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ return SOCKET_ERROR;
+ }
+ pszProxyAuthorizationHeader=NULL;
+ error=ERROR_SUCCESS;
+ for(i=0;i<nlhrReply->headersCount;i++) {
+ if(!lstrcmpiA(nlhrReply->headers[i].szName,"Proxy-Authenticate")) {
+ if(!_strnicmp(nlhrReply->headers[i].szValue,"NTLM ",5))
+ pszProxyAuthorizationHeader=NtlmCreateResponseFromChallenge(nlhrReply->headers[i].szValue+5);
+ else error=ERROR_ACCESS_DENIED;
+ }
+ else if(!lstrcmpiA(nlhrReply->headers[i].szName,"Content-Length"))
+ contentLength=atoi(nlhrReply->headers[i].szValue);
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NtlmDestroy();
+ if(pszProxyAuthorizationHeader==NULL) {
+ if(error!=ERROR_SUCCESS) SetLastError(error);
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+
+ //receive content and throw away
+ { BYTE trashBuf[512];
+ int recvResult;
+
+ while(contentLength) {
+ recvResult=NLRecv(nlc,trashBuf,SIZEOF(trashBuf),nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:MSG_DUMPASTEXT|MSG_DUMPPROXY);
+ if(recvResult==0 || recvResult==SOCKET_ERROR) {
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+ contentLength-=recvResult;
+ }
+ }
+
+ httpRequest.cbAlloced=httpRequest.iEnd=0;
+ httpRequest.sz=NULL;
+ AppendToCharBuffer(&httpRequest,"%s %s HTTP/1.0\r\n",pszRequest,pszUrl);
+
+ //HTTP headers
+ doneHostHeader=doneContentLengthHeader=0;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"Host")) doneHostHeader=1;
+ else if(!lstrcmpiA(nlhr->headers[i].szName,"Content-Length")) doneContentLengthHeader=1;
+ if(nlhr->headers[i].szValue==NULL) continue;
+ AppendToCharBuffer(&httpRequest,"%s: %s\r\n",nlhr->headers[i].szName,nlhr->headers[i].szValue);
+ }
+ if(szHost) {
+ if(!doneHostHeader) AppendToCharBuffer(&httpRequest,"%s: %s\r\n","Host",szHost);
+ mir_free(szHost); szHost=NULL;
+ }
+ AppendToCharBuffer(&httpRequest,"%s: NTLM %s\r\n","Proxy-Authorization",pszProxyAuthorizationHeader);
+
+ //send it
+ bytesSent=SendHttpRequestAndData(nlc,&httpRequest,nlhr,!doneContentLengthHeader);
+ if(bytesSent==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return SOCKET_ERROR;
+ }
+ }
+ else NtlmDestroy();
+ }
+
+ //clean up
+ if(szHost) mir_free(szHost);
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return bytesSent;
+}
+
+int NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+
+ if(nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->requestType!=REQUEST_RESPONSE) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlhr->headers) {
+ int i;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(nlhr->headers[i].szName) mir_free(nlhr->headers[i].szName);
+ if(nlhr->headers[i].szValue) mir_free(nlhr->headers[i].szValue);
+ }
+ mir_free(nlhr->headers);
+ }
+ if(nlhr->pData) mir_free(nlhr->pData);
+ if(nlhr->szResultDescr) mir_free(nlhr->szResultDescr);
+ if(nlhr->szUrl) mir_free(nlhr->szUrl);
+ mir_free(nlhr);
+ return 1;
+}
+
+int NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr;
+ char buffer[4096];
+ int bytesPeeked;
+ DWORD dwRequestTimeoutTime;
+ char *peol,*pbuffer;
+ int headersDone=0,firstLineLength;
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV))
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ dwRequestTimeoutTime=GetTickCount()+HTTPRECVHEADERSTIMEOUT;
+ nlhr=(NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST));
+ nlhr->cbSize=sizeof(NETLIBHTTPREQUEST);
+ nlhr->nlc=nlc;
+ nlhr->requestType=REQUEST_RESPONSE;
+ if(!HttpPeekFirstResponseLine(nlc,dwRequestTimeoutTime,lParam|MSG_PEEK,&nlhr->resultCode,&nlhr->szResultDescr,&firstLineLength)) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr); + return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ bytesPeeked=NLRecv(nlc,buffer,firstLineLength,lParam|MSG_DUMPASTEXT);
+ if(bytesPeeked<firstLineLength) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(bytesPeeked!=SOCKET_ERROR) SetLastError(ERROR_HANDLE_EOF);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ for(;;) {
+ bytesPeeked=RecvWithTimeoutTime(nlc,dwRequestTimeoutTime,buffer,SIZEOF(buffer)-1,MSG_PEEK|lParam);
+ if(bytesPeeked==0 || bytesPeeked==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(bytesPeeked==0) SetLastError(ERROR_HANDLE_EOF);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ buffer[bytesPeeked]='\0';
+ for(pbuffer=buffer;;) {
+ peol=strchr(pbuffer,'\n');
+ if(peol==NULL) {
+ if(lstrlenA(buffer)<bytesPeeked) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_BAD_FORMAT);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ if((bytesPeeked == SIZEOF(buffer)-1 && pbuffer==buffer) //buffer overflow
+ || (pbuffer!=buffer && NLRecv(nlc,buffer,pbuffer-buffer,lParam|MSG_DUMPASTEXT)==SOCKET_ERROR)) { //error removing read bytes from buffer
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ if(pbuffer==buffer) SetLastError(ERROR_BUFFER_OVERFLOW);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ Sleep(100);
+ break;
+ }
+ if(peol==pbuffer || *--peol!='\r') {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_BAD_FORMAT);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ *peol='\0';
+ {
+ char *pColon;
+ int len;
+ if(peol==pbuffer) { //blank line: end of headers
+ if(NLRecv(nlc,buffer,peol+2-buffer,lParam|MSG_DUMPASTEXT)==SOCKET_ERROR) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ headersDone=1;
+ break;
+ }
+ pColon=strchr(pbuffer,':');
+ if(pColon==NULL) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhr);
+ SetLastError(ERROR_INVALID_DATA);
+ return (int)(NETLIBHTTPREQUEST*)NULL;
+ }
+ nlhr->headersCount++;
+ nlhr->headers=(NETLIBHTTPHEADER*)mir_realloc(nlhr->headers,sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ nlhr->headers[nlhr->headersCount-1].szName=(char*)mir_alloc(pColon-pbuffer+1);
+ lstrcpynA(nlhr->headers[nlhr->headersCount-1].szName,pbuffer,pColon-pbuffer+1);
+ len=lstrlenA(nlhr->headers[nlhr->headersCount-1].szName);
+ while(len && (nlhr->headers[nlhr->headersCount-1].szName[len-1]==' ' || nlhr->headers[nlhr->headersCount-1].szName[len-1]=='\t'))
+ nlhr->headers[nlhr->headersCount-1].szName[--len]='\0';
+ pColon++;
+ while(*pColon==' ' || *pColon=='\t') pColon++;
+ nlhr->headers[nlhr->headersCount-1].szValue=mir_strdup(pColon);
+ }
+ pbuffer=peol+2;
+ }
+ if(headersDone) break;
+ }
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ return (int)nlhr;
+}
+
+int NetlibHttpTransaction(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam,*nlhrReply;
+ HANDLE hConnection;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_OUTGOING) || nlhr==NULL || nlhr->cbSize!=sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl==NULL || nlhr->szUrl[0]=='\0') {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+
+ {
+ NETLIBOPENCONNECTION nloc={0};
+ char szHost[128];
+ char *ppath,*phost,*pcolon;
+
+ phost=strstr(nlhr->szUrl,"://");
+ if(phost==NULL) phost=nlhr->szUrl;
+ else phost+=3;
+ lstrcpynA(szHost,phost,SIZEOF(szHost));
+ ppath=strchr(szHost,'/');
+ if(ppath) *ppath='\0';
+ nloc.cbSize=sizeof(nloc);
+ nloc.szHost=szHost;
+ pcolon=strrchr(szHost,':');
+ if(pcolon) {
+ *pcolon='\0';
+ nloc.wPort=(WORD)strtol(pcolon+1,NULL,10);
+ }
+ else nloc.wPort=80;
+ nloc.flags=NLOCF_HTTP;
+ hConnection=(HANDLE)NetlibOpenConnection((WPARAM)nlu,(LPARAM)&nloc);
+ if(hConnection==NULL) return (int)(HANDLE)NULL;
+ }
+
+ {
+ NETLIBHTTPREQUEST nlhrSend;
+ int i,doneUserAgentHeader=0;
+ char szUserAgent[64];
+
+ nlhrSend=*nlhr;
+ nlhrSend.flags&=~NLHRF_REMOVEHOST;
+ nlhrSend.flags|=NLHRF_GENERATEHOST|NLHRF_SMARTREMOVEHOST|NLHRF_SMARTAUTHHEADER;
+ for(i=0;i<nlhr->headersCount;i++) {
+ if(!lstrcmpiA(nlhr->headers[i].szName,"User-Agent"))
+ doneUserAgentHeader=1;
+ }
+ if(!doneUserAgentHeader) {
+ char *pspace,szMirandaVer[32];
+
+ nlhrSend.headersCount++;
+ nlhrSend.headers=(NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhrSend.headersCount);
+ CopyMemory(nlhrSend.headers,nlhr->headers,sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ nlhrSend.headers[nlhrSend.headersCount-1].szName="User-Agent";
+ nlhrSend.headers[nlhrSend.headersCount-1].szValue=szUserAgent;
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szMirandaVer),(LPARAM)szMirandaVer);
+ pspace=strchr(szMirandaVer,' ');
+ if(pspace) {
+ *pspace++='\0';
+ mir_snprintf(szUserAgent,SIZEOF(szUserAgent),"Miranda/%s (%s)",szMirandaVer,pspace);
+ }
+ else mir_snprintf(szUserAgent,SIZEOF(szUserAgent),"Miranda/%s",szMirandaVer);
+ }
+ if(NetlibHttpSendRequest((WPARAM)hConnection,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ if(!doneUserAgentHeader) mir_free(nlhrSend.headers);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ if(!doneUserAgentHeader) mir_free(nlhrSend.headers);
+ }
+
+ {
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)hConnection,0);
+ if(nlhrReply==NULL) {
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ } }
+
+ if (nlhr->requestType != REQUEST_HEAD){
+ int recvResult;
+ int dataBufferAlloced=0;
+
+ for(;;) {
+ if(dataBufferAlloced-nlhrReply->dataLength<1024) {
+ dataBufferAlloced+=2048;
+ nlhrReply->pData=(PBYTE)mir_realloc(nlhrReply->pData,dataBufferAlloced);
+ if(nlhrReply->pData==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ recvResult=NLRecv((struct NetlibConnection*)hConnection,nlhrReply->pData+nlhrReply->dataLength,dataBufferAlloced-nlhrReply->dataLength-1,(nlhr->flags&NLHRF_DUMPASTEXT?MSG_DUMPASTEXT:0)|(nlhr->flags&NLHRF_NODUMP?MSG_NODUMP:(nlhr->flags&NLHRF_DUMPPROXY?MSG_DUMPPROXY:0)));
+ if(recvResult==0) break;
+ if(recvResult==SOCKET_ERROR) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)(HANDLE)NULL;
+ }
+ nlhrReply->dataLength+=recvResult;
+ //TODO: Keep-alive replies are measured by content-length, not by when the connection closes
+ }
+ nlhrReply->pData[nlhrReply->dataLength]='\0';
+ }
+
+ NetlibCloseHandle((WPARAM)hConnection,0);
+ return (int)nlhrReply;
+}
+
+void NetlibHttpSetLastErrorUsingHttpResult(int result)
+{
+ if(result>=200 && result<300) {
+ SetLastError(ERROR_SUCCESS);
+ return;
+ }
+ switch(result) {
+ case 400: SetLastError(ERROR_BAD_FORMAT); break;
+ case 401:
+ case 402:
+ case 403:
+ case 407: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 404: SetLastError(ERROR_FILE_NOT_FOUND); break;
+ case 405:
+ case 406: SetLastError(ERROR_INVALID_FUNCTION); break;
+ case 408: SetLastError(ERROR_TIMEOUT); break;
+ default: SetLastError(ERROR_GEN_FAILURE); break;
+ }
+}
diff --git a/miranda-wine/src/modules/netlib/netlibhttpproxy.c b/miranda-wine/src/modules/netlib/netlibhttpproxy.c new file mode 100644 index 0000000..f3fc82e --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibhttpproxy.c @@ -0,0 +1,610 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+#define HTTPGETTIMEOUT 55000 //in ms. http GETs through most proxies will give up after a while so the request needs to be re-sent
+
+static int HttpGatewaySendGet(struct NetlibConnection *nlc)
+{
+ NETLIBHTTPREQUEST nlhrSend={0};
+ NETLIBHTTPHEADER httpHeaders[3];
+ char szUrl[512];
+ struct NetlibConnection nlcSend;
+
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ return 0;
+ }
+
+ if(connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy))==SOCKET_ERROR) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ return 0;
+ }
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+
+ /*
+ * Gena01 - one small change here, just in case there is a timeout or a problem and we died while
+ * receiving
+ */
+ nlhrSend.requestType=(nlc->nlhpi.szHttpGetUrl == NULL) ? REQUEST_POST : REQUEST_GET;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER; + if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11; +
+ /*
+ * Gena01 - fixing a possible crash, can't use GET Sequence if there is no GET URL
+ */
+ if ((nlc->nlhpi.flags&NLHPIF_USEGETSEQUENCE) && (nlc->nlhpi.szHttpGetUrl != NULL)) {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s%u",nlc->nlhpi.szHttpGetUrl,nlc->nlhpi.firstGetSequence);
+ nlc->nlhpi.firstGetSequence++;
+ if(nlc->nlhpi.flags&NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstPostSequence++;
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl=szUrl;
+ }
+ else nlhrSend.szUrl=(nlc->nlhpi.szHttpGetUrl == NULL) ? nlc->nlhpi.szHttpPostUrl : nlc->nlhpi.szHttpGetUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount= 3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlc->nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+
+ nlcSend=*nlc;
+ nlcSend.usingHttpGateway=0;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL) {
+
+ Netlib_Logf(nlc->nlu,"%s %d: Sending data.[ICQ GET] ",__FILE__,__LINE__);
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ nlc->usingHttpGateway=1;
+ return 0;
+ }
+ nlc->dwLastGetSentTime=GetTickCount();
+ return 1;
+ }
+
+ /*
+ * Gena01 - small addition here, if we doing a POST then insert our packet here
+ */
+ if (nlc->pHttpProxyPacketQueue != NULL) {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+
+ nlc->pHttpProxyPacketQueue = nlc->pHttpProxyPacketQueue->next;
+
+ nlhrSend.dataLength=p->dataBufferLen;
+ nlhrSend.pData=(char*)p->dataBuffer;
+
+ mir_free(p);
+ }
+
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ struct NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ + mir_free(nlhrSend.pData); +
+ nlc->usingHttpGateway=1;
+
+ /*
+ * Gena01 - we need to drop ALL pending packets. Connection died!
+ */
+ while (p != NULL) {
+ struct NetlibHTTPProxyPacketQueue *t = p;
+
+ p = p->next;
+
+ mir_free(t->dataBuffer);
+ mir_free(t);
+ }
+
+ nlc->pHttpProxyPacketQueue = NULL; /* empty Queue */
+
+ return 0;
+ }
+ mir_free(nlhrSend.pData); + nlc->dwLastGetSentTime=GetTickCount();
+ return 1;
+}
+
+/*
+ * Gena01 - this is the old POST method, I renamed it and left it intact for ICQ support. it's called
+ * when we have both GET and POST URLs specified.
+ */
+int NetlibHttpGatewayOLDPost(struct NetlibConnection *nlc,const char *buf,int len,int flags)
+{
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply;
+ NETLIBHTTPHEADER httpHeaders[4];
+ char szUrl[512];
+ struct NetlibConnection nlcSend={0};
+
+ nlcSend.handleType=NLH_CONNECTION;
+ nlcSend.nlu=nlc->nlu;
+ nlcSend.hInstSecurityDll=nlc->hInstSecurityDll;
+ nlcSend.s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlcSend.s==INVALID_SOCKET) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ return SOCKET_ERROR;
+ }
+ nlcSend.hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlcSend.dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlcSend.ncsRecv);
+ NetlibInitializeNestedCS(&nlcSend.ncsSend);
+
+ if(connect(nlcSend.s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy))==SOCKET_ERROR) {
+ Netlib_Logf(nlc->nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return SOCKET_ERROR;
+ }
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+ nlhrSend.requestType=REQUEST_POST;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER;
+ if(flags&MSG_NODUMP) nlhrSend.flags|=NLHRF_NODUMP;
+ if(nlc->nlhpi.flags&NLHPIF_USEPOSTSEQUENCE) {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s%u",nlc->nlhpi.szHttpPostUrl,nlc->nlhpi.firstPostSequence);
+ nlc->nlhpi.firstPostSequence++;
+ if(nlc->nlhpi.flags&NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstGetSequence++;
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl=szUrl;
+ }
+ else nlhrSend.szUrl=nlc->nlhpi.szHttpPostUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlc->nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Connection";
+ httpHeaders[2].szValue="close";
+ httpHeaders[3].szName="Pragma";
+ httpHeaders[3].szValue="no-cache";
+ nlhrSend.dataLength=len;
+ nlhrSend.pData=(char*)buf;
+ if(NetlibHttpSendRequest((WPARAM)&nlcSend,(LPARAM)&nlhrSend)==SOCKET_ERROR) {
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return SOCKET_ERROR;
+ }
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)&nlcSend,flags&MSG_NODUMP?MSG_NODUMP:MSG_DUMPPROXY);
+ if(nlhrReply==NULL
+ || nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ if(nlhrReply) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ }
+ return SOCKET_ERROR;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+ closesocket(nlcSend.s);
+ return len;
+}
+
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags)
+{
+ struct NetlibHTTPProxyPacketQueue *p;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL)
+ return NetlibHttpGatewayOLDPost(nlc, buf, len, flags);
+
+ /*
+ * Gena01 - many changes here, do compare against the other version.
+ *
+ * Change #1: simplify to use similar code to GET
+ * Change #2: we need to allow to parse POST reply if szHttpGetUrl is NULL
+ * Change #3: Keep connection open if we need to.
+ *
+ * Impact: NONE! Since currently miranda doesn't allow szHttpGetUrl to be NULL, it will not connect
+ * with the new plugins that use this code.
+ */
+
+ p = mir_alloc(sizeof(struct NetlibHTTPProxyPacketQueue));
+ p->dataBuffer = mir_alloc(len);
+ memcpy(p->dataBuffer, buf, len);
+ p->dataBufferLen = len;
+ p->next = NULL;
+
+ /*
+ * Now check to see where to insert this in our queue
+ */
+ if (nlc->pHttpProxyPacketQueue == NULL) {
+ nlc->pHttpProxyPacketQueue = p;
+ } else {
+ struct NetlibHTTPProxyPacketQueue *t = nlc->pHttpProxyPacketQueue;
+
+ while (t->next != NULL)
+ t = t->next;
+
+ t->next = p;
+ }
+
+
+ /*
+ * Gena01 - fake a Send!! tell 'em all is ok. We catch errors in Recv.
+ */
+ return len;
+}
+
+#define NETLIBHTTP_RETRYCOUNT 3
+#define NETLIBHTTP_RETRYTIMEOUT 5000
+
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags)
+{
+ DWORD dwTimeNow;
+ int timedout;
+ NETLIBHTTPREQUEST *nlhrReply;
+ PBYTE dataBuffer;
+ int contentLength,i,bytesRecved;
+ int recvResult;
+ int retryCount;
+
+ /*
+ * Gena01 - we need to send packet here, since we didn't do it before.
+ */
+ if ((nlc->nlhpi.szHttpGetUrl == NULL) && (nlc->s == INVALID_SOCKET) && nlc->dataBuffer == NULL ) {
+
+ if ( nlc->pollingTimeout == 0 )
+ nlc->pollingTimeout = 30;
+
+ /* We Need to sleep/wait for the data to send before we do receive */
+ for ( retryCount = 0; retryCount < nlc->pollingTimeout; retryCount++ )
+ {
+ if ( nlc->pHttpProxyPacketQueue != NULL )
+ break;
+
+ if ( SleepEx( 1000, TRUE ))
+ return SOCKET_ERROR;
+ }
+
+/* if ( retryCount == nlc->pollingTimeout )
+ { SetLastError( ERROR_TIMEOUT );
+ return SOCKET_ERROR;
+ }
+*/
+ if ( nlc->pHttpProxyPacketQueue == 0 && nlc->nlu->user.pfnHttpGatewayWrapSend != NULL )
+ nlc->nlu->user.pfnHttpGatewayWrapSend((HANDLE)nlc,"",0,MSG_NOHTTPGATEWAYWRAP,NetlibSend); +
+ if(!HttpGatewaySendGet(nlc)) {
+ return SOCKET_ERROR;
+ }
+ }
+ /********************/
+ if(nlc->dataBuffer) {
+ if(nlc->dataBufferLen<=len) {
+ contentLength=nlc->dataBufferLen;
+ CopyMemory(buf,nlc->dataBuffer,nlc->dataBufferLen);
+ if(!(flags&MSG_PEEK)) {
+ mir_free(nlc->dataBuffer);
+ nlc->dataBuffer=NULL;
+ nlc->dataBufferLen=0;
+ }
+ return contentLength;
+ }
+ CopyMemory(buf,nlc->dataBuffer,len);
+ if(!(flags&MSG_PEEK)) {
+ nlc->dataBufferLen-=len;
+ MoveMemory(nlc->dataBuffer,nlc->dataBuffer+len,nlc->dataBufferLen);
+ nlc->dataBuffer=(PBYTE)mir_realloc(nlc->dataBuffer,nlc->dataBufferLen);
+ }
+ return len;
+ }
+ for( retryCount = 0;;) {
+ timedout=0;
+ dwTimeNow=GetTickCount();
+ if(dwTimeNow>=nlc->dwLastGetSentTime+HTTPGETTIMEOUT) timedout=1;
+ else if(!WaitUntilReadable(nlc->s,nlc->dwLastGetSentTime+HTTPGETTIMEOUT-dwTimeNow)) {
+ if(GetLastError()==ERROR_TIMEOUT) timedout=1;
+ else return SOCKET_ERROR;
+ }
+ if(timedout) {
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+ if(!HttpGatewaySendGet(nlc)) return SOCKET_ERROR;
+ retryCount = 0;
+ continue;
+ }
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,flags|MSG_RAW|MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return SOCKET_ERROR;
+ // ignore 1xx result codes
+ if (nlhrReply->resultCode < 200)
+ { + NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply); + continue;
+ } + // 0.3.1+
+ // Attempt to retry NETLIBHTTP_RETRYCOUNT times if the result code is >300
+ if (nlhrReply->resultCode >= 300)
+ {
+ if (retryCount < NETLIBHTTP_RETRYCOUNT) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ Netlib_Logf(nlc->nlu, "Error received from proxy, retrying");
+ retryCount++;
+ closesocket(nlc->s);
+ nlc->s = INVALID_SOCKET;
+ Sleep(NETLIBHTTP_RETRYTIMEOUT); // wait 5 seconds
+ // retry the connection
+ Netlib_Logf(nlc->nlu,"%s %d: ResultCode?? Doing GET.",__FILE__,__LINE__);
+ if(HttpGatewaySendGet(nlc))
+ continue;
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+ }
+ }
+ retryCount = 0;
+ contentLength=-1;
+ for(i=0;i<nlhrReply->headersCount;i++)
+ { + if(!lstrcmpiA(nlhrReply->headers[i].szName,"Content-Length")) {
+ contentLength=atoi(nlhrReply->headers[i].szValue);
+ break;
+ }
+ } +
+ /*
+ if(contentLength<0) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_INVALID_DATA);
+ return SOCKET_ERROR;
+ }*/
+ if(contentLength==0 && nlc->nlu->user.szHttpGatewayHello != NULL)
+ { + NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply); + continue;
+ } +
+
+ if (contentLength < 0) {
+ /* create initial buffer */
+ contentLength = 2048;
+
+ dataBuffer=(PBYTE)mir_alloc(contentLength);
+
+ /* error and exit */
+ if(dataBuffer==NULL) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+
+ /* now we need to get the bytes and add them to our buffer */
+ bytesRecved = 0;
+
+ do {
+ recvResult=NLRecv(nlc,dataBuffer+bytesRecved,contentLength-bytesRecved,MSG_RAW|MSG_DUMPPROXY);
+ if(recvResult==SOCKET_ERROR) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ return SOCKET_ERROR;
+ }
+ bytesRecved+=recvResult;
+ } while (recvResult > 0);
+ contentLength = bytesRecved;
+ } else {
+ if(contentLength > 0) {
+ dataBuffer=(PBYTE)mir_alloc(contentLength);
+ if(dataBuffer==NULL) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+ for(bytesRecved=0;bytesRecved<contentLength;) {
+ recvResult=NLRecv(nlc,dataBuffer+bytesRecved,contentLength-bytesRecved,MSG_RAW|MSG_DUMPPROXY);
+ if(recvResult==0 || recvResult==SOCKET_ERROR) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(recvResult==0) SetLastError(ERROR_HANDLE_EOF);
+ return SOCKET_ERROR;
+ }
+ bytesRecved+=recvResult;
+ } }
+ else dataBuffer = NULL;
+ }
+
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+
+ /*
+ * Gena01 - ok, ICQ does it here so that when we enter this function again we have reply
+ * pending. This is quite clever, since GET always gets replies from ICQ server
+ *
+ */
+ if (nlc->nlhpi.szHttpGetUrl != NULL) {
+ Netlib_Logf(nlc->nlu,"%s %d: Doing GET, Again????",__FILE__,__LINE__);
+
+ if(!HttpGatewaySendGet(nlc)) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ }
+
+ if(nlc->nlu->user.pfnHttpGatewayUnwrapRecv && !(flags&MSG_NOHTTPGATEWAYWRAP)) {
+ PBYTE newBuffer;
+ newBuffer=nlc->nlu->user.pfnHttpGatewayUnwrapRecv(nlhrReply,dataBuffer,contentLength,&contentLength,mir_realloc);
+ if(newBuffer==NULL) {
+ mir_free(dataBuffer);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ dataBuffer=newBuffer;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ if(contentLength>0) break;
+ if((contentLength==0)&&(nlc->nlhpi.szHttpGetUrl==NULL))
+ break;
+ mir_free(dataBuffer);
+ }
+ if(contentLength<=len) {
+ if(flags&MSG_PEEK) {
+ nlc->dataBuffer=dataBuffer;
+ nlc->dataBufferLen=contentLength;
+ }
+ CopyMemory(buf,dataBuffer,contentLength);
+ if(!(flags&MSG_PEEK)) mir_free(dataBuffer);
+ return contentLength;
+ }
+ CopyMemory(buf,dataBuffer,len);
+ if(!(flags&MSG_PEEK)) {
+ MoveMemory(dataBuffer,dataBuffer+len,contentLength-len);
+ dataBuffer=(PBYTE)mir_realloc(dataBuffer,contentLength-len);
+ nlc->dataBufferLen=contentLength-len;
+ }
+ else nlc->dataBufferLen=contentLength;
+ nlc->dataBuffer=dataBuffer;
+
+ Netlib_Logf(nlc->nlu,"%s %d: NetlibHTTPGatewayRecv EXIT!",__FILE__,__LINE__);
+ return len;
+}
+
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply=NULL;
+ NETLIBHTTPHEADER httpHeaders[3];
+
+ nlc->nlhpi.firstGetSequence=nlc->nlhpi.firstPostSequence=1;
+
+ /*
+ * Gena01 - ok we set nlhrReply to be null, also if the szHttpGatewayHello is NULL, then
+ * we don't send any requests/replies. We do have a socket open though. Could we
+ * re-use it maybe?
+ */
+ if (nlu->user.szHttpGatewayHello != NULL) {
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.nlc=nlc;
+ nlhrSend.requestType=REQUEST_GET;
+ nlhrSend.flags=NLHRF_GENERATEHOST|NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER; + if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11; + + nlhrSend.szUrl=nlu->user.szHttpGatewayHello;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=3;
+ httpHeaders[0].szName="User-Agent";
+ httpHeaders[0].szValue=nlu->user.szHttpGatewayUserAgent;
+ httpHeaders[1].szName="Cache-Control";
+ httpHeaders[1].szValue="no-store, no-cache";
+ httpHeaders[2].szName="Pragma";
+ httpHeaders[2].szValue="no-cache";
+ if(NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend)==SOCKET_ERROR)
+ return 0;
+
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return 0;
+
+ if(nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ return 0;
+ }
+ }
+ if(!nlu->user.pfnHttpGatewayInit(nlc,nloc,nlhrReply)) {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+
+ /*
+ * Gena01 - Ok, we should be able to use just POST. Needed for Yahoo, NO GET requests
+ */
+ if(nlc->nlhpi.szHttpPostUrl==NULL) {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ closesocket(nlc->s);
+ nlc->s=INVALID_SOCKET;
+
+ nlc->usingHttpGateway=1;
+
+ /* don't send anything if only using POST? */
+ if(nlc->nlhpi.szHttpGetUrl!= NULL)
+ if(!HttpGatewaySendGet(nlc))
+ return 0;
+
+ //now properly connected
+ if(nlu->user.pfnHttpGatewayBegin)
+ if(!nlu->user.pfnHttpGatewayBegin(nlc,nloc))
+ return 0;
+ return 1;
+}
+
+int NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPPROXYINFO *nlhpi=(NETLIBHTTPPROXYINFO*)lParam;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || nlhpi==NULL || nlhpi->cbSize!=sizeof(NETLIBHTTPPROXYINFO) || nlhpi->szHttpPostUrl==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ nlc->nlhpi=*nlhpi;
+
+ if (nlc->nlhpi.szHttpGetUrl)
+ nlc->nlhpi.szHttpGetUrl=mir_strdup(nlc->nlhpi.szHttpGetUrl);
+
+ nlc->nlhpi.szHttpPostUrl=mir_strdup(nlc->nlhpi.szHttpPostUrl);
+ return 1;
+}
+
+int NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibUser * nu = (struct NetlibUser*)wParam;
+ if (GetNetlibHandleType(nu)!=NLH_USER) return ERROR_INVALID_PARAMETER;
+ if (nu->szStickyHeaders) { mir_free(nu->szStickyHeaders); nu->szStickyHeaders=NULL; }
+ if (lParam) {
+ nu->szStickyHeaders=mir_strdup((char*)lParam); // pointer is ours
+ }
+ return 0;
+}
+
+int NetlibHttpSetPollingTimeout(WPARAM wParam, LPARAM lParam)
+{
+ int oldTimeout;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ if (GetNetlibHandleType(nlc)!=NLH_CONNECTION) return -1;
+ oldTimeout = nlc->pollingTimeout;
+ nlc->pollingTimeout = lParam;
+ return oldTimeout;
+}
diff --git a/miranda-wine/src/modules/netlib/netliblog.c b/miranda-wine/src/modules/netlib/netliblog.c new file mode 100644 index 0000000..9d07f29 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netliblog.c @@ -0,0 +1,440 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+#define MS_NETLIB_LOGWIN "Netlib/Log/Win"
+
+extern HANDLE hConnectionHeaderMutex;
+
+#define TIMEFORMAT_NONE 0
+#define TIMEFORMAT_HHMMSS 1
+#define TIMEFORMAT_MILLISECONDS 2
+#define TIMEFORMAT_MICROSECONDS 3
+struct {
+ HWND hwndOpts;
+ int toOutputDebugString;
+ int toFile;
+ TCHAR* szFile;
+ int timeFormat;
+ int showUser;
+ int dumpSent,dumpRecv,dumpProxy;
+ int textDumps,autoDetectText;
+ CRITICAL_SECTION cs;
+} logOptions;
+static __int64 mirandaStartTime,perfCounterFreq;
+
+static const TCHAR* szTimeFormats[] =
+{
+ _T( "No times" ),
+ _T( "Standard hh:mm:ss times" ),
+ _T( "Times in milliseconds" ),
+ _T( "Times in microseconds" )
+};
+
+static BOOL CALLBACK LogOptionsDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ logOptions.hwndOpts=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg,IDC_DUMPRECV,logOptions.dumpRecv?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPSENT,logOptions.dumpSent?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPPROXY,logOptions.dumpProxy?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TEXTDUMPS,logOptions.textDumps?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_AUTODETECTTEXT,logOptions.autoDetectText?BST_CHECKED:BST_UNCHECKED);
+ { int i;
+ for( i=0; i < SIZEOF(szTimeFormats); i++ )
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_ADDSTRING,0,(LPARAM)TranslateTS( szTimeFormats[i] ));
+ }
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_SETCURSEL,logOptions.timeFormat,0);
+ CheckDlgButton(hwndDlg,IDC_SHOWNAMES,logOptions.showUser?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOOUTPUTDEBUGSTRING,logOptions.toOutputDebugString?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOFILE,logOptions.toFile?BST_CHECKED:BST_UNCHECKED);
+ SetDlgItemText(hwndDlg,IDC_FILENAME,logOptions.szFile);
+ CheckDlgButton(hwndDlg,IDC_SHOWTHISDLGATSTART,DBGetContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",0)?BST_CHECKED:BST_UNCHECKED);
+ { DBVARIANT dbv;
+ if(!DBGetContactSetting(NULL,"Netlib","RunAtStart",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_RUNATSTART,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_DUMPRECV:
+ logOptions.dumpRecv=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_DUMPSENT:
+ logOptions.dumpSent=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_DUMPPROXY:
+ logOptions.dumpProxy=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TEXTDUMPS:
+ logOptions.textDumps=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_AUTODETECTTEXT:
+ logOptions.autoDetectText=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TIMEFORMAT:
+ logOptions.timeFormat=SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_GETCURSEL,0,0);
+ break;
+ case IDC_SHOWNAMES:
+ logOptions.showUser=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TOOUTPUTDEBUGSTRING:
+ logOptions.toOutputDebugString=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_TOFILE:
+ logOptions.toFile=IsDlgButtonChecked(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_FILENAME:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ if((HWND)lParam==GetFocus()) {
+ CheckDlgButton(hwndDlg,IDC_TOFILE,BST_CHECKED);
+ logOptions.toFile=0;
+ }
+ EnterCriticalSection(&logOptions.cs);
+ if(logOptions.szFile) mir_free(logOptions.szFile);
+ { int len;
+ len=GetWindowTextLength((HWND)lParam);
+ logOptions.szFile = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 ));
+ GetWindowText((HWND)lParam, logOptions.szFile, len+1 );
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ break;
+ case IDC_FILENAMEBROWSE:
+ case IDC_RUNATSTARTBROWSE:
+ { TCHAR str[MAX_PATH+2];
+ OPENFILENAME ofn={0};
+ TCHAR filter[512],*pfilter;
+
+ GetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_HIDEREADONLY;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ ofn.lpstrTitle=TranslateT("Select where log file will be created");
+ } else {
+ ofn.Flags|=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;
+ ofn.lpstrTitle=TranslateT("Select program to be run");
+ }
+ _tcscpy(filter,TranslateT("All Files"));
+ _tcscat(filter,_T(" (*)"));
+ pfilter=filter+lstrlen(filter)+1;
+ _tcscpy(pfilter,_T("*"));
+ pfilter=pfilter+lstrlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str)-2;
+ ofn.nMaxFileTitle=MAX_PATH;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ if(!GetSaveFileName(&ofn)) return 1;
+ } else {
+ if(!GetOpenFileName(&ofn)) return 1;
+ }
+ if(LOWORD(wParam)==IDC_RUNATSTARTBROWSE && _tcschr(str,' ')!=NULL) {
+ MoveMemory(str+1,str,SIZEOF(str)-2);
+ str[0]='"';
+ lstrcat(str,_T("\""));
+ }
+ SetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str);
+ break;
+ }
+ case IDC_SHOWTHISDLGATSTART:
+ DBWriteContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",(BYTE)IsDlgButtonChecked(hwndDlg,LOWORD(wParam)));
+ break;
+ case IDC_RUNATSTART:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ { int len;
+ char *str;
+ len=GetWindowTextLength((HWND)lParam);
+ str=(char*)mir_alloc(len+1);
+ GetWindowTextA((HWND)lParam,str,len+1);
+ DBWriteContactSettingString(NULL,"Netlib","RunAtStart",str);
+ mir_free(str);
+ }
+ break;
+ case IDC_RUNNOW:
+ { int len;
+ char *str;
+ STARTUPINFOA si={0};
+ PROCESS_INFORMATION pi;
+ len=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_RUNATSTART));
+ str=(char*)mir_alloc(len+1);
+ GetDlgItemTextA(hwndDlg,IDC_RUNATSTART,str,len+1);
+ si.cb=sizeof(si);
+ if(str[0]) CreateProcessA(NULL,str,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ }
+ break;
+ case IDC_SAVE:
+ DBWriteContactSettingByte(NULL,"Netlib","DumpRecv",(BYTE)logOptions.dumpRecv);
+ DBWriteContactSettingByte(NULL,"Netlib","DumpSent",(BYTE)logOptions.dumpSent);
+ DBWriteContactSettingByte(NULL,"Netlib","DumpProxy",(BYTE)logOptions.dumpProxy);
+ DBWriteContactSettingByte(NULL,"Netlib","TextDumps",(BYTE)logOptions.textDumps);
+ DBWriteContactSettingByte(NULL,"Netlib","AutoDetectText",(BYTE)logOptions.autoDetectText);
+ DBWriteContactSettingByte(NULL,"Netlib","TimeFormat",(BYTE)logOptions.timeFormat);
+ DBWriteContactSettingByte(NULL,"Netlib","ShowUser",(BYTE)logOptions.showUser);
+ DBWriteContactSettingByte(NULL,"Netlib","ToOutputDebugString",(BYTE)logOptions.toOutputDebugString);
+ DBWriteContactSettingByte(NULL,"Netlib","ToFile",(BYTE)logOptions.toFile);
+ DBWriteContactSettingTString(NULL,"Netlib","File", logOptions.szFile ? logOptions.szFile: _T(""));
+ break;
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ logOptions.hwndOpts=NULL;
+ break;
+ }
+ return FALSE;
+}
+
+void NetlibLogShowOptions(void)
+{
+ if(logOptions.hwndOpts==NULL)
+ logOptions.hwndOpts=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_NETLIBLOGOPTS),NULL,LogOptionsDlgProc);
+ SetForegroundWindow(logOptions.hwndOpts);
+}
+
+static void CreateDirectoryTree( TCHAR* szDir)
+{
+ DWORD dwAttributes;
+ TCHAR* pszLastBackslash,szTestDir[MAX_PATH];
+
+ lstrcpyn(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributes(szTestDir))!=0xffffffff && dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ pszLastBackslash = _tcsrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL ) return;
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szTestDir );
+ CreateDirectory( szTestDir, NULL );
+}
+
+static int NetlibLog(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibUser nludummy;
+ const char *pszMsg=(const char*)lParam;
+ char *szLine;
+ char szTime[32];
+ LARGE_INTEGER liTimeNow;
+ DWORD dwOriginalLastError;
+
+ if( (nlu != NULL && GetNetlibHandleType(nlu)!=NLH_USER) || pszMsg==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if (nlu==NULL) { /* if the Netlib user handle is NULL, just pretend its not */
+ nlu=&nludummy;
+ nlu->user.szSettingsModule="(NULL)";
+ }
+ dwOriginalLastError=GetLastError();
+ QueryPerformanceCounter(&liTimeNow);
+ liTimeNow.QuadPart-=mirandaStartTime;
+ switch(logOptions.timeFormat) {
+ case TIMEFORMAT_HHMMSS:
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,NULL,NULL,szTime,SIZEOF(szTime)-1);
+ break;
+ case TIMEFORMAT_MILLISECONDS:
+ mir_snprintf(szTime,SIZEOF(szTime)-1,"%I64u.%03I64u",liTimeNow.QuadPart/perfCounterFreq,1000*(liTimeNow.QuadPart%perfCounterFreq)/perfCounterFreq);
+ break;
+ case TIMEFORMAT_MICROSECONDS:
+ mir_snprintf(szTime,SIZEOF(szTime)-1,"%I64u.%06I64u",liTimeNow.QuadPart/perfCounterFreq,1000000*(liTimeNow.QuadPart%perfCounterFreq)/perfCounterFreq);
+ break;
+ default:
+ szTime[0]='\0';
+ break;
+ }
+ EnterCriticalSection(&logOptions.cs);
+ if(logOptions.showUser) lstrcatA(szTime," ");
+ szLine=(char*)alloca(lstrlenA(pszMsg)+lstrlenA(nlu->user.szSettingsModule)+5+lstrlenA(szTime));
+ if(logOptions.timeFormat || logOptions.showUser)
+ sprintf(szLine,"[%s%s] %s\n",szTime,logOptions.showUser?nlu->user.szSettingsModule:"",pszMsg);
+ else
+ sprintf(szLine,"%s\n",pszMsg);
+ if(logOptions.toOutputDebugString) OutputDebugStringA(szLine);
+ if(logOptions.toFile && logOptions.szFile[0]) {
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ if(!fp) {
+ CreateDirectoryTree(logOptions.szFile);
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ }
+ if(fp) {
+ fputs(szLine,fp);
+ fclose(fp);
+ }
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ SetLastError(dwOriginalLastError);
+ return 1;
+}
+
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags)
+{
+ int isText=1;
+ char szTitleLine[128];
+ char *szBuf;
+ int titleLineLen;
+ struct NetlibUser *nlu;
+
+ // This section checks a number of conditions and aborts
+ // the dump if the data should not be written to the log
+
+ // Check packet flags
+ if ((flags&MSG_PEEK) || (flags&MSG_NODUMP))
+ return;
+
+ // Check user's log settings
+ if (!(logOptions.toOutputDebugString ||
+ (logOptions.toFile && logOptions.szFile[0])))
+ return;
+ if ((sent && !logOptions.dumpSent) ||
+ (!sent && !logOptions.dumpRecv))
+ return;
+ if ((flags&MSG_DUMPPROXY) && !logOptions.dumpProxy)
+ return;
+
+
+ if (!logOptions.textDumps)
+ isText = 0;
+ else if (!(flags&MSG_DUMPASTEXT)) {
+ if (logOptions.autoDetectText) {
+ int i;
+ for(i = 0; i<len; i++)
+ if ((buf[i]<' ' && buf[i]!='\t' && buf[i]!='\r' && buf[i]!='\n') || buf[i]>=0x80)
+ {
+ isText = 0;
+ break;
+ }
+ }
+ else
+ isText = 0;
+ }
+
+ WaitForSingleObject(hConnectionHeaderMutex, INFINITE);
+ nlu = nlc ? nlc->nlu : NULL;
+ titleLineLen = mir_snprintf(szTitleLine,SIZEOF(szTitleLine), "(%p:%u) Data %s%s\n", nlc, nlc?nlc->s:0, sent?"sent":"received", flags & MSG_DUMPPROXY?" (proxy)":"");
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ // Text data
+ if (isText)
+ {
+ szBuf = (char*)alloca(titleLineLen + len + 1);
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ CopyMemory(szBuf + titleLineLen, (const char*)buf, len);
+ szBuf[titleLineLen + len] = '\0';
+ }
+ // Binary data
+ else
+ {
+ int line, col, colsInLine;
+ char *pszBuf;
+
+ szBuf = (char*)alloca(titleLineLen + ((len+16)>>4) * 76 + 1);
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ pszBuf = szBuf + titleLineLen;
+ for (line = 0; ; line += 16)
+ {
+ colsInLine = min(16, len - line);
+ pszBuf += wsprintfA(pszBuf, "%08X: ", line);
+ // Dump data as hex
+ for (col = 0; col < colsInLine; col++)
+ pszBuf += wsprintfA(pszBuf, "%02X%c", buf[line + col], ((col&3)==3 && col != 15)?'-':' ');
+ // Fill out last line with blanks
+ for ( ; col<16; col++)
+ {
+ lstrcpyA(pszBuf, " ");
+ pszBuf += 3;
+ }
+ *pszBuf++ = ' ';
+ for (col = 0; col < colsInLine; col++)
+ *pszBuf++ = buf[line+col]<' '?'.':(char)buf[line+col];
+ if (len-line<=16)
+ break;
+ *pszBuf++ = '\n'; // End each line with a break
+ }
+ *pszBuf = '\0';
+ }
+
+ NetlibLog((WPARAM)nlu,(LPARAM)szBuf);
+
+}
+
+void NetlibLogInit(void)
+{
+ DBVARIANT dbv;
+ LARGE_INTEGER li;
+
+ CreateServiceFunction(MS_NETLIB_LOG,NetlibLog);
+ QueryPerformanceFrequency(&li);
+ perfCounterFreq=li.QuadPart;
+ QueryPerformanceCounter(&li);
+ mirandaStartTime=li.QuadPart;
+ InitializeCriticalSection(&logOptions.cs);
+ logOptions.dumpRecv=DBGetContactSettingByte(NULL,"Netlib","DumpRecv",1);
+ logOptions.dumpSent=DBGetContactSettingByte(NULL,"Netlib","DumpSent",1);
+ logOptions.dumpProxy=DBGetContactSettingByte(NULL,"Netlib","DumpProxy",0);
+ logOptions.textDumps=DBGetContactSettingByte(NULL,"Netlib","TextDumps",1);
+ logOptions.autoDetectText=DBGetContactSettingByte(NULL,"Netlib","AutoDetectText",1);
+ logOptions.timeFormat=DBGetContactSettingByte(NULL,"Netlib","TimeFormat",TIMEFORMAT_HHMMSS);
+ logOptions.showUser=DBGetContactSettingByte(NULL,"Netlib","ShowUser",1);
+ logOptions.toOutputDebugString=DBGetContactSettingByte(NULL,"Netlib","ToOutputDebugString",0);
+ logOptions.toFile=DBGetContactSettingByte(NULL,"Netlib","ToFile",0);
+
+ if(!DBGetContactSettingTString(NULL, "Netlib", "File", &dbv)) {
+ logOptions.szFile = mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ if(logOptions.toFile && logOptions.szFile[0]) {
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("wt"));
+ if(fp) fclose(fp);
+ }
+ if(DBGetContactSettingByte(NULL,"Netlib","ShowLogOptsAtStart",0))
+ NetlibLogShowOptions();
+ if(!DBGetContactSetting(NULL,"Netlib","RunAtStart",&dbv)) {
+ STARTUPINFOA si={0};
+ PROCESS_INFORMATION pi;
+ si.cb=sizeof(si);
+ if(dbv.pszVal[0]) CreateProcessA(NULL,dbv.pszVal,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ DBFreeVariant(&dbv);
+ }
+}
+
+void NetlibLogShutdown(void)
+{
+ if(IsWindow(logOptions.hwndOpts)) DestroyWindow(logOptions.hwndOpts);
+ DeleteCriticalSection(&logOptions.cs);
+ if(logOptions.szFile) mir_free(logOptions.szFile);
+}
+
diff --git a/miranda-wine/src/modules/netlib/netlibopenconn.c b/miranda-wine/src/modules/netlib/netlibopenconn.c new file mode 100644 index 0000000..6d19e1c --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibopenconn.c @@ -0,0 +1,569 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+extern CRITICAL_SECTION csNetlibUser;
+extern DWORD g_LastConnectionTick; // protected by csNetlibUser
+
+//returns in network byte order
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost)
+{
+ DWORD ip;
+ HOSTENT *host;
+
+ ip=inet_addr(szHost);
+ if(ip!=INADDR_NONE) return ip;
+ host=gethostbyname(szHost);
+ if(host) return *(u_long *)host->h_addr_list[0];
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"gethostbyname",WSAGetLastError());
+ return 0;
+}
+
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set readfd;
+ TIMEVAL tv;
+
+ tv.tv_sec=dwTimeout/1000;
+ tv.tv_usec=(dwTimeout%1000)*1000;
+ FD_ZERO(&readfd);
+ FD_SET(s,&readfd);
+ switch(select(0,&readfd,0,0,&tv)) {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+static int WaitUntilWritable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set writefd;
+ TIMEVAL tv;
+
+ tv.tv_sec=dwTimeout/1000;
+ tv.tv_usec=(dwTimeout%1000)*1000;
+ FD_ZERO(&writefd);
+ FD_SET(s,&writefd);
+ switch(select(0,0,&writefd,0,&tv)) {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+static int NetlibInitSocks4Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //http://www.socks.nec.com/protocol/socks4.protocol and http://www.socks.nec.com/protocol/socks4a.protocol
+ PBYTE pInit;
+ int nUserLen,nHostLen,len;
+ BYTE reply[8];
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nHostLen=lstrlenA(nloc->szHost);
+ pInit=(PBYTE)mir_alloc(10+nUserLen+nHostLen);
+ pInit[0]=4; //SOCKS4
+ pInit[1]=1; //connect
+ *(PWORD)(pInit+2)=htons(nloc->wPort);
+ if(nlu->settings.szProxyAuthUser==NULL) pInit[8]=0;
+ else lstrcpyA(pInit+8,nlu->settings.szProxyAuthUser);
+ if(nlu->settings.dnsThroughProxy) {
+ if((*(PDWORD)(pInit+4)=inet_addr(nloc->szHost))==INADDR_NONE) {
+ *(PDWORD)(pInit+4)=0x01000000;
+ lstrcpyA(pInit+9+nUserLen,nloc->szHost);
+ len=10+nUserLen+nHostLen;
+ }
+ else len=9+nUserLen;
+ }
+ else {
+ *(PDWORD)(pInit+4)=DnsLookup(nlu,nloc->szHost);
+ if(*(PDWORD)(pInit+4)==0) {
+ mir_free(pInit);
+ return 0;
+ }
+ len=9+nUserLen;
+ }
+ if(NLSend(nlc,pInit,len,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+
+ if(!WaitUntilReadable(nlc->s,30000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,reply,SIZEOF(reply),MSG_DUMPPROXY);
+ if(len < sizeof(reply) || reply[1]!=90) {
+ if(len != SOCKET_ERROR) {
+ if (len < SIZEOF(reply)) SetLastError(ERROR_BAD_FORMAT);
+ else switch(reply[1]) {
+ case 91: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 92: SetLastError(ERROR_CONNECTION_UNAVAIL); break;
+ case 93: SetLastError(ERROR_INVALID_ACCESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ //connected
+ return 1;
+}
+
+static int NetlibInitSocks5Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc1928
+ int len;
+ BYTE buf[256];
+
+ buf[0]=5; //yep, socks5
+ buf[1]=1; //one auth method
+ buf[2]=nlu->settings.useProxyAuth?2:0;
+ if(NLSend(nlc,buf,3,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ return 0;
+ }
+
+ if(!WaitUntilReadable(nlc->s,10000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,2,MSG_DUMPPROXY); //confirmation of auth method
+ if(len<2 || (buf[1]!=0 && buf[1]!=2)) {
+ if(len!=SOCKET_ERROR) {
+ if(len<2) SetLastError(ERROR_BAD_FORMAT);
+ else SetLastError(ERROR_INVALID_ID_AUTHORITY);
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+
+ if(buf[1]==2) { //rfc1929
+ int nUserLen,nPassLen;
+ PBYTE pAuthBuf;
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nPassLen=lstrlenA(nlu->settings.szProxyAuthPassword);
+ pAuthBuf=(PBYTE)mir_alloc(3+nUserLen+nPassLen);
+ pAuthBuf[0]=1; //auth version
+ pAuthBuf[1]=nUserLen;
+ memcpy(pAuthBuf+2,nlu->settings.szProxyAuthUser,nUserLen);
+ pAuthBuf[2+nUserLen]=nPassLen;
+ memcpy(pAuthBuf+3+nUserLen,nlu->settings.szProxyAuthPassword,nPassLen);
+ if(NLSend(nlc,pAuthBuf,3+nUserLen+nPassLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pAuthBuf);
+ return 0;
+ }
+ mir_free(pAuthBuf);
+
+ if(!WaitUntilReadable(nlc->s,10000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,SIZEOF(buf),MSG_DUMPPROXY);
+ if(len<2 || buf[1]) {
+ if(len!=SOCKET_ERROR) {
+ if(len<2) SetLastError(ERROR_BAD_FORMAT);
+ else SetLastError(ERROR_ACCESS_DENIED);
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ }
+
+ { PBYTE pInit;
+ int nHostLen;
+ DWORD hostIP;
+
+ if(nlu->settings.dnsThroughProxy) {
+ if((hostIP=inet_addr(nloc->szHost))==INADDR_NONE)
+ nHostLen=lstrlenA(nloc->szHost)+1;
+ else nHostLen=4;
+ }
+ else {
+ if((hostIP=DnsLookup(nlu,nloc->szHost))==0)
+ return 0;
+ nHostLen=4;
+ }
+ pInit=(PBYTE)mir_alloc(6+nHostLen);
+ pInit[0]=5; //SOCKS5
+ pInit[1]=1; //connect
+ pInit[2]=0; //reserved
+ if(hostIP==INADDR_NONE) { //DNS lookup through proxy
+ pInit[3]=3;
+ pInit[4]=nHostLen-1;
+ memcpy(pInit+5,nloc->szHost,nHostLen-1);
+ }
+ else {
+ pInit[3]=1;
+ *(PDWORD)(pInit+4)=hostIP;
+ }
+ *(PWORD)(pInit+4+nHostLen)=htons(nloc->wPort);
+ if(NLSend(nlc,pInit,6+nHostLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+ }
+
+ if(!WaitUntilReadable(nlc->s,30000)) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"WaitUntilReadable",GetLastError());
+ return 0;
+ }
+
+ len=NLRecv(nlc,buf,SIZEOF(buf),MSG_DUMPPROXY);
+ if(len<7 || buf[0]!=5 || buf[1]) {
+ if(len!=SOCKET_ERROR) {
+ if(len<7 || buf[0]!=5) SetLastError(ERROR_BAD_FORMAT);
+ else switch(buf[1]) {
+ case 1: SetLastError(ERROR_GEN_FAILURE); break;
+ case 2: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 3: SetLastError(WSAENETUNREACH); break;
+ case 4: SetLastError(WSAEHOSTUNREACH); break;
+ case 5: SetLastError(WSAECONNREFUSED); break;
+ case 6: SetLastError(WSAETIMEDOUT); break;
+ case 7: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); break;
+ case 8: SetLastError(ERROR_INVALID_ADDRESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+ //connected
+ return 1;
+}
+
+static int NetlibInitHttpsConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc2817
+ NETLIBHTTPHEADER httpHeaders[3];
+ NETLIBHTTPREQUEST nlhrSend={0},*nlhrReply;
+ char szUrl[512];
+
+ memset(httpHeaders,0,sizeof(httpHeaders));
+
+ nlhrSend.cbSize=sizeof(nlhrSend);
+ nlhrSend.requestType=REQUEST_CONNECT;
+ nlhrSend.flags=NLHRF_DUMPPROXY|NLHRF_SMARTAUTHHEADER|NLHRF_HTTP11; + if(nlu->settings.dnsThroughProxy) {
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s:%u",nloc->szHost,nloc->wPort);
+ if(inet_addr(nloc->szHost)==INADDR_NONE) {
+ httpHeaders[0].szName="Host";
+ httpHeaders[0].szValue=szUrl;
+ nlhrSend.headersCount++;
+ }
+ }
+ else {
+ struct in_addr addr;
+ DWORD ip=DnsLookup(nlu,nloc->szHost);
+ if(ip==0) return 0;
+ addr.S_un.S_addr=ip;
+ mir_snprintf(szUrl,SIZEOF(szUrl),"%s:%u",inet_ntoa(addr),nloc->wPort);
+ }
+ nlhrSend.szUrl=szUrl;
+ nlhrSend.headers=httpHeaders;
+ nlhrSend.headersCount=0;
+ if(NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend)==SOCKET_ERROR)
+ return 0;
+ nlhrReply=(NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc,MSG_DUMPPROXY);
+ if(nlhrReply==NULL) return 0;
+ if(nlhrReply->resultCode<200 || nlhrReply->resultCode>=300) {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ Netlib_Logf(nlu,"%s %d: %s request failed (%u %s)",__FILE__,__LINE__,nlu->settings.proxyType==PROXYTYPE_HTTP?"HTTP":"HTTPS",nlhrReply->resultCode,nlhrReply->szResultDescr);
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ //connected
+ return 1;
+}
+
+static void FreePartiallyInitedConnection(struct NetlibConnection *nlc)
+{
+ DWORD dwOriginalLastError=GetLastError();
+
+ if(nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+ if(nlc->nlhpi.szHttpPostUrl) mir_free(nlc->nlhpi.szHttpPostUrl);
+ if(nlc->nlhpi.szHttpGetUrl) mir_free(nlc->nlhpi.szHttpGetUrl);
+ if(nlc->hInstSecurityDll) FreeLibrary(nlc->hInstSecurityDll);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ mir_free(nlc);
+ SetLastError(dwOriginalLastError);
+}
+
+#define PortInMask(mask,p) ((mask)[((p)&0xFFFF)>>3]&(1<<((p)&7)))
+
+static int my_connect(SOCKET s, const struct sockaddr * name, int namelen, NETLIBOPENCONNECTION * nloc)
+{
+ int rc=0;
+ unsigned int dwTimeout=( nloc->cbSize==sizeof(NETLIBOPENCONNECTION) && nloc->flags&NLOCF_V2 ) ? nloc->timeout : 0;
+ u_long notblocking=1;
+ TIMEVAL tv;
+ DWORD lasterr = 0;
+ int waitdiff;
+ // if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
+ if ( dwTimeout == 0 )
+ dwTimeout += 60;
+ // return the socket to non blocking
+ if ( ioctlsocket(s, FIONBIO, ¬blocking) != 0 ) {
+ return SOCKET_ERROR;
+ }
+ // this is for XP SP2 where there is a default connection attempt limit of 10/second
+ EnterCriticalSection(&csNetlibUser);
+ waitdiff=GetTickCount() - g_LastConnectionTick;
+ g_LastConnectionTick=GetTickCount();
+ LeaveCriticalSection(&csNetlibUser);
+ if ( waitdiff < 1000 ) {
+ // last connection was less than 1 second ago, wait 1.2 seconds
+ SleepEx(1200,TRUE);
+ }
+ // might of died in between the wait
+ if ( Miranda_Terminated() ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ // try a connect
+ if ( connect(s, name, namelen) == 0 ) {
+ goto unblock;
+ }
+ // didn't work, was it cos of nonblocking?
+ if ( WSAGetLastError() != WSAEWOULDBLOCK ) {
+ rc=SOCKET_ERROR;
+ lasterr=WSAGetLastError();
+ goto unblock;
+ }
+ // setup select()
+ tv.tv_sec=1;
+ tv.tv_usec=0;
+ for (;;) {
+ fd_set r, w, e;
+ FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
+ FD_SET(s, &r);
+ FD_SET(s, &w);
+ FD_SET(s, &e);
+ if ( (rc=select(0, &r, &w, &e, &tv)) == SOCKET_ERROR ) {
+ break;
+ }
+ if ( rc > 0 ) {
+ if ( FD_ISSET(s, &r) ) {
+ // connection was closed
+ rc=SOCKET_ERROR;
+ lasterr=WSAECONNRESET;
+ }
+ if ( FD_ISSET(s, &w) ) {
+ // connection was successful
+ rc=0;
+ }
+ if ( FD_ISSET(s, &e) ) {
+ // connection failed.
+ int len=sizeof(lasterr);
+ rc=SOCKET_ERROR;
+ getsockopt(s,SOL_SOCKET,SO_ERROR,(char*)&lasterr,&len);
+ }
+ goto unblock;
+ } else if ( Miranda_Terminated() ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ } else if ( nloc->cbSize==sizeof(NETLIBOPENCONNECTION) && nloc->flags&NLOCF_V2 && nloc->waitcallback != NULL
+ && nloc->waitcallback(&dwTimeout) == 0) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ if ( --dwTimeout == 0 ) {
+ rc=SOCKET_ERROR;
+ lasterr=ERROR_TIMEOUT;
+ goto unblock;
+ }
+ }
+unblock:
+ notblocking=0;
+ ioctlsocket(s, FIONBIO, ¬blocking);
+ SetLastError(lasterr);
+ return rc;
+}
+
+int NetlibOpenConnection(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBOPENCONNECTION *nloc=(NETLIBOPENCONNECTION*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ struct NetlibConnection *nlc;
+ SOCKADDR_IN sin;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || !(nlu->user.flags&NUF_OUTGOING) || nloc==NULL
+ || !(nloc->cbSize==NETLIBOPENCONNECTION_V1_SIZE||nloc->cbSize==sizeof(NETLIBOPENCONNECTION)) || nloc->szHost==NULL || nloc->wPort==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(HANDLE)NULL;
+ }
+ nlc=(struct NetlibConnection*)mir_calloc(sizeof(struct NetlibConnection));
+ nlc->handleType=NLH_CONNECTION;
+ nlc->nlu=nlu;
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ if (nlu->settings.specifyOutgoingPorts && nlu->settings.szOutgoingPorts)
+ {
+ BYTE portsMask[0x2000];
+ int startPort,portNum,i,j,portsCount;
+
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=htonl(INADDR_ANY);
+ sin.sin_port=0;
+
+ portsCount=StringToPortsMask(nlu->settings.szOutgoingPorts,portsMask);
+ if (portsCount) {
+ startPort=rand() % portsCount;
+ for (i=0;i<0x02000;i++) {
+ if(portsMask[i]==0) continue;
+ if(portsMask[i]==0xFF && startPort>=8) {startPort-=8; continue;}
+ for(j=0;j<8;j++)
+ if(portsMask[i]&(1<<j))
+ if(startPort--==0) {
+ portNum=(i<<3)+j;
+ break;
+ }
+ if(startPort==-1) break;
+ } //for
+ if (i!=0x2000) {
+ startPort=portNum;
+ do {
+ sin.sin_port=htons((WORD)portNum);
+ if(bind(nlc->s,(SOCKADDR*)&sin,sizeof(sin))==0) break;
+ for(portNum++;!PortInMask(portsMask,portNum);portNum++)
+ if(portNum==0xFFFF) portNum=0;
+ } while (portNum!=startPort);
+ } //if
+ } //if
+ }
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow=0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ if(nlu->settings.useProxy && (nlu->settings.proxyType==PROXYTYPE_HTTP || nlu->settings.proxyType==PROXYTYPE_HTTPS) && nlu->settings.useProxyAuth && nlu->settings.useProxyAuthNtlm)
+ nlc->hInstSecurityDll=LoadLibraryA("security.dll");
+
+ nlc->sinProxy.sin_family=AF_INET;
+ if(nlu->settings.useProxy) {
+ nlc->sinProxy.sin_port=htons((short)nlu->settings.wProxyPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nlu->settings.szProxyServer);
+ }
+ else {
+ nlc->sinProxy.sin_port=htons((short)nloc->wPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nloc->szHost);
+ }
+ if(nlc->sinProxy.sin_addr.S_un.S_addr==0
+ || my_connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy), nloc)==SOCKET_ERROR) {
+ if(nlc->sinProxy.sin_addr.S_un.S_addr)
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+
+ if(nlu->settings.useProxy
+ && !(nloc->flags&NLOCF_HTTP
+ && (nlu->settings.proxyType==PROXYTYPE_HTTP || nlu->settings.proxyType==PROXYTYPE_HTTPS)))
+ {
+ if(!WaitUntilWritable(nlc->s,30000)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+
+ switch(nlu->settings.proxyType) {
+ case PROXYTYPE_SOCKS4:
+ if(!NetlibInitSocks4Connection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_SOCKS5:
+ if(!NetlibInitSocks5Connection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_HTTPS:
+ if(!NetlibInitHttpsConnection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ case PROXYTYPE_HTTP:
+ if(!(nlu->user.flags&NUF_HTTPGATEWAY)) {
+ //NLOCF_HTTP not specified and no HTTP gateway available: try HTTPS
+ if(!NetlibInitHttpsConnection(nlc,nlu,nloc)) {
+ //can't do HTTPS: try direct
+ if(nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+
+ nlc->s=socket(AF_INET,SOCK_STREAM,0);
+ if(nlc->s==INVALID_SOCKET) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ nlc->sinProxy.sin_family=AF_INET;
+ nlc->sinProxy.sin_port=htons((short)nloc->wPort);
+ nlc->sinProxy.sin_addr.S_un.S_addr=DnsLookup(nlu,nloc->szHost);
+ if(nlc->sinProxy.sin_addr.S_un.S_addr==0
+ || my_connect(nlc->s,(SOCKADDR *)&nlc->sinProxy,sizeof(nlc->sinProxy), nloc)==SOCKET_ERROR) {
+ if(nlc->sinProxy.sin_addr.S_un.S_addr)
+ Netlib_Logf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"connect",WSAGetLastError());
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ }
+ else if(!NetlibInitHttpConnection(nlc,nlu,nloc)) {
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ FreePartiallyInitedConnection(nlc);
+ return (int)(HANDLE)NULL;
+ }
+ }
+ Netlib_Logf(nlu,"(%d) Connected to %s:%d",nlc->s,nloc->szHost,nloc->wPort);
+ return (int)nlc;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibopts.c b/miranda-wine/src/modules/netlib/netlibopts.c new file mode 100644 index 0000000..918b940 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibopts.c @@ -0,0 +1,516 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+extern struct NetlibUser **netlibUser;
+extern int netlibUserCount;
+extern CRITICAL_SECTION csNetlibUser;
+
+struct NetlibTempSettings {
+ DWORD flags;
+ char *szSettingsModule;
+ NETLIBUSERSETTINGS settings;
+} static *tempSettings;
+static int tempSettingsCount;
+
+static const UINT outgoingConnectionsControls[]={
+ IDC_STATIC12,
+ IDC_USEPROXY,
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYAUTHNTLM,
+ IDC_PROXYDNS,
+ IDC_SPECIFYPORTSO,
+ IDC_STATIC53,IDC_PORTSRANGEO,
+ IDC_STATIC54};
+static const UINT useProxyControls[]={
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYAUTHNTLM,
+ IDC_PROXYDNS};
+static const UINT specifyOPortsControls[]={
+ IDC_STATIC53,IDC_PORTSRANGEO,
+ IDC_STATIC54
+};
+static const UINT incomingConnectionsControls[]={
+ IDC_STATIC43,
+ IDC_SPECIFYPORTS,
+ IDC_STATIC51,IDC_PORTSRANGE,
+ IDC_STATIC52};
+static const UINT specifyPortsControls[]={
+ IDC_STATIC51,IDC_PORTSRANGE,
+ IDC_STATIC52};
+static const TCHAR* szProxyTypes[]={_T("<mixed>"),_T("SOCKS4"),_T("SOCKS5"),_T("HTTP"),_T("HTTPS")};
+static const WORD oftenProxyPorts[]={1080,1080,1080,8080,8080};
+
+#define M_REFRESHALL (WM_USER+100)
+#define M_REFRESHENABLING (WM_USER+101)
+
+static void ShowMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) ShowWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void EnableMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) EnableWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void AddProxyTypeItem(HWND hwndDlg,int type,int selectType)
+{
+ int i;
+ i=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_ADDSTRING,0,(LPARAM)(type==0?TranslateTS(szProxyTypes[type]):szProxyTypes[type]));
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_SETITEMDATA,i,type);
+ if(type==selectType) SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_SETCURSEL,i,0);
+}
+
+static void CopySettingsStruct(NETLIBUSERSETTINGS *dest,NETLIBUSERSETTINGS *source)
+{
+ *dest=*source;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+}
+
+static void CombineSettingsStrings(char **dest,char **source)
+{
+ if(*dest!=NULL && (*source==NULL || lstrcmpiA(*dest,*source))) {mir_free(*dest); *dest=NULL;}
+}
+
+static void CombineSettingsStructs(NETLIBUSERSETTINGS *dest,DWORD *destFlags,NETLIBUSERSETTINGS *source,DWORD sourceFlags)
+{
+ if(sourceFlags&NUF_OUTGOING) {
+ if(*destFlags&NUF_OUTGOING) {
+ if(dest->useProxy!=source->useProxy) dest->useProxy=2;
+ if(dest->proxyType!=source->proxyType) dest->proxyType=0;
+ CombineSettingsStrings(&dest->szProxyServer,&source->szProxyServer);
+ if(dest->wProxyPort!=source->wProxyPort) dest->wProxyPort=0;
+ if(dest->useProxyAuth!=source->useProxyAuth) dest->useProxyAuth=2;
+ CombineSettingsStrings(&dest->szProxyAuthUser,&source->szProxyAuthUser);
+ CombineSettingsStrings(&dest->szProxyAuthPassword,&source->szProxyAuthPassword);
+ if(dest->useProxyAuthNtlm!=source->useProxyAuthNtlm) dest->useProxyAuthNtlm=2;
+ if(dest->dnsThroughProxy!=source->dnsThroughProxy) dest->dnsThroughProxy=2;
+ if(dest->specifyOutgoingPorts!=source->specifyOutgoingPorts) dest->specifyOutgoingPorts=2;
+ CombineSettingsStrings(&dest->szOutgoingPorts,&source->szOutgoingPorts);
+ }
+ else {
+ dest->useProxy=source->useProxy;
+ dest->proxyType=source->proxyType;
+ dest->szProxyServer=source->szProxyServer;
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+ dest->wProxyPort=source->wProxyPort;
+ dest->useProxyAuth=source->useProxyAuth;
+ dest->szProxyAuthUser=source->szProxyAuthUser;
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ dest->szProxyAuthPassword=source->szProxyAuthPassword;
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ dest->useProxyAuthNtlm=source->useProxyAuthNtlm;
+ dest->dnsThroughProxy=source->dnsThroughProxy;
+ dest->specifyOutgoingPorts=source->specifyOutgoingPorts;
+ dest->szOutgoingPorts=source->szOutgoingPorts;
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ }
+ }
+ if(sourceFlags&NUF_INCOMING) {
+ if(*destFlags&NUF_INCOMING) {
+ if(dest->specifyIncomingPorts!=source->specifyIncomingPorts) dest->specifyIncomingPorts=2;
+ CombineSettingsStrings(&dest->szIncomingPorts,&source->szIncomingPorts);
+ }
+ else {
+ dest->specifyIncomingPorts=source->specifyIncomingPorts;
+ dest->szIncomingPorts=source->szIncomingPorts;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ }
+ }
+ if((*destFlags&NUF_NOHTTPSOPTION)!=(sourceFlags&NUF_NOHTTPSOPTION))
+ *destFlags=(*destFlags|sourceFlags)&~NUF_NOHTTPSOPTION;
+ else *destFlags|=sourceFlags;
+}
+
+static void ChangeSettingIntByCheckbox(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int newValue,i;
+
+ newValue=IsDlgButtonChecked(hwndDlg,ctrlId)!=BST_CHECKED;
+ CheckDlgButton(hwndDlg,ctrlId,newValue?BST_CHECKED:BST_UNCHECKED);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS))
+ *(int*)(((PBYTE)&tempSettings[i].settings)+memberOffset)=newValue;
+ }
+ else *(int*)(((PBYTE)&tempSettings[iUser].settings)+memberOffset)=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+}
+
+static void ChangeSettingStringByEdit(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int i,newValueLen;
+ char *szNewValue,**ppszNew;
+
+ newValueLen=GetWindowTextLength(GetDlgItem(hwndDlg,ctrlId));
+ szNewValue=(char*)mir_alloc(newValueLen+1);
+ GetDlgItemTextA(hwndDlg,ctrlId,szNewValue,newValueLen+1);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS)) {
+ ppszNew=(char**)(((PBYTE)&tempSettings[i].settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=mir_strdup(szNewValue);
+ }
+ mir_free(szNewValue);
+ }
+ else {
+ ppszNew=(char**)(((PBYTE)&tempSettings[iUser].settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=szNewValue;
+ }
+}
+
+static void WriteSettingsStructToDb(const char *szSettingsModule,NETLIBUSERSETTINGS *settings,DWORD flags)
+{
+ if(flags&NUF_OUTGOING) {
+ char szEncodedPassword[512];
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxy",(BYTE)settings->useProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLProxyType",(BYTE)settings->proxyType);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyServer",settings->szProxyServer?settings->szProxyServer:"");
+ DBWriteContactSettingWord(NULL,szSettingsModule,"NLProxyPort",(WORD)settings->wProxyPort);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuth",(BYTE)settings->useProxyAuth);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthUser",settings->szProxyAuthUser?settings->szProxyAuthUser:"");
+ lstrcpynA(szEncodedPassword,settings->szProxyAuthPassword?settings->szProxyAuthPassword:"",SIZEOF(szEncodedPassword));
+ CallService(MS_DB_CRYPT_ENCODESTRING,SIZEOF(szEncodedPassword),(LPARAM)szEncodedPassword);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthPassword",szEncodedPassword);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuthNtlm",(BYTE)settings->useProxyAuthNtlm);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLDnsThroughProxy",(BYTE)settings->dnsThroughProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyOutgoingPorts",(BYTE)settings->specifyOutgoingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLOutgoingPorts",settings->szOutgoingPorts?settings->szOutgoingPorts:"");
+ }
+ if(flags&NUF_INCOMING) {
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyIncomingPorts",(BYTE)settings->specifyIncomingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLIncomingPorts",settings->szIncomingPorts?settings->szIncomingPorts:"");
+ }
+}
+
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings)
+{
+ int iUser,i;
+ NETLIBUSERSETTINGS combinedSettings={0};
+ DWORD flags;
+
+ EnterCriticalSection(&csNetlibUser);
+ for(iUser=0;iUser<netlibUserCount;iUser++)
+ if(!lstrcmpA(szSettingsModule,netlibUser[iUser]->user.szSettingsModule)) break;
+ if(iUser==netlibUserCount) {
+ LeaveCriticalSection(&csNetlibUser);
+ return;
+ }
+ NetlibFreeUserSettingsStruct(&netlibUser[iUser]->settings); + CopySettingsStruct(&netlibUser[iUser]->settings,settings);
+ WriteSettingsStructToDb(netlibUser[iUser]->user.szSettingsModule,&netlibUser[iUser]->settings,netlibUser[iUser]->user.flags);
+ combinedSettings.cbSize=sizeof(combinedSettings);
+ for(i=0,flags=0;i<netlibUserCount;i++) {
+ if(netlibUser[iUser]->user.flags&NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&combinedSettings,&flags,&netlibUser[iUser]->settings,netlibUser[iUser]->user.flags);
+ }
+ if(combinedSettings.useProxy==2) combinedSettings.useProxy=0;
+ if(combinedSettings.proxyType==0) combinedSettings.proxyType=PROXYTYPE_SOCKS5;
+ if(combinedSettings.useProxyAuth==2) combinedSettings.useProxyAuth=0;
+ if(combinedSettings.useProxyAuthNtlm==2) combinedSettings.useProxyAuthNtlm=0;
+ if(combinedSettings.dnsThroughProxy==2) combinedSettings.dnsThroughProxy=1;
+ if(combinedSettings.specifyIncomingPorts==2) combinedSettings.specifyIncomingPorts=0;
+ WriteSettingsStructToDb("Netlib",&combinedSettings,flags);
+ NetlibFreeUserSettingsStruct(&combinedSettings);
+ LeaveCriticalSection(&csNetlibUser);
+}
+
+static BOOL CALLBACK DlgProcNetlibOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int iUser,iItem;
+
+ TranslateDialogDefault(hwndDlg);
+ iItem=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)TranslateT("<All connections>"));
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,(LPARAM)-1);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETCURSEL,iItem,0);
+ EnterCriticalSection(&csNetlibUser);
+ tempSettingsCount=netlibUserCount;
+ tempSettings=(struct NetlibTempSettings*)mir_alloc(sizeof(struct NetlibTempSettings)*tempSettingsCount);
+ for(iUser=0;iUser<netlibUserCount;iUser++) {
+ tempSettings[iUser].flags=netlibUser[iUser]->user.flags;
+ tempSettings[iUser].szSettingsModule=mir_strdup(netlibUser[iUser]->user.szSettingsModule);
+ CopySettingsStruct(&tempSettings[iUser].settings,&netlibUser[iUser]->settings);
+ if(netlibUser[iUser]->user.flags&NUF_NOOPTIONS) continue;
+ iItem=SendDlgItemMessageA(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)netlibUser[iUser]->user.szDescriptiveName);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,iUser);
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return TRUE;
+ }
+ case M_REFRESHALL:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ NETLIBUSERSETTINGS settings={0};
+ DWORD flags;
+
+ if(iUser==-1) {
+ int i;
+ settings.cbSize=sizeof(settings);
+ for(i=0,flags=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&settings,&flags,&tempSettings[i].settings,tempSettings[i].flags);
+ }
+ }
+ else {
+ NetlibFreeUserSettingsStruct(&settings); + CopySettingsStruct(&settings,&tempSettings[iUser].settings);
+ flags=tempSettings[iUser].flags;
+ }
+ ShowMultipleControls(hwndDlg,outgoingConnectionsControls,SIZEOF(outgoingConnectionsControls),flags&NUF_OUTGOING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_USEPROXY,settings.useProxy);
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_RESETCONTENT,0,0);
+ if(settings.proxyType==0) AddProxyTypeItem(hwndDlg,0,settings.proxyType);
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_SOCKS4,settings.proxyType);
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_SOCKS5,settings.proxyType);
+ if(flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTP,settings.proxyType);
+ if(!(flags&NUF_NOHTTPSOPTION)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTPS,settings.proxyType);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYHOST,settings.szProxyServer?settings.szProxyServer:"");
+ if(settings.wProxyPort) SetDlgItemInt(hwndDlg,IDC_PROXYPORT,settings.wProxyPort,FALSE);
+ else SetDlgItemTextA(hwndDlg,IDC_PROXYPORT,"");
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTH,settings.useProxyAuth);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYUSER,settings.szProxyAuthUser?settings.szProxyAuthUser:"");
+ SetDlgItemTextA(hwndDlg,IDC_PROXYPASS,settings.szProxyAuthPassword?settings.szProxyAuthPassword:"");
+ CheckDlgButton(hwndDlg,IDC_PROXYDNS,settings.dnsThroughProxy);
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTHNTLM,settings.useProxyAuthNtlm);
+
+ ShowMultipleControls(hwndDlg,incomingConnectionsControls,SIZEOF(incomingConnectionsControls),flags&NUF_INCOMING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTS,settings.specifyIncomingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGE,settings.szIncomingPorts?settings.szIncomingPorts:"");
+
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTSO,settings.specifyOutgoingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGEO,settings.szOutgoingPorts?settings.szOutgoingPorts:"");
+
+ NetlibFreeUserSettingsStruct(&settings);
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ break;
+ }
+ case M_REFRESHENABLING:
+ { int selectedProxyType;
+ TCHAR str[80];
+
+ selectedProxyType=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ wsprintf(str,TranslateT("(often %d)"),oftenProxyPorts[selectedProxyType]);
+ SetDlgItemText(hwndDlg,IDC_STOFTENPORT,str);
+ if(IsDlgButtonChecked(hwndDlg,IDC_USEPROXY)!=BST_UNCHECKED) {
+ int enableAuth=0,enableUser=0,enablePass=0,enableNtlm=0;
+ EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),TRUE);
+ if(selectedProxyType==0) {
+ int i;
+ for(i=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS || !(tempSettings[i].flags&NUF_OUTGOING) || !tempSettings[i].settings.useProxy) continue;
+ if(tempSettings[i].settings.proxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else {
+ enableAuth=1;
+ if(tempSettings[i].settings.useProxyAuth) {
+ if(tempSettings[i].settings.proxyType==PROXYTYPE_HTTP || tempSettings[i].settings.proxyType==PROXYTYPE_HTTPS) {
+ enableNtlm=1;
+ if(!tempSettings[i].settings.useProxyAuthNtlm) enableUser=enablePass=1;
+ }
+ else enableUser=enablePass=1;
+ }
+ }
+ }
+ }
+ else {
+ if(selectedProxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else {
+ enableAuth=1;
+ if(IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTH)!=BST_UNCHECKED) {
+ if(selectedProxyType==PROXYTYPE_HTTP || selectedProxyType==PROXYTYPE_HTTPS) {
+ enableNtlm=1;
+ if(IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTHNTLM)!=BST_CHECKED) enableUser=enablePass=1;
+ }
+ else enableUser=enablePass=1;
+ }
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTH),enableAuth);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC31),enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYUSER),enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC32),enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYPASS),enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTHNTLM),enableNtlm);
+ }
+ else EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),FALSE);
+ EnableMultipleControls(hwndDlg,specifyPortsControls,SIZEOF(specifyPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTS)!=BST_UNCHECKED);
+ EnableMultipleControls(hwndDlg,specifyOPortsControls,SIZEOF(specifyOPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTSO)!=BST_UNCHECKED);
+ break;
+ }
+ case WM_COMMAND:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ switch(LOWORD(wParam)) {
+ case IDC_NETLIBUSERS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return 0;
+ case IDC_LOGOPTIONS:
+ NetlibLogShowOptions();
+ return 0;
+ case IDC_PROXYTYPE:
+ if(HIWORD(wParam)!=CBN_SELCHANGE) return 0;
+ { int newValue,i;
+ newValue=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ if(iUser==-1) {
+ if(newValue==0) return 0;
+ for(i=0;i<tempSettingsCount;i++) {
+ if(tempSettings[i].flags&NUF_NOOPTIONS) continue;
+ if(newValue==PROXYTYPE_HTTP && !(tempSettings[i].flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)))
+ tempSettings[i].settings.proxyType=PROXYTYPE_HTTPS;
+ else if(newValue==PROXYTYPE_HTTPS && tempSettings[i].flags&NUF_NOHTTPSOPTION)
+ tempSettings[i].settings.proxyType=PROXYTYPE_HTTP;
+ else tempSettings[i].settings.proxyType=newValue;
+ }
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ }
+ else {
+ tempSettings[iUser].settings.proxyType=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ }
+ }
+ break;
+ case IDC_USEPROXY:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxy));
+ break;
+ case IDC_PROXYAUTH:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuth));
+ break;
+ case IDC_PROXYAUTHNTLM:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuthNtlm));
+ break;
+ case IDC_PROXYDNS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,dnsThroughProxy));
+ break;
+ case IDC_SPECIFYPORTS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyIncomingPorts));
+ break;
+ case IDC_SPECIFYPORTSO:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyOutgoingPorts));
+ break;
+ case IDC_PROXYHOST:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyServer));
+ break;
+ case IDC_PROXYPORT:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ { int newValue,i;
+ newValue=GetDlgItemInt(hwndDlg,LOWORD(wParam),NULL,FALSE);
+ if(iUser==-1) {
+ for(i=0;i<tempSettingsCount;i++)
+ if(!(tempSettings[i].flags&NUF_NOOPTIONS))
+ tempSettings[i].settings.wProxyPort=newValue;
+ }
+ else tempSettings[iUser].settings.wProxyPort=newValue;
+ }
+ break;
+ case IDC_PROXYUSER:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthUser));
+ break;
+ case IDC_PROXYPASS:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthPassword));
+ break;
+ case IDC_PORTSRANGE:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szIncomingPorts));
+ break;
+ case IDC_PORTSRANGEO:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szOutgoingPorts));
+ break;
+ }
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RECONNECTREQD),SW_SHOW);
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ break;
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { int iUser;
+ for(iUser=0;iUser<tempSettingsCount;iUser++)
+ NetlibSaveUserSettingsStruct(tempSettings[iUser].szSettingsModule,&tempSettings[iUser].settings);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int iUser;
+ for(iUser=0;iUser<tempSettingsCount;iUser++) {
+ mir_free(tempSettings[iUser].szSettingsModule);
+ NetlibFreeUserSettingsStruct(&tempSettings[iUser].settings);
+ }
+ mir_free(tempSettings);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_LOGOPTIONS};
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ int i,optionsCount;
+
+ EnterCriticalSection(&csNetlibUser);
+ for(i=0,optionsCount=0;i<netlibUserCount;i++)
+ if(!(netlibUser[i]->user.flags&NUF_NOOPTIONS)) optionsCount++;
+ LeaveCriticalSection(&csNetlibUser);
+ if ( optionsCount == 0 )
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_NETLIB);
+ odp.pszTitle = "Network";
+ odp.pfnDlgProc = DlgProcNetlibOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibpktrecver.c b/miranda-wine/src/modules/netlib/netlibpktrecver.c new file mode 100644 index 0000000..7bc6eb4 --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibpktrecver.c @@ -0,0 +1,85 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+int NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ struct NetlibPacketRecver *nlpr;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || lParam==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (int)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr=(struct NetlibPacketRecver*)mir_calloc(sizeof(struct NetlibPacketRecver));
+ if(nlpr==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (int)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr->handleType=NLH_PACKETRECVER;
+ nlpr->nlc=nlc;
+ nlpr->packetRecver.cbSize=sizeof(nlpr->packetRecver);
+ nlpr->packetRecver.bufferSize=lParam;
+ nlpr->packetRecver.buffer=(PBYTE)mir_alloc(nlpr->packetRecver.bufferSize);
+ nlpr->packetRecver.bytesUsed=0;
+ nlpr->packetRecver.bytesAvailable=0;
+ return (int)nlpr;
+}
+
+int NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ NETLIBPACKETRECVER *nlprParam=(NETLIBPACKETRECVER*)lParam;
+ int recvResult;
+
+ if(GetNetlibHandleType(nlpr)!=NLH_PACKETRECVER || nlprParam==NULL || nlprParam->cbSize!=sizeof(NETLIBPACKETRECVER) || nlprParam->bytesUsed>nlpr->packetRecver.bytesAvailable) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if (Miranda_Terminated()) { /* HACK: Lame, break while loops of protocols that can't kill their while loops, (cough, ICQ, cough) */
+ SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ nlpr->packetRecver.dwTimeout=nlprParam->dwTimeout;
+ if(nlprParam->bytesUsed==0) {
+ if(nlpr->packetRecver.bytesAvailable==nlpr->packetRecver.bufferSize) {
+ nlpr->packetRecver.bytesAvailable=0;
+ Netlib_Logf(nlpr->nlc->nlu,"Packet recver: packet overflowed buffer, ditching");
+ }
+ }
+ else {
+ MoveMemory(nlpr->packetRecver.buffer,nlpr->packetRecver.buffer+nlprParam->bytesUsed,nlpr->packetRecver.bytesAvailable-nlprParam->bytesUsed);
+ nlpr->packetRecver.bytesAvailable-=nlprParam->bytesUsed;
+ }
+ if(nlprParam->dwTimeout!=INFINITE) {
+ if(!WaitUntilReadable(nlpr->nlc->s,nlprParam->dwTimeout)) {
+ *nlprParam=nlpr->packetRecver;
+ return SOCKET_ERROR;
+ }
+ }
+ recvResult=NLRecv(nlpr->nlc,nlpr->packetRecver.buffer+nlpr->packetRecver.bytesAvailable,nlpr->packetRecver.bufferSize-nlpr->packetRecver.bytesAvailable,0);
+ if(recvResult>0) nlpr->packetRecver.bytesAvailable+=recvResult;
+ *nlprParam=nlpr->packetRecver;
+ return recvResult;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibsock.c b/miranda-wine/src/modules/netlib/netlibsock.c new file mode 100644 index 0000000..acedd8e --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibsock.c @@ -0,0 +1,166 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "netlib.h"
+
+extern CRITICAL_SECTION csNetlibCloseHandle;
+extern HANDLE hConnectionHeaderMutex;
+
+int NetlibSend(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ int result;
+
+ if(nlb==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_SEND)) return SOCKET_ERROR;
+ if(nlc->usingHttpGateway && !(nlb->flags&MSG_RAW)) {
+ if(!(nlb->flags&MSG_NOHTTPGATEWAYWRAP) && nlc->nlu->user.pfnHttpGatewayWrapSend) {
+ NetlibDumpData(nlc,nlb->buf,nlb->len,1,nlb->flags);
+ result=nlc->nlu->user.pfnHttpGatewayWrapSend((HANDLE)nlc,nlb->buf,nlb->len,nlb->flags|MSG_NOHTTPGATEWAYWRAP,NetlibSend);
+ }
+ else result=NetlibHttpGatewayPost(nlc,nlb->buf,nlb->len,nlb->flags);
+ }
+ else {
+ NetlibDumpData(nlc,nlb->buf,nlb->len,1,nlb->flags);
+ result=send(nlc->s,nlb->buf,nlb->len,nlb->flags&0xFFFF);
+ }
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+ return result;
+}
+
+int NetlibRecv(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ int recvResult;
+
+ if(nlb==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV)) return SOCKET_ERROR;
+ if(nlc->usingHttpGateway && !(nlb->flags&MSG_RAW))
+ recvResult=NetlibHttpGatewayRecv(nlc,nlb->buf,nlb->len,nlb->flags);
+ else
+ recvResult=recv(nlc->s,nlb->buf,nlb->len,nlb->flags&0xFFFF);
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ if(recvResult<=0) return recvResult;
+ NetlibDumpData(nlc,nlb->buf,recvResult,0,nlb->flags);
+ return recvResult;
+}
+
+static int ConnectionListToSocketList(HANDLE *hConns,fd_set *fd)
+{
+ struct NetlibConnection *nlcCheck;
+ int i;
+
+ FD_ZERO(fd);
+ for(i=0;hConns[i] && hConns[i]!=INVALID_HANDLE_VALUE && i<FD_SETSIZE;i++) {
+ nlcCheck=(struct NetlibConnection*)hConns[i];
+ if(nlcCheck->handleType!=NLH_CONNECTION && nlcCheck->handleType!=NLH_BOUNDPORT) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ FD_SET(nlcCheck->s,fd);
+ }
+ return 1;
+}
+
+int NetlibSelect(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECT *nls=(NETLIBSELECT*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+
+ if(nls==NULL || nls->cbSize!=sizeof(NETLIBSELECT)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(!ConnectionListToSocketList(nls->hReadConns,&readfd)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+}
+
+int NetlibSelectEx(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBSELECTEX *nls=(NETLIBSELECTEX*)lParam;
+ fd_set readfd,writefd,exceptfd;
+ TIMEVAL tv;
+ int rc=SOCKET_ERROR;
+ int j;
+ struct NetlibConnection *conn=NULL;
+
+ if(nls==NULL || nls->cbSize!=sizeof(NETLIBSELECTEX)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(!ConnectionListToSocketList(nls->hReadConns,&readfd)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ rc=select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ /* go thru each passed HCONN array and grab its socket handle, then give it to FD_ISSET()
+ to see if an event happened for that socket, if it has it will be returned as TRUE (otherwise not)
+ This happens for read/write/except */
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hReadConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+
+ if (conn->usingHttpGateway && conn->nlhpi.szHttpGetUrl == NULL && conn->dataBuffer == NULL)
+ nls->hReadStatus[j] = (conn->pHttpProxyPacketQueue != NULL);
+ else
+ nls->hReadStatus[j] = FD_ISSET(conn->s,&readfd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hWriteConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hWriteStatus[j] = FD_ISSET(conn->s,&writefd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hExceptConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hExceptStatus[j] = FD_ISSET(conn->s,&exceptfd);
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return rc;
+}
diff --git a/miranda-wine/src/modules/netlib/netlibupnp.c b/miranda-wine/src/modules/netlib/netlibupnp.c new file mode 100644 index 0000000..c91de6c --- /dev/null +++ b/miranda-wine/src/modules/netlib/netlibupnp.c @@ -0,0 +1,495 @@ +/* +UPnP plugin for Miranda IM +Copyright (C) 2006 borkra + +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. +*/ + +/* Main file for the Weather Protocol, includes loading, unloading, + upgrading, support for plugin uninsaller, and anything that doesn't + belong to any other file. +*/ + +#include "commonheaders.h" +#include "netlib.h" + +static char search_request_msg[] = + "M-SEARCH * HTTP/1.1\r\n" + "MX: 2\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "ST: urn:schemas-upnp-org:service:%s\r\n" + "\r\n"; + +static char xml_get_hdr[] = + "GET %s HTTP/1.1\r\n" + "Connection: close\r\n" + "Host: %s:%s\r\n\r\n"; + +static char soap_post_hdr[] = + "POST %s HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CONTENT-LENGTH: %u\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" + "SOAPACTION: \"%s#%s\"\r\n\r\n" + "%s"; + +static char soap_post_hdr_m[] = + "M-POST %s URL HTTP/1.1\r\n" + "HOST: %s:%s\r\n" + "CONTENT-LENGTH: %u\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" + "MAN: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n" + "01-SOAPACTION: \"%s#%s\"\r\n\r\n" + "%s"; + +static char search_device[] = + "<serviceType>%s</serviceType>"; + +static char soap_action[] = + "<s:Envelope\r\n" + " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n" + " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" + " <s:Body>\r\n" + " <u:%s xmlns:u=\"%s\">\r\n" + "%s" + " </u:%s>\r\n" + " </s:Body>\r\n" + "</s:Envelope>\r\n"; + +static char add_port_mapping[] = + " <NewRemoteHost></NewRemoteHost>\r\n" + " <NewExternalPort>%i</NewExternalPort>\r\n" + " <NewProtocol>%s</NewProtocol>\r\n" + " <NewInternalPort>%i</NewInternalPort>\r\n" + " <NewInternalClient>%s</NewInternalClient>\r\n" + " <NewEnabled>1</NewEnabled>\r\n" + " <NewPortMappingDescription>Miranda</NewPortMappingDescription>\r\n" + " <NewLeaseDuration>0</NewLeaseDuration>\r\n"; + +static char delete_port_mapping[] = + " <NewRemoteHost></NewRemoteHost>\r\n" + " <NewExternalPort>%i</NewExternalPort>\r\n" + " <NewProtocol>%s</NewProtocol>\r\n"; + +static char default_http_port[] = "80"; + +static BOOL gatewayFound = FALSE; +static SOCKADDR_IN locIP; +static time_t lastDiscTime = 0; +static int expireTime = 120; + +static char szCtlUrl[256], szDev[256]; + + +static BOOL txtParseParam(char* szData, char* presearch, + char* start, char* finish, char* param, int size) +{ + char *cp, *cp1; + int len; + + *param = 0; + + if (presearch != NULL) + { + cp1 = strstr(szData, presearch); + if (cp1 == NULL) return FALSE; + } + else + cp1 = szData; + + cp = strstr(cp1, start); + if (cp == NULL) return FALSE; + cp += strlen(start); + while (*cp == ' ') ++cp; + + cp1 = strstr(cp, finish); + if (cp1 == NULL) return FALSE; + while (*(cp1-1) == ' ' && cp1 > cp) --cp1; + + len = min(cp1 - cp, size); + strncpy(param, cp, len); + param[len] = 0; + + return TRUE; +} + +static LongLog(char* szData) +{ + char* buf = szData; + int sz = strlen(szData); + + while ( sz > 1000) + { + char* nbuf = buf + 1000; + char t = *nbuf; + *nbuf = 0; + Netlib_Logf(NULL, buf); + *nbuf = t; + buf = nbuf; + sz -= 1000; + } + Netlib_Logf(NULL, buf); +} + + +static void discoverUPnP(char* szUrl, int sizeUrl) +{ + char* buf; + int buflen; + unsigned i, j, nip = 0; + char* szData = NULL; + unsigned* ips = NULL; + + static const unsigned any = INADDR_ANY; + fd_set readfd; + TIMEVAL tv = { 1, 0 }; + + char hostname[256]; + PHOSTENT he; + + SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + SOCKADDR_IN enetaddr; + enetaddr.sin_family = AF_INET; + enetaddr.sin_port = htons(1900); + enetaddr.sin_addr.s_addr = inet_addr("239.255.255.250"); + + FD_ZERO(&readfd); + FD_SET(sock, &readfd); + + szUrl[0] = 0; + + gethostname( hostname, sizeof( hostname )); + he = gethostbyname( hostname ); + + if (he) + { + while(he->h_addr_list[nip]) ++nip; + + ips = mir_alloc(nip * sizeof(unsigned)); + + for (j=0; j<nip; ++j) + ips[j] = *(unsigned*)he->h_addr_list[j]; + } + + buf = mir_alloc(1500); + + for(i = 3; --i && szUrl[0] == 0;) + { + for (j=0; j<nip; ++j) + { + if (ips) + setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ips[j], sizeof(unsigned)); + + buflen = mir_snprintf(buf, 1500, search_request_msg, "WANIPConnection:1"); + sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); + LongLog(buf); + + buflen = mir_snprintf(buf, 1500, search_request_msg, "WANPPPConnection:1"); + sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); + LongLog(buf); + } + + while (select(0, &readfd, NULL, NULL, &tv) == 1) + { + buflen = recv(sock, buf, 1500, 0); + if (buflen != SOCKET_ERROR) + { + buf[buflen] = 0; + LongLog(buf); + + if (txtParseParam(buf, NULL, "LOCATION:", "\r", szUrl, sizeUrl) || + txtParseParam(buf, NULL, "Location:", "\r", szUrl, sizeUrl)) + { + char age[30]; + txtParseParam(szUrl, NULL, "http://", "/", szCtlUrl, sizeof(szCtlUrl)); + txtParseParam(buf, NULL, "ST:", "\r", szDev, sizeof(szDev)); + txtParseParam(buf, "max-age", "=", "\r", age, sizeof(age)); + expireTime = atoi(age); + break; + } + } + } + } + + mir_free(buf); + mir_free(ips); + setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&any, sizeof(unsigned)); + closesocket(sock); +} + + +static int httpTransact (char* szUrl, char* szResult, int resSize, char* szActionName) +{ + // Parse URL + char *ppath, *phost, *pport, *szHost, *szPort, szRes[6]; + int sz, res = 0; + + char* szPostHdr = soap_post_hdr; + char* szData = mir_alloc(4096); + char* szReq = szActionName ? mir_strdup(szResult) : NULL; + szResult[0] = 0; + + + phost = strstr(szUrl,"://"); + if (phost == NULL) phost = szUrl; + else phost += 3; + + ppath = strchr(phost,'/'); + if (ppath == NULL) ppath = phost + strlen(phost); + + pport = strchr(phost,':'); + if (pport == NULL) pport = ppath; + + sz = pport - phost + 1; + szHost = _alloca(sz); + strncpy(szHost, phost, sz); + szHost[sz-1] = 0; + + sz = ppath - pport; + if (sz > 1) + { + szPort = _alloca(sz); + strncpy(szPort, pport+1, sz); + szPort[sz-1] = 0; + } + else + szPort = default_http_port; + + for (;;) + { + if (szActionName == NULL) + sz = mir_snprintf (szData, 4096, + xml_get_hdr, ppath, szHost, szPort); + else + { + char szData1[1024]; + + sz = mir_snprintf (szData1, sizeof(szData1), + soap_action, szActionName, szDev, szReq, szActionName); + + sz = mir_snprintf (szData, 4096, + szPostHdr, ppath, szHost, szPort, + sz, szDev, szActionName, szData1); + } + + { + static TIMEVAL tv = { 3, 0 }; + static unsigned ttl = 4; + fd_set readfd; + + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + SOCKADDR_IN enetaddr; + enetaddr.sin_family = AF_INET; + enetaddr.sin_port = htons((unsigned short)atol(szPort)); + enetaddr.sin_addr.s_addr = inet_addr(szHost); + + if (enetaddr.sin_addr.s_addr == INADDR_NONE) + { + PHOSTENT he = gethostbyname(szHost); + if (he) + enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0]; + } + + Netlib_Logf(NULL, "UPnP HTTP connection Host: %s Port: %s\n", szHost, szPort); + + FD_ZERO(&readfd); + FD_SET(sock, &readfd); + + setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned)); + + if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == 0) + { + if (send( sock, szData, sz, 0 ) != SOCKET_ERROR) + { + LongLog(szData); + sz = 0; + for(;;) + { + int bytesRecv; + char *hdrend; + + if (select(0, &readfd, NULL, NULL, &tv) != 1) + { + Netlib_Logf(NULL, "UPnP select timeout"); + break; + } + + bytesRecv = recv( sock, &szResult[sz], resSize-sz, 0 ); + if ( bytesRecv == 0 || bytesRecv == SOCKET_ERROR) + break; + else + sz += bytesRecv; + + if (sz >= (resSize-1)) + { + szResult[resSize-1] = 0; + break; + } + else + szResult[sz] = 0; + + hdrend = strstr(szResult, "\r\n\r\n"); + if (hdrend != NULL && + (txtParseParam(szResult, NULL, "Content-Length:", "\r", szRes, sizeof(szRes)) || + txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\r", szRes, sizeof(szRes)))) + { + int pktsz = atol(szRes) + (hdrend - szResult + 4); + if (sz >= pktsz) + { + szResult[pktsz] = 0; + break; + } + } + + } + LongLog(szResult); + } + else + Netlib_Logf(NULL, "UPnP send failed %d", WSAGetLastError()); + } + else + Netlib_Logf(NULL, "UPnP connect failed %d", WSAGetLastError()); + + if (szActionName == NULL) + { + int len = sizeof(locIP); + getsockname(sock, (SOCKADDR*)&locIP, &len); + } + + shutdown(sock, 2); + closesocket(sock); + } + txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes)); + res = atol(szRes); + if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr) + szPostHdr = soap_post_hdr_m; + else + break; + } + + mir_free(szData); + mir_free(szReq); + return res; +} + + +static void findUPnPGateway(void) +{ + time_t curTime = time(NULL); + + if ((curTime - lastDiscTime) >= expireTime) + { + char szUrl[256]; + char* szData = mir_alloc(8192); + + lastDiscTime = curTime; + + discoverUPnP(szUrl, sizeof(szUrl)); + gatewayFound = szUrl[0] != 0 && httpTransact(szUrl, szData, 8192, NULL) == 200; + + if (gatewayFound) + { + char szTemp[256]; + size_t ctlLen; + + txtParseParam(szData, NULL, "<URLBase>", "</URLBase>", szTemp, sizeof(szTemp)); + if (szTemp[0] != 0) strcpy(szCtlUrl, szTemp); + ctlLen = strlen(szCtlUrl); + if (ctlLen > 0 && szCtlUrl[ctlLen-1] == '/') + szCtlUrl[--ctlLen] = 0; + + mir_snprintf(szTemp, sizeof(szTemp), search_device, szDev); + txtParseParam(szData, szTemp, "<controlURL>", "</controlURL>", szUrl, sizeof(szUrl)); + switch (szUrl[0]) + { + case 0: + gatewayFound = FALSE; + break; + + case '/': + strncat(szCtlUrl, szUrl, sizeof(szCtlUrl) - ctlLen); + szCtlUrl[sizeof(szCtlUrl)-1] = 0; + break; + + default: + strncpy(szCtlUrl, szUrl, sizeof(szCtlUrl)); + szCtlUrl[sizeof(szCtlUrl)-1] = 0; + break; + } + } + Netlib_Logf(NULL, "UPnP Gateway detected %d, Control URL: %s\n", gatewayFound, szCtlUrl); + mir_free(szData); + } +} + + +BOOL NetlibUPnPAddPortMapping(WORD intport, char *proto, + WORD *extport, DWORD *extip, BOOL search) +{ + int res = 0; + + findUPnPGateway(); + + if (gatewayFound) + { + char* szData = mir_alloc(4096); + char szExtIP[30]; + + *extport = intport - 1; + *extip = ntohl(locIP.sin_addr.S_un.S_addr); + + do { + ++*extport; + mir_snprintf(szData, 4096, add_port_mapping, + *extport, proto, intport, inet_ntoa(locIP.sin_addr)); + res = httpTransact(szCtlUrl, szData, 4096, "AddPortMapping"); + } while (search && res == 718); + + if (res == 200) + { + szData[0] = 0; + res = httpTransact(szCtlUrl, szData, 4096, "GetExternalIPAddress"); + if (res == 200 && txtParseParam(szData, "<NewExternalIPAddress", ">", "<", szExtIP, sizeof(szExtIP))) + *extip = ntohl(inet_addr(szExtIP)); + } + mir_free(szData); + } + + return res == 200; +} + + +void NetlibUPnPDeletePortMapping(WORD extport, char* proto) +{ + if (extport != 0) + { +// findUPnPGateway(); + + if (gatewayFound) + { + char* szData = mir_alloc(4096); + + mir_snprintf(szData, 4096, delete_port_mapping, + extport, proto); + httpTransact(szCtlUrl, szData, 4096, "DeletePortMapping"); + + mir_free(szData); + } + } +} + diff --git a/miranda-wine/src/modules/options/options.c b/miranda-wine/src/modules/options/options.c new file mode 100644 index 0000000..cea7421 --- /dev/null +++ b/miranda-wine/src/modules/options/options.c @@ -0,0 +1,664 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+char* u2a( wchar_t* src );
+
+#define OPTIONPAGE_OLD_SIZE 40
+
+static HANDLE hOptionsInitEvent;
+static HWND hwndOptions=NULL;
+
+struct OptionsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DlgTemplateExBegin {
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+};
+
+struct OptionsPageData {
+ DLGTEMPLATE *pTemplate;
+ DLGPROC dlgProc;
+ HINSTANCE hInst;
+ HTREEITEM hTreeItem;
+ HWND hwnd;
+ int changed;
+ int simpleHeight,expertHeight;
+ int simpleWidth,expertWidth;
+ int simpleBottomControlId,simpleRightControlId;
+ int nExpertOnlyControls;
+ UINT *expertOnlyControls;
+ DWORD flags;
+ TCHAR *pszTitle, *pszGroup;
+};
+
+struct OptionsDlgData {
+ int pageCount;
+ int currentPage;
+ HTREEITEM hCurrentPage;
+ struct OptionsPageData *opd;
+ RECT rcDisplay;
+ HFONT hBoldFont;
+};
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF( str );
+ tvi.hItem = TreeView_GetRoot( hwndTree );
+ while( tvi.hItem != NULL ) {
+ SendMessage( hwndTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+ if( !_tcsicmp( str,name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+static BOOL CALLBACK BoldGroupTitlesEnumChildren(HWND hwnd,LPARAM lParam)
+{
+ TCHAR szClass[64];
+
+ GetClassName(hwnd,szClass,SIZEOF(szClass));
+ if(!lstrcmp(szClass,_T("Button")) && (GetWindowLong(hwnd,GWL_STYLE)&0x0F)==BS_GROUPBOX)
+ SendMessage(hwnd,WM_SETFONT,lParam,0);
+ return TRUE;
+}
+
+#define OPTSTATE_PREFIX "s_"
+
+static void SaveOptionsTreeState(HWND hdlg) {
+ TVITEMA tvi;
+ char buf[130],str[128];
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot( GetDlgItem( hdlg, IDC_PAGETREE ));
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( GetDlgItem(hdlg,IDC_PAGETREE), TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ wsprintfA(buf,"%s%s",OPTSTATE_PREFIX,str);
+ DBWriteContactSettingByte(NULL,"Options",buf,(BYTE)((tvi.state&TVIS_EXPANDED)?1:0));
+ }
+ tvi.hItem = TreeView_GetNextSibling( GetDlgItem( hdlg, IDC_PAGETREE ), tvi.hItem );
+} }
+
+#define DM_FOCUSPAGE (WM_USER+10)
+#define DM_REBUILDPAGETREE (WM_USER+11)
+
+static BOOL CALLBACK OptionsDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct OptionsDlgData* dat = (struct OptionsDlgData* )GetWindowLong( hdlg, GWL_USERDATA );
+
+ switch ( message ) {
+ case WM_INITDIALOG:
+ { HRSRC hrsrc;
+ HGLOBAL hglb;
+ PROPSHEETHEADER *psh=(PROPSHEETHEADER*)lParam;
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)psh->pStartPage;
+ OPTIONSDIALOGPAGE *odp;
+ int i;
+ POINT pt;
+ RECT rc,rcDlg;
+ struct DlgTemplateExBegin *dte;
+ TCHAR *lastPage = NULL, *lastGroup = NULL;
+ DBVARIANT dbv;
+
+ Utils_RestoreWindowPositionNoSize(hdlg, NULL, "Options", "");
+ TranslateDialogDefault(hdlg);
+ SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_OPTIONS)));
+ CheckDlgButton(hdlg,IDC_EXPERT,DBGetContactSettingByte(NULL,"Options","Expert",SETTING_SHOWEXPERT_DEFAULT)?BST_CHECKED:BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ dat=(struct OptionsDlgData*)mir_alloc(sizeof(struct OptionsDlgData));
+ SetWindowLong(hdlg,GWL_USERDATA,(LONG)dat);
+ SetWindowText(hdlg,psh->pszCaption);
+ { LOGFONT lf;
+ dat->hBoldFont=(HFONT)SendDlgItemMessage(hdlg,IDC_EXPERT,WM_GETFONT,0,0);
+ GetObject(dat->hBoldFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ }
+ dat->pageCount = psh->nPages;
+ dat->opd = ( struct OptionsPageData* )mir_alloc( sizeof(struct OptionsPageData) * dat->pageCount );
+ odp = ( OPTIONSDIALOGPAGE* )psh->ppsp;
+
+ dat->currentPage = -1;
+ if ( ood->pszPage == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastPage", &dbv )) {
+ lastPage = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastPage = LangPackPcharToTchar( ood->pszPage );
+
+ if ( ood->pszGroup == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastGroup", &dbv )) {
+ lastGroup = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastGroup = LangPackPcharToTchar( ood->pszGroup );
+
+ for ( i=0; i < dat->pageCount; i++ ) {
+ DWORD resSize;
+ hrsrc=FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5));
+ hglb=LoadResource(odp[i].hInstance,hrsrc);
+ resSize=SizeofResource(odp[i].hInstance,hrsrc);
+ dat->opd[i].pTemplate=mir_alloc(resSize);
+ memcpy(dat->opd[i].pTemplate,LockResource(hglb),resSize);
+ dte=(struct DlgTemplateExBegin*)dat->opd[i].pTemplate;
+ if ( dte->signature == 0xFFFF ) {
+ //this feels like an access violation, and is according to boundschecker
+ //...but it works - for now
+ //may well have to remove and sort out the original dialogs
+ dte->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ dte->style|=WS_CHILD;
+ }
+ else {
+ dat->opd[i].pTemplate->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ dat->opd[i].pTemplate->style|=WS_CHILD;
+ }
+ dat->opd[i].dlgProc=odp[i].pfnDlgProc;
+ dat->opd[i].hInst=odp[i].hInstance;
+ dat->opd[i].hwnd=NULL;
+ dat->opd[i].changed=0;
+ dat->opd[i].simpleHeight=dat->opd[i].expertHeight=0;
+ dat->opd[i].simpleBottomControlId=odp[i].nIDBottomSimpleControl;
+ dat->opd[i].simpleWidth=dat->opd[i].expertWidth=0;
+ dat->opd[i].simpleRightControlId=odp[i].nIDRightSimpleControl;
+ dat->opd[i].nExpertOnlyControls=odp[i].nExpertOnlyControls;
+ dat->opd[i].expertOnlyControls=odp[i].expertOnlyControls;
+ dat->opd[i].flags=odp[i].flags;
+ if ( odp[i].pszTitle == NULL )
+ dat->opd[i].pszTitle = NULL;
+ else if ( odp[i].flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ dat->opd[i].pszTitle = ( TCHAR* )mir_wstrdup( odp[i].ptszTitle );
+ #else
+ dat->opd[i].pszTitle = u2a(( WCHAR* )odp[i].ptszTitle );
+ #endif
+ }
+ else dat->opd[i].pszTitle = ( TCHAR* )mir_strdup( odp[i].pszTitle );
+
+ if ( odp[i].pszGroup == NULL )
+ dat->opd[i].pszGroup = NULL;
+ else if ( odp[i].flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ dat->opd[i].pszGroup = ( TCHAR* )mir_wstrdup( odp[i].ptszGroup );
+ #else
+ dat->opd[i].pszGroup = u2a(( WCHAR* )odp[i].ptszGroup );
+ #endif
+ }
+ else dat->opd[i].pszGroup = ( TCHAR* )mir_strdup( odp[i].pszGroup );
+
+ if ( !lstrcmp( lastPage, odp[i].ptszTitle ) &&
+ (( lastGroup == NULL && odp[i].ptszGroup == NULL ) || !lstrcmp( lastGroup, odp[i].ptszGroup )))
+ dat->currentPage = i;
+ }
+ mir_free( lastGroup );
+ mir_free( lastPage );
+
+ GetWindowRect(hdlg,&rcDlg);
+ pt.x=pt.y=0;
+ ClientToScreen(hdlg,&pt);
+ GetWindowRect(GetDlgItem(hdlg,IDC_PAGETREE),&rc);
+ dat->rcDisplay.left=rc.right-pt.x+(rc.left-rcDlg.left);
+ dat->rcDisplay.top=rc.top-pt.y;
+ dat->rcDisplay.right=rcDlg.right-(rc.left-rcDlg.left)-pt.x;
+ GetWindowRect(GetDlgItem(hdlg,IDOK),&rc);
+ dat->rcDisplay.bottom=rc.top-(rcDlg.bottom-rc.bottom)-pt.y;
+
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+ return TRUE;
+ }
+ case DM_REBUILDPAGETREE:
+ { int i;
+ TVINSERTSTRUCT tvis;
+ TVITEMA tvi;
+ char str[128],buf[130];
+
+ TreeView_SelectItem(GetDlgItem(hdlg,IDC_PAGETREE),NULL);
+ if ( dat->currentPage != (-1))
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ ShowWindow(GetDlgItem(hdlg,IDC_PAGETREE),SW_HIDE); //deleteall is annoyingly visible
+ TreeView_DeleteAllItems(GetDlgItem(hdlg,IDC_PAGETREE));
+ dat->hCurrentPage = NULL;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if (( dat->opd[i].flags & ODPF_SIMPLEONLY ) && IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ if (( dat->opd[i].flags & ODPF_EXPERTONLY ) && !IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ tvis.hParent = NULL;
+ if(dat->opd[i].pszGroup != NULL) {
+ tvis.hParent = FindNamedTreeItemAtRoot(GetDlgItem(hdlg,IDC_PAGETREE),dat->opd[i].pszGroup);
+ if(tvis.hParent == NULL) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = dat->opd[i].pszGroup;
+ tvis.hParent = TreeView_InsertItem( GetDlgItem(hdlg,IDC_PAGETREE), &tvis );
+ }
+ }
+ else {
+ TVITEM tvi;
+ tvi.hItem = FindNamedTreeItemAtRoot(GetDlgItem(hdlg,IDC_PAGETREE),dat->opd[i].pszTitle);
+ if( tvi.hItem != NULL ) {
+ if ( i == dat->currentPage ) dat->hCurrentPage=tvi.hItem;
+ tvi.mask = TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hdlg,IDC_PAGETREE),&tvi);
+ if ( tvi.lParam == -1 ) {
+ tvi.lParam = i;
+ TreeView_SetItem(GetDlgItem(hdlg,IDC_PAGETREE),&tvi);
+ continue;
+ } } }
+
+ tvis.item.pszText = dat->opd[i].pszTitle;
+ tvis.item.lParam = i;
+ dat->opd[i].hTreeItem = TreeView_InsertItem( GetDlgItem(hdlg,IDC_PAGETREE), &tvis);
+ if ( i == dat->currentPage )
+ dat->hCurrentPage = dat->opd[i].hTreeItem;
+ }
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(GetDlgItem(hdlg,IDC_PAGETREE));
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( GetDlgItem(hdlg,IDC_PAGETREE), TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ wsprintfA(buf,"%s%s",OPTSTATE_PREFIX,str);
+ if ( !DBGetContactSettingByte( NULL, "Options", buf, 1 ))
+ TreeView_Expand( GetDlgItem(hdlg,IDC_PAGETREE), tvi.hItem, TVE_COLLAPSE );
+ }
+ tvi.hItem = TreeView_GetNextSibling( GetDlgItem( hdlg, IDC_PAGETREE ), tvi.hItem );
+ }
+ if(dat->hCurrentPage==NULL) dat->hCurrentPage=TreeView_GetRoot(GetDlgItem(hdlg,IDC_PAGETREE));
+ dat->currentPage=-1;
+ TreeView_SelectItem(GetDlgItem(hdlg,IDC_PAGETREE),dat->hCurrentPage);
+ ShowWindow(GetDlgItem(hdlg,IDC_PAGETREE),SW_SHOW);
+ break;
+ }
+ case PSM_CHANGED:
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),TRUE);
+ if(dat->currentPage != (-1)) dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+ case PSM_ISEXPERT:
+ SetWindowLong(hdlg,DWL_MSGRESULT,IsDlgButtonChecked(hdlg,IDC_EXPERT));
+ return TRUE;
+ case PSM_GETBOLDFONT:
+ SetWindowLong(hdlg,DWL_MSGRESULT,(LONG)dat->hBoldFont);
+ return TRUE;
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_ITEMEXPANDING:
+ SetWindowLong(hdlg,DWL_MSGRESULT,FALSE);
+ return TRUE;
+ case TVN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLong(hdlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TVN_SELCHANGED:
+ { TVITEM tvi;
+ ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_HIDE);
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ tvi.hItem=dat->hCurrentPage=TreeView_GetSelection(GetDlgItem(hdlg,IDC_PAGETREE));
+ if(tvi.hItem==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hdlg,IDC_PAGETREE),&tvi);
+ dat->currentPage=tvi.lParam;
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].hwnd == NULL ) {
+ RECT rcPage;
+ RECT rcControl,rc;
+ int w,h;
+
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectA(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hdlg,dat->opd[dat->currentPage].dlgProc);
+ if(dat->opd[dat->currentPage].flags&ODPF_BOLDGROUPS)
+ EnumChildWindows(dat->opd[dat->currentPage].hwnd,BoldGroupTitlesEnumChildren,(LPARAM)dat->hBoldFont);
+ GetClientRect(dat->opd[dat->currentPage].hwnd,&rcPage);
+ dat->opd[dat->currentPage].expertWidth=rcPage.right;
+ dat->opd[dat->currentPage].expertHeight=rcPage.bottom;
+ GetWindowRect(dat->opd[dat->currentPage].hwnd,&rc);
+
+ if(dat->opd[dat->currentPage].simpleBottomControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleBottomControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleHeight=rcControl.bottom-rc.top;
+ }
+ else dat->opd[dat->currentPage].simpleHeight=dat->opd[dat->currentPage].expertHeight;
+
+ if(dat->opd[dat->currentPage].simpleRightControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleRightControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleWidth=rcControl.right-rc.left;
+ }
+ else dat->opd[dat->currentPage].simpleWidth=dat->opd[dat->currentPage].expertWidth;
+
+ if(IsDlgButtonChecked(hdlg,IDC_EXPERT)) {
+ w=dat->opd[dat->currentPage].expertWidth;
+ h=dat->opd[dat->currentPage].expertHeight;
+ }
+ else {
+ int i;
+ for(i=0;i<dat->opd[dat->currentPage].nExpertOnlyControls;i++)
+ ShowWindow(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].expertOnlyControls[i]),SW_HIDE);
+ w=dat->opd[dat->currentPage].simpleWidth;
+ h=dat->opd[dat->currentPage].simpleHeight;
+ }
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-w)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-h)>>1,w,h,0);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ if(((LPNMTREEVIEW)lParam)->action==TVC_BYMOUSE) PostMessage(hdlg,DM_FOCUSPAGE,0,0);
+ else SetFocus(GetDlgItem(hdlg,IDC_PAGETREE));
+ }
+ else ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_SHOW);
+ break;
+ } } }
+ break;
+ case DM_FOCUSPAGE:
+ if(dat->currentPage==-1) break;
+ SetFocus(dat->opd[dat->currentPage].hwnd);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_EXPERT:
+ { int expert=IsDlgButtonChecked(hdlg,IDC_EXPERT);
+ int i,j;
+ PSHNOTIFY pshn;
+ RECT rcPage;
+ int neww,newh;
+
+ DBWriteContactSettingByte(NULL,"Options","Expert",(BYTE)expert);
+ pshn.hdr.idFrom=0;
+ pshn.lParam=expert;
+ pshn.hdr.code=PSN_EXPERTCHANGED;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+
+ for(j=0;j<dat->opd[i].nExpertOnlyControls;j++)
+ ShowWindow(GetDlgItem(dat->opd[i].hwnd,dat->opd[i].expertOnlyControls[j]),expert?SW_SHOW:SW_HIDE);
+
+ GetClientRect(dat->opd[i].hwnd,&rcPage);
+ if(dat->opd[i].simpleBottomControlId) newh=expert?dat->opd[i].expertHeight:dat->opd[i].simpleHeight;
+ else newh=rcPage.bottom-rcPage.top;
+ if(dat->opd[i].simpleRightControlId) neww=expert?dat->opd[i].expertWidth:dat->opd[i].simpleWidth;
+ else neww=rcPage.right-rcPage.left;
+ if(i==dat->currentPage) {
+ POINT ptStart,ptEnd,ptNow;
+ DWORD thisTick,startTick;
+ RECT rc;
+
+ ptNow.x=ptNow.y=0;
+ ClientToScreen(hdlg,&ptNow);
+ GetWindowRect(dat->opd[i].hwnd,&rc);
+ ptStart.x=rc.left-ptNow.x;
+ ptStart.y=rc.top-ptNow.y;
+ ptEnd.x=(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1;
+ ptEnd.y=(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1;
+ if(abs(ptEnd.x-ptStart.x)>5 || abs(ptEnd.y-ptStart.y)>5) {
+ startTick=GetTickCount();
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,0,0,min(neww,rcPage.right),min(newh,rcPage.bottom),SWP_NOMOVE);
+ UpdateWindow(dat->opd[i].hwnd);
+ for(;;) {
+ thisTick=GetTickCount();
+ if(thisTick>startTick+100) break;
+ ptNow.x=ptStart.x+(ptEnd.x-ptStart.x)*(int)(thisTick-startTick)/100;
+ ptNow.y=ptStart.y+(ptEnd.y-ptStart.y)*(int)(thisTick-startTick)/100;
+ SetWindowPos(dat->opd[i].hwnd,0,ptNow.x,ptNow.y,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ }
+ }
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1,neww,newh,0);
+ }
+ SaveOptionsTreeState(hdlg);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+ break;
+ }
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hdlg);
+ break;
+ }
+ case IDOK:
+ case IDC_APPLY:
+ { int i;
+ PSHNOTIFY pshn;
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ if(dat->currentPage!=(-1)) {
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ dat->opd[i].changed=0;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ dat->hCurrentPage=dat->opd[i].hTreeItem;
+ TreeView_SelectItem(GetDlgItem(hdlg,IDC_PAGETREE),dat->hCurrentPage);
+ if(dat->currentPage!=(-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ if (dat->currentPage != (-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ } }
+
+ if ( LOWORD( wParam ) == IDOK )
+ DestroyWindow(hdlg);
+ break;
+ } }
+ break;
+ case WM_DESTROY:
+ SaveOptionsTreeState( hdlg );
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].pszGroup )
+ DBWriteContactSettingTString( NULL, "Options", "LastGroup", dat->opd[dat->currentPage].pszGroup );
+ else DBDeleteContactSetting( NULL, "Options", "LastGroup" );
+ DBWriteContactSettingTString( NULL, "Options", "LastPage", dat->opd[dat->currentPage].pszTitle );
+ }
+ else {
+ DBDeleteContactSetting(NULL,"Options","LastGroup");
+ DBDeleteContactSetting(NULL,"Options","LastPage");
+ }
+ Utils_SaveWindowPosition(hdlg, NULL, "Options", "");
+ {
+ int i;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ if(dat->opd[i].pszGroup) mir_free(dat->opd[i].pszGroup);
+ if(dat->opd[i].pszTitle) mir_free(dat->opd[i].pszTitle);
+ if(dat->opd[i].pTemplate) mir_free(dat->opd[i].pTemplate);
+ } }
+ mir_free(dat->opd);
+ DeleteObject(dat->hBoldFont);
+ mir_free(dat);
+ hwndOptions=NULL;
+ break;
+ }
+ return FALSE;
+}
+
+static void OpenOptionsNow(const char *pszGroup,const char *pszPage)
+{
+ PROPSHEETHEADER psh;
+ struct OptionsPageInit opi;
+ int i;
+ OPENOPTIONSDIALOG ood;
+
+ if(IsWindow(hwndOptions)) {
+ ShowWindow(hwndOptions,SW_RESTORE);
+ SetForegroundWindow(hwndOptions);
+ return;
+ }
+ opi.pageCount=0;
+ opi.odp=NULL;
+ NotifyEventHooks(hOptionsInitEvent,(WPARAM)&opi,0);
+ if(opi.pageCount==0) return;
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ ood.pszGroup=pszGroup;
+ ood.pszPage=pszPage;
+ psh.pStartPage = (LPCTSTR)&ood; //more structure misuse
+ psh.pszCaption = TranslateT("Miranda IM Options");
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+ hwndOptions=CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_OPTIONS),NULL,OptionsDlgProc,(LPARAM)&psh);
+ for(i=0;i<opi.pageCount;i++) {
+ mir_free((char*)opi.odp[i].pszTitle);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ mir_free(opi.odp);
+}
+
+static int OpenOptions(WPARAM wParam,LPARAM lParam)
+{
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)lParam;
+ if(ood==NULL||ood->cbSize!=sizeof(OPENOPTIONSDIALOG)) return 1;
+ OpenOptionsNow(ood->pszGroup,ood->pszPage);
+ return 0;
+}
+
+static int OpenOptionsDialog(WPARAM wParam,LPARAM lParam)
+{
+ OpenOptionsNow(NULL,NULL);
+ return 0;
+}
+
+static int AddOptionsPage(WPARAM wParam,LPARAM lParam)
+{ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct OptionsPageInit *opi=(struct OptionsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE) && odp->cbSize != OPTIONPAGE_OLD_SIZE) return 1;
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ memset( dst, 0, sizeof( OPTIONSDIALOGPAGE ));
+ memcpy( dst, odp, odp->cbSize );
+
+ if ( odp->ptszTitle != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTitle = mir_wstrdup( TranslateW( odp->ptszTitle ));
+ else {
+ dst->ptszTitle = LangPackPcharToTchar( odp->pszTitle );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTitle = mir_strdup( Translate( odp->pszTitle ));
+ #endif
+ }
+
+ if ( odp->pszGroup != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszGroup = mir_wstrdup( TranslateW( odp->ptszGroup ));
+ else {
+ dst->ptszGroup = LangPackPcharToTchar( odp->pszGroup );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszGroup = mir_strdup( Translate( odp->pszGroup ));
+ #endif
+ }
+
+ if (( DWORD )odp->pszTemplate & 0xFFFF0000 )
+ dst->pszTemplate = mir_strdup( odp->pszTemplate );
+
+ opi->pageCount++;
+ return 0;
+}
+
+static int OptModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.flags=0;
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_OPTIONS));
+ mi.position=1900000000;
+ mi.pszName=Translate("&Options...");
+ mi.pszService="Options/OptionsCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ return 0;
+}
+
+int ShutdownOptionsModule(WPARAM wParam,LPARAM lParam)
+{
+ if (IsWindow(hwndOptions)) DestroyWindow(hwndOptions);
+ hwndOptions=NULL;
+ return 0;
+}
+
+int LoadOptionsModule(void)
+{
+ hwndOptions=NULL;
+ hOptionsInitEvent=CreateHookableEvent(ME_OPT_INITIALISE);
+ CreateServiceFunction(MS_OPT_ADDPAGE,AddOptionsPage);
+ CreateServiceFunction(MS_OPT_OPENOPTIONS,OpenOptions);
+ CreateServiceFunction("Options/OptionsCommand",OpenOptionsDialog);
+ HookEvent(ME_SYSTEM_MODULESLOADED,OptModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownOptionsModule);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/plugins/newplugins.c b/miranda-wine/src/modules/plugins/newplugins.c new file mode 100644 index 0000000..3f4ee31 --- /dev/null +++ b/miranda-wine/src/modules/plugins/newplugins.c @@ -0,0 +1,815 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "../database/dblists.h"
+
+// block these plugins
+#define DEFMOD_REMOVED_UIPLUGINOPTS 21
+
+// basic export prototypes
+typedef int (__cdecl * Miranda_Plugin_Load) ( PLUGINLINK * );
+typedef int (__cdecl * Miranda_Plugin_Unload) ( void );
+// version control
+typedef PLUGININFO * (__cdecl * Miranda_Plugin_Info) ( DWORD mirandaVersion );
+// prototype for databases
+typedef DATABASELINK * (__cdecl * Database_Plugin_Info) ( void * reserved );
+// prototype for clists
+typedef int (__cdecl * CList_Initialise) ( PLUGINLINK * );
+// prototype for protocol plugins?
+
+typedef struct { // can all be NULL
+ HINSTANCE hInst;
+ Miranda_Plugin_Load Load;
+ Miranda_Plugin_Unload Unload;
+ Miranda_Plugin_Info Info;
+ Database_Plugin_Info DbInfo;
+ CList_Initialise clistlink;
+ PLUGININFO * pluginInfo; // must be freed if hInst==NULL then its a copy
+ DATABASELINK * dblink; // only valid during module being in memory
+} BASIC_PLUGIN_INFO;
+
+#define PCLASS_FAILED 0x1 // not a valid plugin, or API is invalid, pluginname is valid
+#define PCLASS_BASICAPI 0x2 // has Load, Unload, MirandaPluginInfo() -> PLUGININFO seems valid, this dll is in memory.
+#define PCLASS_DB 0x4 // has DatabasePluginInfo() and is valid as can be, and PCLASS_BASICAPI has to be set too
+#define PCLASS_LAST 0x8 // this plugin should be unloaded after everything else
+#define PCLASS_OK 0x10 // plugin should be loaded, if DB means nothing
+#define PCLASS_LOADED 0x20 // Load() has been called, Unload() should be called.
+#define PCLASS_STOPPED 0x40 // wasn't loaded cos plugin name not on white list
+#define PCLASS_CLIST 0x80 // a CList implementation
+
+typedef struct pluginEntry {
+ char pluginname[64];
+ unsigned int pclass; // PCLASS_*
+ BASIC_PLUGIN_INFO bpi;
+ struct pluginEntry * nextclass;
+} pluginEntry;
+
+SortedList pluginList = { 0 }, pluginListAddr = { 0 };
+
+PLUGINLINK pluginCoreLink;
+char mirandabootini[MAX_PATH];
+static DWORD mirandaVersion;
+static pluginEntry * pluginListDb;
+static pluginEntry * pluginListUI;
+static pluginEntry * pluginList_png2dib = NULL;
+static HANDLE hPluginListHeap = NULL;
+static pluginEntry * pluginDefModList[DEFMOD_HIGHEST+1]; // do not free this memory
+static int askAboutIgnoredPlugins;
+
+int InitIni(void);
+void UninitIni(void);
+
+#define PLUGINDISABLELIST "PluginDisable"
+
+void KillModuleEventHooks( HINSTANCE );
+void KillModuleServices( HINSTANCE );
+
+int LoadDatabaseModule(void);
+void ListView_SetItemTextA( HWND hwndLV, int i, int iSubItem, char* pszText );
+
+void ListView_GetItemTextA( HWND hwndLV, int i, int iSubItem, char* pszText, size_t cchTextMax )
+{
+ LV_ITEMA ms_lvi;
+ ms_lvi.iSubItem = iSubItem;
+ ms_lvi.cchTextMax = cchTextMax;
+ ms_lvi.pszText = pszText;
+ SendMessageA( hwndLV, LVM_GETITEMTEXTA, i, (LPARAM)&ms_lvi);
+}
+
+HINSTANCE GetInstByAddress( void* codePtr )
+{
+ int idx;
+ HINSTANCE result;
+ pluginEntry p; p.bpi.hInst = codePtr;
+
+ if ( pluginListAddr.realCount == 0 )
+ return NULL;
+
+ List_GetIndex( &pluginListAddr, &p, &idx );
+ if ( idx > 0 )
+ idx--;
+
+ result = (( pluginEntry* )( pluginListAddr.items[idx] ))->bpi.hInst;
+ if ( idx == 0 && codePtr < ( void* )result )
+ return NULL;
+
+ return result;
+}
+
+// returns true if the API exports were good, otherwise, passed in data is returned
+#define CHECKAPI_NONE 0
+#define CHECKAPI_DB 1
+#define CHECKAPI_CLIST 2
+static int checkAPI(char * plugin, BASIC_PLUGIN_INFO * bpi, DWORD mirandaVersion, int checkTypeAPI, int * exports)
+{
+ HINSTANCE h = NULL;
+ // this is evil but these plugins are buggy/old and people are blaming Miranda
+ {
+ char * p = strrchr(plugin,'\\');
+ if ( p != NULL && ++p ) {
+ if ( lstrcmpiA(p,"autoloadavatars.dll")==0 || lstrcmpiA(p,"multiwindow.dll")==0 ) return 0;
+ }
+ }
+ h = LoadLibraryA(plugin);
+ if ( h == NULL ) return 0;
+ // loaded, check for exports
+ bpi->Load = (Miranda_Plugin_Load) GetProcAddress(h, "Load");
+ bpi->Unload = (Miranda_Plugin_Unload) GetProcAddress(h, "Unload");
+ bpi->Info = (Miranda_Plugin_Info) GetProcAddress(h, "MirandaPluginInfo");
+ // if they were present
+ if ( bpi->Load && bpi->Unload && bpi->Info )
+ {
+ PLUGININFO * pi = bpi->Info(mirandaVersion);
+ if ( pi && pi->cbSize==sizeof(PLUGININFO) && pi->shortName && pi->description
+ && pi->author && pi->authorEmail && pi->copyright && pi->homepage
+ && pi->replacesDefaultModule <= DEFMOD_HIGHEST
+ && pi->replacesDefaultModule != DEFMOD_REMOVED_UIPLUGINOPTS)
+ {
+ bpi->pluginInfo = pi;
+ // basic API is present
+ if ( checkTypeAPI == CHECKAPI_NONE ) {
+ bpi->hInst=h;
+ return 1;
+ }
+ // check for DB?
+ if ( checkTypeAPI == CHECKAPI_DB ) {
+ bpi->DbInfo = (Database_Plugin_Info) GetProcAddress(h, "DatabasePluginInfo");
+ if ( bpi->DbInfo ) {
+ // fetch internal database function pointers
+ bpi->dblink = bpi->DbInfo(NULL);
+ // validate returned link structure
+ if ( bpi->dblink && bpi->dblink->cbSize==sizeof(DATABASELINK) ) {
+ bpi->hInst=h;
+ return 1;
+ }
+ // had DB exports
+ if ( exports != NULL ) *exports=1;
+ } //if
+ } //if
+
+ // check clist ?
+ if ( checkTypeAPI == CHECKAPI_CLIST ) {
+ bpi->clistlink = (CList_Initialise) GetProcAddress(h, "CListInitialise");
+ #if defined( _UNICODE )
+ if ( pi->isTransient == UNICODE_AWARE )
+ #endif
+ if ( bpi->clistlink ) {
+ // nothing more can be done here, this export is a load function
+ bpi->hInst=h;
+ if ( exports != NULL ) *exports=1;
+ return 1;
+ }
+ }
+ } // if
+ if ( exports != NULL ) *exports=1;
+ } //if
+ // not found, unload
+ FreeLibrary(h);
+ return 0;
+}
+
+// returns true if the given file is <anything>.dll exactly
+static int valid_library_name(char * name)
+{
+ char * dot = strrchr(name, '.');
+ if ( dot != NULL && lstrcmpiA(dot+1,"dll") == 0) {
+ if ( dot[4] == 0 ) return 1;
+ }
+ return 0;
+}
+
+// returns true if the given file matches dbx_*.dll, which is used to LoadLibrary()
+static int validguess_db_name(char * name)
+{
+ int rc=0;
+ // this is ONLY SAFE because name -> ffd.cFileName == MAX_PATH
+ char x = name[4];
+ name[4]=0;
+ rc=lstrcmpiA(name,"dbx_") == 0;
+ name[4]=x;
+ return rc;
+}
+
+// returns true if the given file matches clist_*.dll
+static int validguess_clist_name(char * name)
+{
+ int rc=0;
+ // argh evil
+ char x = name[6];
+ name[6]=0;
+ rc=lstrcmpiA(name,"clist_") == 0;
+ name[6]=x;
+ return rc;
+}
+
+// perform any API related tasks to freeing
+static void Plugin_Uninit(pluginEntry * p)
+{
+ // if it was an installed database plugin, call its unload
+ if ( p->pclass & PCLASS_DB )
+ p->bpi.dblink->Unload( p->pclass & PCLASS_OK );
+
+ // if the basic API check had passed, call Unload if Load() was ever called
+ if ( p->pclass & PCLASS_LOADED )
+ p->bpi.Unload();
+
+ // release the library
+ if ( p->bpi.hInst != NULL ) {
+ // we need to kill all resources which belong to that DLL before calling FreeLibrary
+ KillModuleEventHooks( p->bpi.hInst );
+ KillModuleServices( p->bpi.hInst );
+
+ FreeLibrary( p->bpi.hInst );
+ ZeroMemory( &p->bpi, sizeof( p->bpi ));
+ }
+ List_RemovePtr( &pluginList, p );
+ List_RemovePtr( &pluginListAddr, p );
+}
+
+typedef BOOL (*SCAN_PLUGINS_CALLBACK) ( WIN32_FIND_DATAA * fd, char * path, WPARAM wParam, LPARAM lParam );
+
+static void enumPlugins(SCAN_PLUGINS_CALLBACK cb, WPARAM wParam, LPARAM lParam)
+{
+ char exe[MAX_PATH];
+ char search[MAX_PATH];
+ char * p = 0;
+ // get miranda's exe path
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ // find the last \ and null it out, this leaves no trailing slash
+ p = strrchr(exe, '\\');
+ if ( p ) *p=0;
+ // create the search filter
+ mir_snprintf(search,SIZEOF(search),"%s\\Plugins\\*.dll", exe);
+ {
+ // FFFN will return filenames for things like dot dll+ or dot dllx
+ HANDLE hFind=INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+ hFind = FindFirstFileA(search, &ffd);
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ do {
+ if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && valid_library_name(ffd.cFileName) )
+ {
+ cb(&ffd,exe,wParam,lParam);
+ } //if
+ } while ( FindNextFileA(hFind, &ffd) );
+ FindClose(hFind);
+ } //if
+ }
+}
+
+// this is called by the db module to return all DBs plugins, then when it finds the one it likes the others are unloaded
+static int PluginsEnum(WPARAM wParam, LPARAM lParam)
+{
+ PLUGIN_DB_ENUM * de = (PLUGIN_DB_ENUM *) lParam;
+ pluginEntry * x = pluginListDb;
+ if ( de == NULL || de->cbSize != sizeof(PLUGIN_DB_ENUM) || de->pfnEnumCallback == NULL ) return 1;
+ while ( x != NULL ) {
+ int rc = de->pfnEnumCallback(x->pluginname, x->bpi.dblink, de->lParam);
+ if ( rc == DBPE_DONE ) {
+ // this db has been picked, get rid of all the others
+ pluginEntry * y = pluginListDb, * n;
+ while ( y != NULL ) {
+ n = y->nextclass;
+ if ( x != y )
+ Plugin_Uninit(y);
+ y = n;
+ } // while
+ x->pclass |= PCLASS_LOADED | PCLASS_OK | PCLASS_LAST;
+ return 0;
+ }
+ else if ( rc == DBPE_HALT ) return 1;
+ x = x->nextclass;
+ } // while
+ return pluginListDb != NULL ? 1 : -1;
+}
+
+static int PluginsGetDefaultArray(WPARAM wParam, LPARAM lParam)
+{
+ return (int) &pluginDefModList;
+}
+
+// called in the first pass to create pluginEntry* structures and validate database plugins
+static BOOL scanPluginsDir (WIN32_FIND_DATAA * fd, char * path, WPARAM wParam, LPARAM lParam )
+{
+ int isdb = validguess_db_name(fd->cFileName);
+ BASIC_PLUGIN_INFO bpi;
+ pluginEntry * p = HeapAlloc(hPluginListHeap, HEAP_NO_SERIALIZE|HEAP_ZERO_MEMORY, sizeof(pluginEntry));
+ strncpy(p->pluginname, fd->cFileName, SIZEOF(p->pluginname));
+ // plugin name suggests its a db module, load it right now
+ if ( isdb ) {
+ char buf[MAX_PATH];
+ mir_snprintf(buf,SIZEOF(buf),"%s\\Plugins\\%s", path, fd->cFileName);
+ if ( checkAPI(buf, &bpi, mirandaVersion, CHECKAPI_DB, NULL) ) {
+ // db plugin is valid
+ p->pclass |= (PCLASS_DB|PCLASS_BASICAPI);
+ // copy the dblink stuff
+ p->bpi=bpi;
+ // keep a faster list.
+ if ( pluginListDb != NULL ) p->nextclass=pluginListDb;
+ pluginListDb=p;
+ }
+ else {
+ // didn't have basic APIs or DB exports - failed.
+ p->pclass |= PCLASS_FAILED;
+ }
+ }
+ else if ( validguess_clist_name(fd->cFileName) ) {
+ // keep a note of this plugin for later
+ if ( pluginListUI != NULL ) p->nextclass=pluginListUI;
+ pluginListUI=p;
+ p->pclass |= PCLASS_CLIST;
+ }
+ else if ( lstrcmpiA(fd->cFileName, "png2dib.dll") == 0)
+ pluginList_png2dib = p;
+
+ // add it to the list
+ List_InsertPtr( &pluginList, p );
+ return TRUE;
+}
+
+static void SetPluginOnWhiteList(char * pluginname, int allow)
+{
+ DBWriteContactSettingByte(NULL, PLUGINDISABLELIST, pluginname, (BYTE)(allow ? 0 : 1));
+}
+
+// returns 1 if the plugin should be enabled within this profile, filename is always lower case
+static int isPluginOnWhiteList(char * pluginname)
+{
+ int rc = DBGetContactSettingByte(NULL, PLUGINDISABLELIST, pluginname, 0);
+ if ( rc != 0 && askAboutIgnoredPlugins ) {
+ char buf[256];
+ mir_snprintf(buf,SIZEOF(buf),Translate("'%s' is disabled, re-enable?"),pluginname);
+ if ( MessageBoxA(NULL,buf,Translate("Re-enable Miranda plugin?"),MB_YESNO|MB_ICONQUESTION) == IDYES ) {
+ SetPluginOnWhiteList(pluginname, 1);
+ return 1;
+ } }
+
+ return rc == 0;
+}
+
+static pluginEntry* getCListModule(char * exe, char * slice, int useWhiteList)
+{
+ pluginEntry * p = pluginListUI;
+ BASIC_PLUGIN_INFO bpi;
+ while ( p != NULL )
+ {
+ mir_snprintf(slice, &exe[MAX_PATH] - slice, "\\Plugins\\%s", p->pluginname);
+ CharLowerA(p->pluginname);
+ if ( useWhiteList ? isPluginOnWhiteList(p->pluginname) : 1 ) {
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_CLIST, NULL) ) {
+ p->bpi = bpi;
+ p->pclass |= PCLASS_LAST | PCLASS_OK | PCLASS_BASICAPI;
+ if ( bpi.clistlink(&pluginCoreLink) == 0 ) {
+ p->bpi=bpi;
+ p->pclass |= PCLASS_LOADED;
+ return p;
+ }
+ else Plugin_Uninit( p );
+ } //if
+ } //if
+ p = p->nextclass;
+ }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Event hook to unload all non-core plugins
+// hooked very late, after all the internal plugins, blah
+
+static int UnloadNewPlugins(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+
+ // unload everything but the special db/clist plugins
+ for ( i = pluginList.realCount-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList.items[i];
+ if ( !(p->pclass & PCLASS_LAST) && (p->pclass & PCLASS_OK))
+ Plugin_Uninit( p );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins options page dialog
+
+static BOOL dialogListPlugins(WIN32_FIND_DATAA * fd, char * path, WPARAM wParam, LPARAM lParam)
+{
+ LVITEMA it;
+ int iRow;
+ HWND hwndList=(HWND)lParam;
+ BASIC_PLUGIN_INFO pi;
+ int exports=0;
+ char buf[MAX_PATH];
+ int isdb = 0;
+ HINSTANCE gModule=NULL;
+ mir_snprintf(buf,SIZEOF(buf),"%s\\Plugins\\%s",path,fd->cFileName);
+ CharLowerA(fd->cFileName);
+ gModule=GetModuleHandleA(buf);
+ if ( checkAPI(buf, &pi, mirandaVersion, CHECKAPI_NONE, &exports) == 0 ) {
+ // failed to load anything, but if exports were good, show some info.
+ return TRUE;
+ }
+ isdb = pi.pluginInfo->replacesDefaultModule == DEFMOD_DB;
+ ZeroMemory(&it, sizeof(it));
+ it.mask=LVIF_TEXT | LVIF_PARAM;
+ it.pszText = Translate(fd->cFileName);
+ it.lParam=(LPARAM)pi.pluginInfo->replacesDefaultModule;
+ iRow=SendMessageA( hwndList, LVM_INSERTITEMA, 0, (LPARAM)&it );
+ if ( isPluginOnWhiteList(fd->cFileName) ) ListView_SetItemState(hwndList, iRow, !isdb ? 0x2000 : 0x3000, 0xF000);
+ if ( iRow != (-1) ) {
+ ListView_SetItemTextA(hwndList, iRow, 1, pi.pluginInfo->shortName);
+ mir_snprintf(buf,SIZEOF(buf),"%d.%d.%d.%d", HIBYTE(HIWORD(pi.pluginInfo->version)), LOBYTE(HIWORD(pi.pluginInfo->version)), HIBYTE(LOWORD(pi.pluginInfo->version)), LOBYTE(LOWORD(pi.pluginInfo->version)));
+ ListView_SetItemTextA(hwndList, iRow, 2, buf);
+ ListView_SetItemText(hwndList, iRow, 3, TranslateTS( gModule != NULL ? _T("Yes"):_T("No") ));
+ ListView_SetItemTextA(hwndList, iRow, 4, pi.pluginInfo->author);
+ ListView_SetItemTextA(hwndList, iRow, 5, pi.pluginInfo->authorEmail);
+ ListView_SetItemTextA(hwndList, iRow, 6, pi.pluginInfo->description);
+ ListView_SetItemTextA(hwndList, iRow, 7, pi.pluginInfo->copyright);
+ ListView_SetItemTextA(hwndList, iRow, 8, pi.pluginInfo->homepage);
+ }
+ FreeLibrary(pi.hInst);
+ return TRUE;
+}
+
+static LRESULT CALLBACK ListView_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC proc=(WNDPROC)GetWindowLong(hwnd,GWL_USERDATA);
+ if ( msg == WM_WINDOWPOSCHANGING ) ShowScrollBar(hwnd,SB_HORZ,FALSE);
+ return CallWindowProc(proc,hwnd,msg,wParam,lParam);
+}
+
+static TCHAR* PluginCutCopyright(TCHAR * buf)
+{
+ /* Some plugins include (C,c)opyright, which is fine but it looks stupid in the UI */
+ TCHAR tmp[16];
+ _tcsncpy(tmp, buf, 9);
+ tmp[9]=0;
+ if ( lstrcmpi( tmp, _T("copyright")) == 0 ) return buf+10;
+ return buf;
+}
+
+static BOOL CALLBACK DlgPluginOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ LVCOLUMN col;
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndList,GWL_USERDATA, SetWindowLong(hwndList,GWL_WNDPROC, (LONG)ListView_WndProc));
+ col.mask=LVCF_TEXT|LVCF_WIDTH;
+ col.pszText=TranslateT("Plugin");
+ col.cx=75;
+ ListView_InsertColumn(hwndList,0,&col);
+
+ col.pszText=TranslateT("Name");
+ ListView_InsertColumn(hwndList,1,&col);
+
+ col.pszText=TranslateT("Version");
+ col.cx=60;
+ ListView_InsertColumn(hwndList,2,&col);
+
+ col.pszText=TranslateT("Running");
+ col.cx=1000;
+ ListView_InsertColumn(hwndList,3,&col);
+
+ col.pszText=TranslateT("Author");
+ ListView_InsertColumn(hwndList,4,&col);
+
+ col.pszText=TranslateT("e-mail");
+ ListView_InsertColumn(hwndList,5,&col);
+
+ col.pszText=TranslateT("Description");
+ ListView_InsertColumn(hwndList,6,&col);
+
+ col.pszText=TranslateT("Copyright");
+ ListView_InsertColumn(hwndList,7,&col);
+
+ col.pszText=TranslateT("Homepage");
+ ListView_InsertColumn(hwndList,8,&col);
+
+ // XXX: Won't work on windows 95 without IE3+ or 4.70
+ ListView_SetExtendedListViewStyleEx(hwndList, 0, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT );
+ // scan the plugin dir for plugins, cos
+ enumPlugins(dialogListPlugins,(WPARAM)hwndDlg,(LPARAM)hwndList);
+ // sort out the headers
+ ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE); // dll name
+ ListView_SetColumnWidth(hwndList, 1, LVSCW_AUTOSIZE); // short name
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ {
+ NMLISTVIEW * hdr = (NMLISTVIEW *) lParam;
+ if ( hdr && hdr->hdr.code == LVN_ITEMCHANGED && hdr->uOldState != 0
+ && (hdr->uNewState == 0x1000 || hdr->uNewState == 0x2000 ) && IsWindowVisible(hdr->hdr.hwndFrom) ) {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ LVITEM it;
+ int iRow;
+ ZeroMemory(&it,sizeof(it));
+ it.mask=LVIF_PARAM | LVIF_STATE;
+ it.iItem = hdr->iItem;
+ if ( ListView_GetItem(hwndList,&it) && it.lParam == DEFMOD_DB ) {
+ ListView_SetItemState(hwndList, hdr->iItem, 0x3000, 0xF000);
+ return FALSE;
+ }
+ // if enabling and replaces, find all other replaces and toggle off
+ if ( hdr->uNewState&0x2000 && it.lParam ) {
+ for ( iRow=0; iRow != (-1); ) {
+ if ( iRow != hdr->iItem ) {
+ LVITEM dt;
+ dt.mask = LVIF_PARAM;
+ dt.iItem = iRow;
+ if ( ListView_GetItem(hwndList,&dt) && dt.lParam == it.lParam ) {
+ // the lParam is unset, so when the check is unset the clist block doesnt trigger
+ LPARAM lParam = dt.lParam;
+ dt.lParam = 0;
+ ListView_SetItem(hwndList, &dt);
+ ListView_SetItemState(hwndList, iRow, 0x1000, 0xF000);
+ dt.lParam = lParam;
+ ListView_SetItem(hwndList, &dt);
+ }
+ }
+ iRow=ListView_GetNextItem(hwndList, iRow, LVNI_ALL);
+ }
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), TRUE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ if ( hdr && hdr->hdr.code == LVN_ITEMCHANGED && IsWindowVisible(hdr->hdr.hwndFrom) && hdr->iItem != -1 ) {
+ TCHAR buf[1024];
+ int sel = hdr->uNewState&LVIS_SELECTED;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PLUGLIST);
+ // frame/about
+ ListView_GetItemText(hwndList, hdr->iItem, 1, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGININFOFRAME),sel ? buf : _T(""));
+ // author
+ ListView_GetItemText(hwndList, hdr->iItem, 4, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINAUTHOR), sel ? buf : _T(""));
+ // author email
+ ListView_GetItemText(hwndList, hdr->iItem, 5, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINEMAIL), sel ? buf : _T(""));
+ // description
+ ListView_GetItemText(hwndList, hdr->iItem, 6, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINLONGINFO), sel ? buf : _T(""));
+ // copyright
+ ListView_GetItemText(hwndList, hdr->iItem, 7, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINCPYR), sel ? PluginCutCopyright(buf) : _T(""));
+ // homepage
+ ListView_GetItemText(hwndList, hdr->iItem, 8, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINURL), sel ? buf : _T(""));
+ }
+ if ( hdr && hdr->hdr.code == PSN_APPLY ) {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ int iRow;
+ int iState;
+ char buf[1024];
+ for (iRow=0 ; iRow != (-1) ; ) {
+ ListView_GetItemTextA(hwndList, iRow, 0, buf, SIZEOF(buf));
+ iState=ListView_GetItemState(hwndList, iRow, LVIS_STATEIMAGEMASK);
+ SetPluginOnWhiteList(buf, iState&0x2000 ? 1 : 0);
+ iRow=ListView_GetNextItem(hwndList, iRow, LVNI_ALL);
+ } }
+ break;
+ }
+ case WM_COMMAND:
+ {
+ if ( HIWORD(wParam) == STN_CLICKED ) {
+ switch (LOWORD(wParam)) {
+ case IDC_PLUGINEMAIL:
+ case IDC_PLUGINURL:
+ {
+ char buf[512];
+ char * p = &buf[7];
+ lstrcpyA(buf,"mailto:");
+ if ( GetWindowTextA(GetDlgItem(hwndDlg, LOWORD(wParam)), p, SIZEOF(buf) - 7) ) {
+ CallService(MS_UTILS_OPENURL,0,(LPARAM) (LOWORD(wParam)==IDC_PLUGINEMAIL ? buf : p) );
+ }
+ break;
+ }
+ } // switch
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static int PluginOptionsInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pfnDlgProc = DlgPluginOpt;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_PLUGINS);
+ odp.position = 1300000000;
+ odp.pszTitle = "Plugins";
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Loads all plugins
+
+int LoadNewPluginsModule(void)
+{
+ char exe[MAX_PATH];
+ char* slice;
+ pluginEntry* p;
+ pluginEntry* clist = NULL;
+ int useWhiteList, i;
+
+ // make full path to the plugin
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ slice=strrchr(exe, '\\');
+ if ( slice != NULL )
+ *slice=0;
+
+ // remember some useful options
+ askAboutIgnoredPlugins=(UINT) GetPrivateProfileIntA( "PluginLoader", "AskAboutIgnoredPlugins", 0, mirandabootini);
+
+ // if png2dib is present, load it to provide the basic core functions
+ if ( pluginList_png2dib != NULL ) {
+ BASIC_PLUGIN_INFO bpi;
+ mir_snprintf(slice,&exe[SIZEOF(exe)] - slice, "\\Plugins\\%s", pluginList_png2dib->pluginname);
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_NONE, NULL) ) {
+ pluginList_png2dib->bpi = bpi;
+ pluginList_png2dib->pclass |= PCLASS_OK | PCLASS_BASICAPI;
+ if ( bpi.Load(&pluginCoreLink) == 0 )
+ pluginList_png2dib->pclass |= PCLASS_LOADED;
+ else
+ Plugin_Uninit( pluginList_png2dib );
+ } }
+
+ // first load the clist cos alot of plugins need that to be present at Load()
+ for ( useWhiteList = 1; useWhiteList >= 0 && clist == NULL; useWhiteList-- )
+ clist=getCListModule(exe, slice, useWhiteList);
+ /* the loop above will try and get one clist DLL to work, if all fail then just bail now */
+ if ( clist == NULL ) {
+ // result = 0, no clist_* can be found
+ if ( pluginListUI )
+ MessageBox(0, TranslateT("Unable to start any of the installed contact list plugins, I even ignored your preferences for which contact list couldn't load any."), _T(""), MB_OK | MB_ICONINFORMATION);
+ else
+ MessageBox(0, TranslateT("Can't find a contact list plugin! you need clist_classic or clist_mw.") , _T(""), MB_OK | MB_ICONINFORMATION);
+ return 1;
+ }
+
+ /* enable and disable as needed */
+ p=pluginListUI;
+ while ( p != NULL ) {
+ SetPluginOnWhiteList(p->pluginname, clist != p ? 0 : 1 );
+ p = p->nextclass;
+ }
+ /* now loop thru and load all the other plugins, do this in one pass */
+
+ for ( i=0; i < pluginList.realCount; i++ ) {
+ p = pluginList.items[i];
+ CharLowerA(p->pluginname);
+ if ( !(p->pclass&PCLASS_LOADED) && !(p->pclass&PCLASS_DB)
+ && !(p->pclass&PCLASS_CLIST) && isPluginOnWhiteList(p->pluginname) ) {
+ BASIC_PLUGIN_INFO bpi;
+ mir_snprintf(slice,&exe[SIZEOF(exe)] - slice, "\\Plugins\\%s", p->pluginname);
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_NONE, NULL) ) {
+ int rm = bpi.pluginInfo->replacesDefaultModule;
+ p->bpi = bpi;
+ p->pclass |= PCLASS_OK | PCLASS_BASICAPI;
+
+ List_InsertPtr( &pluginListAddr, p );
+
+ if ( pluginDefModList[rm] == NULL ) {
+ if ( bpi.Load(&pluginCoreLink) == 0 ) p->pclass |= PCLASS_LOADED;
+ else {
+ Plugin_Uninit( p );
+ i--;
+ }
+ if ( rm ) pluginDefModList[rm]=p;
+ } //if
+ else {
+ SetPluginOnWhiteList( p->pluginname, 0 );
+ Plugin_Uninit( p );
+ i--;
+ }
+ }
+ else p->pclass |= PCLASS_FAILED;
+ } }
+
+ // hook shutdown after everything
+ HookEvent(ME_SYSTEM_SHUTDOWN, UnloadNewPlugins);
+ HookEvent(ME_OPT_INITIALISE, PluginOptionsInit);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins module initialization
+// called before anything real is loaded, incl. database
+
+static int sttComparePlugins( pluginEntry* p1, pluginEntry* p2 )
+{ return ( int )( p1->bpi.hInst - p2->bpi.hInst );
+}
+
+static int sttComparePluginsByName( pluginEntry* p1, pluginEntry* p2 )
+{ return lstrcmpA( p1->pluginname, p2->pluginname );
+}
+
+int LoadNewPluginsModuleInfos(void)
+{
+ pluginList.increment = 10;
+ pluginList.sortFunc = sttComparePluginsByName;
+
+ pluginListAddr.increment = 10;
+ pluginListAddr.sortFunc = sttComparePlugins;
+
+ hPluginListHeap=HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
+ mirandaVersion = (DWORD)CallService(MS_SYSTEM_GETVERSION, 0, 0);
+ //
+ CreateServiceFunction(MS_PLUGINS_ENUMDBPLUGINS, PluginsEnum);
+ CreateServiceFunction(MS_PLUGINS_GETDISABLEDEFAULTARRAY, PluginsGetDefaultArray);
+ // make sure plugins can get internal core APIs
+ pluginCoreLink.CallService=CallService;
+ pluginCoreLink.ServiceExists=ServiceExists;
+ pluginCoreLink.CreateServiceFunction=CreateServiceFunction;
+ pluginCoreLink.CreateTransientServiceFunction=CreateServiceFunction;
+ pluginCoreLink.DestroyServiceFunction=DestroyServiceFunction;
+ pluginCoreLink.CreateHookableEvent=CreateHookableEvent;
+ pluginCoreLink.DestroyHookableEvent=DestroyHookableEvent;
+ pluginCoreLink.HookEvent=HookEvent;
+ pluginCoreLink.HookEventMessage=HookEventMessage;
+ pluginCoreLink.UnhookEvent=UnhookEvent;
+ pluginCoreLink.NotifyEventHooks=NotifyEventHooks;
+ pluginCoreLink.SetHookDefaultForHookableEvent=SetHookDefaultForHookableEvent;
+ pluginCoreLink.CallServiceSync=CallServiceSync;
+ pluginCoreLink.CallFunctionAsync=CallFunctionAsync;
+ // remember where the mirandaboot.ini goes
+ {
+ char exe[MAX_PATH];
+ char * slice;
+ GetModuleFileNameA(NULL, exe, SIZEOF(exe));
+ slice=strrchr(exe, '\\');
+ if ( slice != NULL ) *slice=0;
+ mir_snprintf(mirandabootini, SIZEOF(mirandabootini), "%s\\mirandaboot.ini", exe);
+ }
+ // look for all *.dll's
+ enumPlugins(scanPluginsDir, 0, 0);
+ // the database will select which db plugin to use, or fail if no profile is selected
+ if (LoadDatabaseModule()) return 1;
+ InitIni();
+ // could validate the plugin entries here but internal modules arent loaded so can't call Load() in one pass
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins module unloading
+// called at the end of module chain unloading, just modular engine left at this point
+
+int UnloadNewPluginsModule(void)
+{
+ int i;
+
+ // unload everything but the DB
+ for ( i = pluginList.realCount-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList.items[i];
+ if ( !(p->pclass & PCLASS_DB) )
+ Plugin_Uninit( p );
+ }
+
+ // unload the DB
+ for ( i = pluginList.realCount-1; i >= 0; i-- ) {
+ pluginEntry * p = pluginList.items[i];
+ Plugin_Uninit( p );
+ }
+
+ if ( hPluginListHeap ) HeapDestroy(hPluginListHeap);
+ hPluginListHeap=0;
+
+ List_Destroy( &pluginList );
+ List_Destroy( &pluginListAddr );
+ UninitIni();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/protocols/protochains.c b/miranda-wine/src/modules/protocols/protochains.c new file mode 100644 index 0000000..e36d95d --- /dev/null +++ b/miranda-wine/src/modules/protocols/protochains.c @@ -0,0 +1,225 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <m_protomod.h>
+
+int Proto_IsProtocolLoaded(WPARAM wParam,LPARAM lParam);
+
+//Protocol chain is list of integers "0".."n", with network protocol named "p"
+static int Proto_CallContactService(WPARAM wParam,LPARAM lParam)
+//note that this is ChainSend() too, due to a quirk of function definitions
+{
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ int i;
+ char str[10];
+ DBVARIANT dbv;
+ int ret;
+
+ if(wParam==(WPARAM)(-1)) return 1;
+ for(i=wParam;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) break;
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,i+1,lParam))!=CALLSERVICE_NOTFOUND) {
+ //chain was started, exit
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ }
+ if(DBGetContactSetting(ccs->hContact,"Protocol","p",&dbv)) return 1;
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,(WPARAM)(-1),lParam))!=CALLSERVICE_NOTFOUND) {
+ //chain was started, exit
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ return 1;
+}
+
+static int CallRecvChain(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ int i,ret;
+ char str[10];
+ DBVARIANT dbv;
+
+ if(wParam==(WPARAM)(-1)) return 1; //shouldn't happen - sanity check
+ if(wParam==0) { //begin processing by finding end of chain
+ for(;;wParam++) {
+ _itoa(wParam,str,10);
+ if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) break;
+ mir_free(dbv.pszVal);
+ }
+ }
+ else wParam--;
+ for(i=wParam-1;i>=0;i--) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting(ccs->hContact,"_Filter",str,&dbv)) return 1; //never happens
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,i+1,lParam))!=CALLSERVICE_NOTFOUND) {
+ //chain was started, exit
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ }
+ //end of chain, call network protocol again
+ if(DBGetContactSetting(ccs->hContact,"Protocol","p",&dbv)) return 1;
+ if((ret=CallProtoService(dbv.pszVal,ccs->szProtoService,(WPARAM)(-1),lParam))!=CALLSERVICE_NOTFOUND) {
+ mir_free(dbv.pszVal);
+ return ret;
+ }
+ mir_free(dbv.pszVal);
+ return 1;
+}
+
+static int Proto_ChainRecv(WPARAM wParam,LPARAM lParam)
+{
+ /* this will switch threads just like before */
+ return CallServiceSync(MS_PROTO_CHAINRECV "ThreadSafe",wParam,lParam);
+}
+
+#if 1
+static int Proto_GetContactBaseProto(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv;
+ PROTOCOLDESCRIPTOR *pd;
+ DBCONTACTGETSETTING dbcgs;
+ char name[32];
+
+ dbv.type=DBVT_ASCIIZ;
+ dbv.pszVal=name;
+ dbv.cchVal=SIZEOF(name);
+ dbcgs.pValue=&dbv;
+ dbcgs.szModule="Protocol";
+ dbcgs.szSetting="p";
+ if(CallService(MS_DB_CONTACT_GETSETTINGSTATIC,wParam,(LPARAM)&dbcgs)) return (int)(char*)NULL;
+ pd=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,(LPARAM)dbv.pszVal);
+ if(pd==NULL) return (int)(char*)NULL;
+ return (int)pd->szName;
+}
+#endif
+
+static int Proto_IsProtoOnContact(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ char str[10];
+ DBVARIANT dbv;
+
+ if(!DBGetContactSetting((HANDLE)wParam,"Protocol","p",&dbv)) {
+ if(!strcmp((char*)lParam,dbv.pszVal)) {
+ mir_free(dbv.pszVal);
+ return -1;
+ }
+ mir_free(dbv.pszVal);
+ }
+ for(i=0;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) break;
+ if(!strcmp((char*)lParam,dbv.pszVal)) {
+ mir_free(dbv.pszVal);
+ return i+1;
+ }
+ mir_free(dbv.pszVal);
+ }
+ return 0;
+}
+
+static int Proto_AddToContact(WPARAM wParam,LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR *pd,*pdCompare;
+
+ pd=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,lParam);
+ if(pd==NULL) return 1;
+ if ( pd->type == PROTOTYPE_PROTOCOL ) {
+ DBWriteContactSettingString((HANDLE)wParam,"Protocol","p",(char*)lParam);
+ return 0;
+ }
+ if(Proto_IsProtoOnContact(wParam,lParam)) return 1;
+ { /* v:0.3.3 + PROTO FILTERS ARE NOW KEPT IN THEIR OWN DB MODULE! */
+ int i;
+ char str[10],*lastProto;
+ DBVARIANT dbv;
+
+ for(i=0;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) break;
+ pdCompare=(PROTOCOLDESCRIPTOR*)Proto_IsProtocolLoaded(0,(LPARAM)dbv.pszVal);
+ mir_free(dbv.pszVal);
+ if(pdCompare==NULL) continue;
+ if(pd->type > pdCompare->type) break;
+ }
+ //put the new module at position i
+ lastProto=mir_strdup((char*)lParam);
+ for(;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) {
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,lastProto);
+ mir_free(lastProto);
+ break;
+ }
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,lastProto);
+ mir_free(lastProto);
+ lastProto=dbv.pszVal;
+ }
+ }
+ return 0;
+}
+
+static int Proto_RemoveFromContact(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ DBVARIANT dbv;
+ char str[10];
+
+ i=Proto_IsProtoOnContact(wParam,lParam);
+ if(!i) return 1;
+ if(i==-1)
+ DBDeleteContactSetting((HANDLE)wParam,"Protocol","p");
+ else {
+ for(i--;;i++) { //we have to decrease i, as Proto_IsOnContact returns +1 more number than read from database
+ _itoa(i+1,str,10);
+ if(0!=DBGetContactSetting((HANDLE)wParam,"_Filter",str,&dbv)) {
+ _itoa(i,str,10);
+ DBDeleteContactSetting((HANDLE)wParam,"_Filter",str);
+ break;
+ }
+ _itoa(i,str,10);
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ }
+ return 0;
+}
+
+int LoadProtoChains(void)
+{
+ CreateServiceFunction(MS_PROTO_CALLCONTACTSERVICE,Proto_CallContactService);
+ CreateServiceFunction(MS_PROTO_CHAINSEND,Proto_CallContactService);
+ CreateServiceFunction(MS_PROTO_CHAINRECV,Proto_ChainRecv);
+ CreateServiceFunction(MS_PROTO_CHAINRECV "ThreadSafe",CallRecvChain);
+ CreateServiceFunction(MS_PROTO_GETCONTACTBASEPROTO,Proto_GetContactBaseProto);
+ CreateServiceFunction(MS_PROTO_ISPROTOONCONTACT,Proto_IsProtoOnContact);
+ CreateServiceFunction(MS_PROTO_ADDTOCONTACT,Proto_AddToContact);
+ CreateServiceFunction(MS_PROTO_REMOVEFROMCONTACT,Proto_RemoveFromContact);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/protocols/protocols.c b/miranda-wine/src/modules/protocols/protocols.c new file mode 100644 index 0000000..88b5513 --- /dev/null +++ b/miranda-wine/src/modules/protocols/protocols.c @@ -0,0 +1,134 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+int LoadProtoChains(void);
+
+static HANDLE hAckEvent,hTypeEvent;
+static int protocolModuleCount;
+static PROTOCOLDESCRIPTOR *protocolModule;
+static PROTOCOLDESCRIPTOR **pProtocolModules;
+
+void InitContactDir(void);
+void UninitContactDir(void);
+
+static int Proto_BroadcastAck(WPARAM wParam,LPARAM lParam)
+{
+ return NotifyEventHooks(hAckEvent,wParam,lParam);
+}
+
+int Proto_IsProtocolLoaded(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<protocolModuleCount;i++)
+ if(!strcmp(protocolModule[i].szName,(char*)lParam)) return (int)&protocolModule[i];
+ return (int)(PROTOCOLDESCRIPTOR*)NULL;
+}
+
+static int Proto_EnumProtocols(WPARAM wParam,LPARAM lParam)
+{
+ *(int*)wParam=protocolModuleCount;
+ *(PROTOCOLDESCRIPTOR***)lParam=pProtocolModules;
+ return 0;
+}
+
+static int Proto_RegisterModule(WPARAM wParam,LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR *pd=(PROTOCOLDESCRIPTOR*)lParam;
+ int i;
+
+ if(pd->cbSize!=sizeof(PROTOCOLDESCRIPTOR)) return 1;
+ protocolModule=(PROTOCOLDESCRIPTOR*)mir_realloc(protocolModule,sizeof(PROTOCOLDESCRIPTOR)*(protocolModuleCount+1));
+ protocolModule[protocolModuleCount]=*pd;
+ protocolModule[protocolModuleCount++].szName=mir_strdup(pd->szName);
+ pProtocolModules=(PROTOCOLDESCRIPTOR**)mir_realloc(pProtocolModules,sizeof(PROTOCOLDESCRIPTOR*)*(protocolModuleCount+1));
+ for(i=0;i<protocolModuleCount;i++)
+ pProtocolModules[i]=&protocolModule[i];
+ return 0;
+}
+
+static int Proto_ValidTypingContact(HANDLE hContact, char *szProto) {
+ DWORD protoCaps;
+
+ if (!hContact || !szProto) return 0;
+ protoCaps=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (!(protoCaps&PF4_SUPPORTTYPING)) return 0;
+ return 1;
+}
+
+static int Proto_SelfIsTyping(WPARAM wParam,LPARAM lParam)
+{
+ int type = (int)lParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if (type!=PROTOTYPE_SELFTYPING_OFF && type!=PROTOTYPE_SELFTYPING_ON) return 0;
+
+ if (!szProto) return 0;
+ if (Proto_ValidTypingContact((HANDLE)wParam, szProto)) {
+ CallProtoService(szProto, PSS_USERISTYPING, wParam, lParam);
+ }
+ return 0;
+}
+
+static int Proto_ContactIsTyping(WPARAM wParam,LPARAM lParam)
+{
+ int type = (int)lParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+
+ if (!szProto) return 0;
+ if (type<PROTOTYPE_CONTACTTYPING_OFF) return 0;
+ if (Proto_ValidTypingContact((HANDLE)wParam, szProto))
+ NotifyEventHooks(hTypeEvent, wParam, lParam);
+ return 0;
+}
+
+static int ProtoShutdown(WPARAM wParam,LPARAM lParam)
+{
+ if (hAckEvent) DestroyHookableEvent(hAckEvent);
+ hAckEvent=NULL;
+ if(protocolModule!=NULL) {
+ int i;
+ for(i=0;i<protocolModuleCount;i++)
+ mir_free(protocolModule[i].szName);
+ mir_free(protocolModule);
+ }
+ if(pProtocolModules!=NULL) mir_free(pProtocolModules);
+ protocolModuleCount=0;
+ UninitContactDir();
+ return 0;
+}
+
+int LoadProtocolsModule(void)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,ProtoShutdown);
+ if(LoadProtoChains()) return 1;
+ hAckEvent=CreateHookableEvent(ME_PROTO_ACK);
+ hTypeEvent=CreateHookableEvent(ME_PROTO_CONTACTISTYPING);
+ CreateServiceFunction(MS_PROTO_BROADCASTACK,Proto_BroadcastAck);
+ CreateServiceFunction(MS_PROTO_ISPROTOCOLLOADED,Proto_IsProtocolLoaded);
+ CreateServiceFunction(MS_PROTO_ENUMPROTOCOLS,Proto_EnumProtocols);
+ CreateServiceFunction(MS_PROTO_REGISTERMODULE,Proto_RegisterModule);
+ CreateServiceFunction(MS_PROTO_SELFISTYPING,Proto_SelfIsTyping);
+ CreateServiceFunction(MS_PROTO_CONTACTISTYPING,Proto_ContactIsTyping);
+ InitContactDir();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/protocols/protodir.c b/miranda-wine/src/modules/protocols/protodir.c new file mode 100644 index 0000000..7a11026 --- /dev/null +++ b/miranda-wine/src/modules/protocols/protodir.c @@ -0,0 +1,248 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#if 0
+
+extern HANDLE hCacheHeap;
+
+/*
+
+ the id cache has id/proto against hContact to lookup ID's fast to resolve to hContact,
+ the protoBaseCache has hContact's sorted, so can lookup hContact->proto fast, these two caches
+ share the same data, they're indexes, each entry might not have an "id" set.
+
+ There is a small cache which maintains a protocol list
+
+*/
+
+/*
+
+ The information we need to cache is not readily available, data has to be gathered at startup
+ when a new contact is created/deleted, when a new proto registers and so on.
+
+ The information we get at startup includes walking the contact chain and reading Protocol/p which
+ will give us the protocol the contact is on, all this info is stored in contactEntry's within
+ protoCache ONLY - contactCache is EMPTY at this point.
+
+ We can not fetch the id of the contact because this information is only in SOME protocol plugins,
+ this is a problem but we'll hook all proto registrations and ask each proto if it supports the
+ returning this ID name, if not - it won't even use our id <-> contact look so no biggie!
+
+*/
+
+typedef struct {
+ char * proto; // within proto cache
+ char * id; // optional
+ HANDLE hContact;
+} contactEntry;
+
+typedef struct {
+ CRITICAL_SECTION csLock;
+ SortedList contactCache; // index for id/proto -> hContact
+ SortedList protoCache; // index for hContact -> proto/id
+ SortedList protoNameCache; // index of protocol names
+} contactDir;
+
+static contactDir condir;
+
+// compare's id/proto and return's hContact's
+int contactCacheCompare(void * a, void * b)
+{
+ contactEntry * x = (contactEntry *) a;
+ contactEntry * y = (contactEntry *) b;
+ int rc=0;
+ // same protocol?
+ rc = strcmp(x->proto, y->proto);
+ if ( rc == 0 ) {
+ // same id? id's might be missing
+ if ( x->id && y->id ) rc = strcmp(x->id, y->id);
+ }
+ return rc;
+}
+
+// compares hContact's and returns associated data
+int protoCacheCompare(void * a, void * b)
+{
+ contactEntry * x = (contactEntry *) a;
+ contactEntry * y = (contactEntry *) b;
+ if ( x->hContact < y->hContact ) return -1;
+ if ( x->hContact > y->hContact ) return 1;
+ return 0;
+}
+
+// keeps a list of protocol names
+int protoNameCacheCompare(void * a, void * b)
+{
+ return strcmp( (char *)a, (char*)b );
+}
+
+// cache the protocol string so that its not allocated per contact but shared
+char * contactDir_Proto_Add(contactDir * cd, char * proto)
+{
+ int index = 0 ;
+ char * szCache = 0;
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoNameCache, proto, &index) ) szCache = cd->protoNameCache.items[index];
+ else {
+ szCache = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, strlen(proto)+1);
+ strcpy(szCache, proto);
+ List_Insert(&cd->protoNameCache, szCache, index);
+ }
+ LeaveCriticalSection(&cd->csLock);
+ return szCache;
+}
+
+// thread safe
+char * contactDir_Proto_Get(contactDir * cd, HANDLE hContact)
+{
+ char * szCache = 0;
+ int index = 0;
+ contactEntry e;
+ e.hContact=hContact;
+ e.proto="";
+ e.id="";
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoCache, &e, &index) ) {
+ contactEntry * p = cd->protoCache.items[index];
+ szCache = p->proto;
+ }
+ LeaveCriticalSection(&cd->csLock);
+ return szCache;
+}
+
+// thread tolerant, if updating id dont pass proto, if updating proto dont pass id
+void contactDir_Contact_Add(contactDir * cd, HANDLE hContact, char * proto, char * id)
+{
+ // if a contact is gonna exist anywhere it's going to be in the ->protoCache which has a key of hContact
+ // if id is not null then the contact should be indexed via the ->contactCache instead
+ if ( id == NULL ) {
+ int index = 0;
+ contactEntry e;
+ e.hContact=hContact;
+ e.proto = proto;
+ e.id = "";
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoCache, &e, &index) ) {
+ contactEntry * p = cd->protoCache.items[index];
+ // this hContact is in the cache, protcol changing?
+ p->proto = contactDir_Proto_Add(cd, proto); // just replace the old pointer
+ } else {
+ contactEntry * p = 0;
+ // this hContact isn't in the cache, add it
+ p = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, sizeof(contactEntry));
+ p->proto = contactDir_Proto_Add(cd, proto);
+ p->id = 0;
+ p->hContact = hContact;
+ // add it
+ List_Insert(&cd->protoCache, p, index);
+ }
+ LeaveCriticalSection(&cd->csLock);
+ } else {
+ // this contact HAS to be in ->protoCache since it was added during startup
+ // need to find the contactEntry* that should already exist for it
+ } //if
+}
+
+// only expected to be called at startup.
+void contactDir_Proto_Walk(contactDir * cd)
+{
+ HANDLE hContact;
+ char buf[128];
+ DBCONTACTGETSETTING gsProto;
+ DBVARIANT dbvProto;
+ // setup the read structure
+ gsProto.szModule="Protocol";
+ gsProto.szSetting="p";
+ gsProto.pValue = &dbvProto;
+ // this might not work
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while ( hContact ) {
+ // and how we'll get the reset
+ dbvProto.type=DBVT_ASCIIZ;
+ dbvProto.pszVal = (char *) &buf;
+ dbvProto.cchVal = SIZEOF(buf);
+ // figure out what hContact/Protocol/p is
+ if ( CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)hContact, (LPARAM)&gsProto) == 0 ) {
+ contactDir_Contact_Add(cd, hContact, buf, NULL);
+ }
+ // find next
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+// ctor/dtor
+
+void contactDir_Init(contactDir * cd)
+{
+ InitializeCriticalSection(&cd->csLock);
+ cd->contactCache.increment=50;
+ cd->contactCache.sortFunc=contactCacheCompare;
+ cd->protoCache.increment=50;
+ cd->protoCache.sortFunc=protoCacheCompare;
+ cd->protoNameCache.increment=5;
+ cd->protoNameCache.sortFunc=protoNameCacheCompare;
+ // build a list of all hContact's and what proto's they are on
+ contactDir_Proto_Walk(cd);
+}
+
+void contactDir_Deinit(contactDir * cd)
+{
+ List_Destroy(&cd->contactCache);
+ List_Destroy(&cd->protoCache);
+ List_Destroy(&cd->protoNameCache);
+ DeleteCriticalSection(&cd->csLock);
+}
+
+static int contactDirGetProto(WPARAM wParam, LPARAM lParam)
+{
+ return (int) contactDir_Proto_Get(&condir,(HANDLE)wParam);
+}
+
+#endif
+
+void InitContactDir(void)
+{
+ return;
+ //contactDir_Init(&condir);
+ //CreateServiceFunction(MS_PROTODIR_PROTOFROMCONTACT, contactDirGetProto);
+}
+
+
+void UninitContactDir(void)
+{
+ return;
+#if 0
+ {
+ int j;
+ for ( j = 0; j< condir.protoCache.realCount; j++) {
+ char buf[128];
+ contactEntry * p = condir.protoCache.items[j];
+ mir_snprintf(buf,SIZEOF(buf)," [%s] %s @ %x \n", p->proto, p->id ? p->id : "", p->hContact);
+ OutputDebugString(buf);
+ }
+ }
+ contactDir_Deinit(&condir);
+#endif
+}
diff --git a/miranda-wine/src/modules/skin/skin.c b/miranda-wine/src/modules/skin/skin.c new file mode 100644 index 0000000..5fea4ca --- /dev/null +++ b/miranda-wine/src/modules/skin/skin.c @@ -0,0 +1,77 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+int InitSkinIcons(void);
+void UninitSkinIcons(void);
+int InitSkinSounds(void);
+void UninitSkinSounds(void);
+BOOL CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DlgProcIconsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static int SkinSystemShutdown(WPARAM wParam,LPARAM lParam)
+{
+ UninitSkinSounds();
+ UninitSkinIcons();
+ return 0;
+}
+
+static UINT iconsExpertOnlyControls[]={IDC_IMPORT};
+static int SkinOptionsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -200000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SOUND);
+ odp.pszGroup = "Events";
+ odp.pszTitle = "Sounds";
+ odp.pfnDlgProc = DlgProcSoundOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.position = -180000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICONS);
+ odp.pszTitle = "Icons";
+ odp.pszGroup = "Contact List";
+ odp.pfnDlgProc = DlgProcIconsOpts;
+ odp.expertOnlyControls = iconsExpertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( iconsExpertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int SkinSystemModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ HookEvent(ME_OPT_INITIALISE,SkinOptionsInit);
+ return 0;
+}
+
+int LoadSkinModule(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,SkinSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_SHUTDOWN,SkinSystemShutdown);
+ if(InitSkinIcons()) return 1;
+ if(InitSkinSounds()) return 1;
+ return 0;
+}
diff --git a/miranda-wine/src/modules/skin/skinicons.c b/miranda-wine/src/modules/skin/skinicons.c new file mode 100644 index 0000000..706f585 --- /dev/null +++ b/miranda-wine/src/modules/skin/skinicons.c @@ -0,0 +1,1044 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <io.h>
+
+/***********W*A*R*N*I*N*G*************
+
+ This is quite possibly the worst
+ code that has ever been written.
+
+************W*A*R*N*I*N*G************/
+
+BOOL CALLBACK DlgProcIconIndex(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HINSTANCE hMiranda;
+static HANDLE hIconsChangedEvent;
+static HICON ImportIcon(const char *szProto,int n);
+
+struct IconPreview {
+ int id;
+ char* description;
+ int main;
+};
+
+struct IconPreview static mainIcons[] =
+{
+ { SKINICON_OTHER_MIRANDA, "Miranda IM", 1 },
+ { SKINICON_EVENT_MESSAGE, "Message", 1 },
+ { SKINICON_EVENT_URL, "URL", 1 },
+ { SKINICON_EVENT_FILE, "File", 1 },
+ { SKINICON_OTHER_USERONLINE, "User Online", 1 },
+ { SKINICON_OTHER_GROUPOPEN, "Group (Open)", 1 },
+ { SKINICON_OTHER_GROUPSHUT, "Group (Closed)", 1 },
+};
+static int skinIconStatusToIdStatus[]={ID_STATUS_OFFLINE,ID_STATUS_ONLINE,ID_STATUS_AWAY,ID_STATUS_NA,ID_STATUS_OCCUPIED,ID_STATUS_DND,ID_STATUS_FREECHAT,ID_STATUS_INVISIBLE,ID_STATUS_ONTHEPHONE,ID_STATUS_OUTTOLUNCH};
+static int skinIconStatusToPf2[]={0xFFFFFFFF,PF2_ONLINE,PF2_SHORTAWAY,PF2_LONGAWAY,PF2_LIGHTDND,PF2_HEAVYDND,PF2_FREECHAT,PF2_INVISIBLE,PF2_ONTHEPHONE,PF2_OUTTOLUNCH};
+static UINT skinIconStatusToResourceId[]={IDI_OFFLINE,IDI_ONLINE,IDI_AWAY,IDI_NA,IDI_OCCUPIED,IDI_DND,IDI_FREE4CHAT,IDI_INVISIBLE,IDI_ONTHEPHONE,IDI_OUTTOLUNCH};
+static UINT eventIconToResourceId[]={IDI_RECVMSG,IDI_URL,IDI_FILE};
+static UINT otherIconToResourceId[]={IDI_MIRANDA,IDI_MIRANDA,IDI_MIRANDA,IDI_GROUPOPEN,IDI_USERONLINE,IDI_GROUPSHUT};
+
+struct ProtoIcons {
+ char *szProto;
+ HICON hIcons[ SIZEOF(skinIconStatusToIdStatus) ];
+} static *protoIcons;
+static int protoIconsCount;
+static HICON hEventIcons[3],hOtherIcons[6];
+static HICON hStatusIcons[ SIZEOF(skinIconStatusToIdStatus) ];
+
+static int IdStatusToSkinIconStatus(int idStatus)
+{
+ int i;
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ )
+ if(skinIconStatusToIdStatus[i]==idStatus) return i;
+ return SKINICON_STATUS_OFFLINE;
+}
+
+static int LoadSkinProtoIcon(WPARAM wParam,LPARAM lParam)
+{
+ char *szProto=(char*)wParam;
+ int i;
+ if (!szProto) {
+ // Only return a protocol specific icon if there is only one protocol
+ // Otherwise return the builtin hStatusIcons icon. This affects the global status menu mainly.
+ PROTOCOLDESCRIPTOR **proto;
+ DWORD protoCount,j;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&proto);
+ if (protoIconsCount==1) {
+ HICON hIcon=protoIcons[0].hIcons[IdStatusToSkinIconStatus(lParam)];
+ if (hIcon) {
+ if (protoCount) {
+ for (j=0;j<protoCount;j++) {
+ if (proto[j]->type!=PROTOTYPE_PROTOCOL) continue;
+ if (!_strcmpi(proto[j]->szName,protoIcons[0].szProto)) return (int)hIcon;
+ } //for
+ } else {
+ return (int)hIcon;
+ } //if
+ } //if
+ } // if
+ return (int)hStatusIcons[IdStatusToSkinIconStatus(lParam)];
+ } //if
+
+ for(i=0;i<protoIconsCount;i++)
+ if(!strcmp(szProto,protoIcons[i].szProto))
+ return (int)protoIcons[i].hIcons[IdStatusToSkinIconStatus(lParam)];
+ {
+ int j;
+ protoIcons=(struct ProtoIcons*)mir_realloc(protoIcons,sizeof(struct ProtoIcons)*(protoIconsCount+1));
+ protoIcons[protoIconsCount].szProto=mir_strdup(szProto);
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ )
+ {
+ protoIcons[protoIconsCount].hIcons[j]=ImportIcon(szProto,j);
+ }//for
+ protoIconsCount++;
+ }
+ return (int)protoIcons[protoIconsCount-1].hIcons[IdStatusToSkinIconStatus(lParam)];
+}
+
+static int LoadSkinIcon(WPARAM wParam,LPARAM lParam)
+{
+ if(wParam<SKINICON_EVENT_MESSAGE) {
+ if(wParam>=SIZEOF(skinIconStatusToIdStatus)) return (int)(HICON)NULL;
+ return LoadSkinProtoIcon((WPARAM)(char*)NULL,skinIconStatusToIdStatus[wParam]);
+ }
+ if(wParam<SKINICON_OTHER_MIRANDA) {
+ if(wParam-SKINICON_EVENT_MESSAGE>=SIZEOF(hEventIcons)) return (int)(HICON)NULL;
+ return (int)hEventIcons[wParam-SKINICON_EVENT_MESSAGE];
+ }
+ if(wParam-SKINICON_OTHER_MIRANDA>=SIZEOF(hOtherIcons)) return (int)(HICON)NULL;
+ return (int)hOtherIcons[wParam-SKINICON_OTHER_MIRANDA];
+}
+
+static HICON ExtractIconFromPath(const char *path)
+{
+ char *comma;
+ char file[MAX_PATH],fileFull[MAX_PATH];
+ int n;
+ HICON hIcon;
+
+ if (path == NULL) return (HICON)NULL;
+
+ lstrcpynA(file,path,SIZEOF(file));
+ comma=strrchr(file,',');
+ if(comma==NULL) n=0;
+ else {n=atoi(comma+1); *comma=0;}
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)file, (LPARAM)fileFull);
+ hIcon=NULL;
+ ExtractIconExA(fileFull,n,NULL,&hIcon,1);
+ return hIcon;
+}
+
+static HICON ImportIcon(const char *szProto,int n)
+{
+ DBVARIANT dbv;
+ char szSetting[64];
+ HICON hIcon;
+
+ if(szProto==NULL && n<SKINICON_EVENT_MESSAGE) {
+ /* return 'all protocol status icon' */
+ int i;
+ for(i=0;;i++) {
+ szSetting[0]='p';
+ _itoa(i,szSetting+1,10);
+ if(DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) break;
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",dbv.pszVal,skinIconStatusToIdStatus[n]);
+ DBFreeVariant(&dbv);
+ if(!DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) {
+ hIcon=ExtractIconFromPath(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if (hIcon)
+ return hIcon;
+ } //if
+ } //for
+ return hStatusIcons[n];
+ }//if
+
+ /* if there is a protocol, build <protocol><ID> to get a path, otherwise
+ use the index 'n' directly. */
+ if (szProto) {
+ //
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",szProto,skinIconStatusToIdStatus[n]);
+ } else {
+ _itoa(n,szSetting,10);
+ } //if
+
+ if(!DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) {
+ hIcon=ExtractIconFromPath(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if(hIcon!=NULL)
+ return hIcon;
+ }
+ if (szProto) {
+ char szPath[MAX_PATH], szFullPath[MAX_PATH],*str;
+ HICON hIcon;
+
+ GetModuleFileNameA(GetModuleHandle(NULL), szPath, MAX_PATH);
+ str=strrchr(szPath,'\\');
+ if(str!=NULL) *str=0;
+ mir_snprintf(szFullPath, SIZEOF(szFullPath), "%s\\Icons\\proto_%s.dll,%d", szPath, szProto, -(int)skinIconStatusToResourceId[n]);
+ hIcon=ExtractIconFromPath(szFullPath);
+ if (hIcon) return hIcon;
+ /* looking for a protocol icon and it wasn't found, use internal */
+ return hStatusIcons[n];
+ }
+ return LoadIcon(hMiranda,MAKEINTRESOURCE(n<SKINICON_OTHER_MIRANDA?eventIconToResourceId[n-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[n-SKINICON_OTHER_MIRANDA]));
+}
+
+static void LoadAllIcons(void)
+{
+ DBVARIANT dbv;
+ int i,j,z;
+ char szSetting[128];
+
+ for( i=0; i < SIZEOF(hEventIcons); i++ )
+ hEventIcons[i]=ImportIcon(NULL,i+SKINICON_EVENT_MESSAGE);
+ for( i=0; i < SIZEOF(hOtherIcons); i++ )
+ hOtherIcons[i]=ImportIcon(NULL,i+SKINICON_OTHER_MIRANDA);
+ ZeroMemory(hStatusIcons,sizeof(hStatusIcons));
+ for( i=0; i < SIZEOF(hStatusIcons); i++ )
+ {
+ _itoa(skinIconStatusToIdStatus[i], szSetting, 10);
+ hStatusIcons[i] = NULL;
+ if(!DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) {
+ hStatusIcons[i] = ExtractIconFromPath(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ if (!hStatusIcons[i]) hStatusIcons[i]=LoadIcon(hMiranda,MAKEINTRESOURCE(skinIconStatusToResourceId[i]));
+ }
+ protoIcons=NULL;
+ protoIconsCount=0;
+ for(i=0;;i++) {
+ z = 0;
+ szSetting[0]='p';
+ _itoa(i,szSetting+1,10);
+ if(DBGetContactSetting(NULL,"Icons",szSetting,&dbv)) break;
+ for(j=0;j<protoIconsCount;j++) {
+ if (!strcmp(dbv.pszVal,protoIcons[j].szProto)) z = 1;
+ }
+ if (!z) {
+ protoIcons=(struct ProtoIcons*)mir_realloc(protoIcons,sizeof(struct ProtoIcons)*(protoIconsCount+1));
+ protoIcons[protoIconsCount].szProto=dbv.pszVal;
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ )
+ {
+ protoIcons[protoIconsCount].hIcons[j]=ImportIcon(dbv.pszVal,j);
+ }//for
+ protoIconsCount++;
+ }
+ if (z) DBFreeVariant(&dbv); /* the proto was found, free the string */
+ }//for
+}
+
+void FreeAllIcons(void)
+{
+ int i,j;
+ for( i=0; i < SIZEOF(hOtherIcons); i++ ) DestroyIcon(hOtherIcons[i]);
+ for( i=0; i < SIZEOF(hEventIcons); i++ ) DestroyIcon(hEventIcons[i]);
+ for( i=0; i < protoIconsCount;i++) {
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ if(hStatusIcons[i]==protoIcons[i].hIcons[j]) continue;
+ DestroyIcon(protoIcons[i].hIcons[j]);
+ }
+ mir_free(protoIcons[i].szProto);
+ }
+ mir_free(protoIcons);
+ for( i=0; i < SIZEOF(hStatusIcons); i++ )
+ DestroyIcon(hStatusIcons[i]);
+}
+
+int InitSkinIcons(void)
+{
+ hMiranda=GetModuleHandle(NULL);
+ LoadAllIcons();
+ CreateServiceFunction(MS_SKIN_LOADICON,LoadSkinIcon);
+ CreateServiceFunction(MS_SKIN_LOADPROTOICON,LoadSkinProtoIcon);
+ hIconsChangedEvent=CreateHookableEvent(ME_SKIN_ICONSCHANGED);
+ return 0;
+}
+
+void UninitSkinIcons(void)
+{
+ FreeAllIcons();
+}
+
+struct ProtoIconsData {
+ PROTOCOLDESCRIPTOR *proto;
+ char **iconPath;
+};
+struct IconsOptsData {
+ struct ProtoIconsData *protoIcons;
+ int protoCount;
+ char **mainIconPath;
+ char **mainStatusPath;
+ HWND hwndIndex;
+ int originalGroupWidth;
+ int shortGroupWidth;
+ int groupHeight;
+};
+#define DM_REBUILDICONSPREVIEW (WM_USER+10)
+#define DM_CHANGEICON (WM_USER+11)
+#define DM_CHANGESPECIFICICON (WM_USER+12)
+BOOL CALLBACK DlgProcIconsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct IconsOptsData *dat;
+
+ dat=(struct IconsOptsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { PROTOCOLDESCRIPTOR *proto,**protoList;
+ int protoCount,i,j;
+ char szSetting[64];
+ DBVARIANT dbv;
+
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct IconsOptsData*)mir_alloc(sizeof(struct IconsOptsData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->mainIconPath=(char**)mir_alloc(sizeof(char*) * SIZEOF(mainIcons));
+ dat->mainStatusPath=(char**)mir_alloc(sizeof(char*) * SIZEOF(skinIconStatusToIdStatus));
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ _itoa(mainIcons[i].id,szSetting,10);
+ if ( DBGetContactSetting( NULL, "Icons", szSetting, &dbv ))
+ dat->mainIconPath[i]=NULL;
+ else
+ dat->mainIconPath[i]=dbv.pszVal;
+ }
+
+ for ( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ _itoa(skinIconStatusToIdStatus[i],szSetting,10);
+ if ( DBGetContactSetting( NULL, "Icons", szSetting, &dbv ))
+ dat->mainStatusPath[i]=NULL;
+ else
+ dat->mainStatusPath[i]=dbv.pszVal;
+ }
+
+ ListView_SetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR32|ILC_MASK,0,30),LVSIL_NORMAL);
+ ListView_SetIconSpacing(GetDlgItem(hwndDlg,IDC_PREVIEW),56,67);
+ i=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_ADDSTRING,0,(LPARAM)TranslateT("Main Icons"));
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETITEMDATA,i,0);
+ i=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_ADDSTRING,0,(LPARAM)TranslateT("Global Status Icons"));
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETITEMDATA,i,0);
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protoList);
+ for ( i=0; i < protoCount; i++ ) {
+ TCHAR str[128];
+ char protoName[96];
+ if(protoList[i]->type!=PROTOTYPE_PROTOCOL || CallProtoService(protoList[i]->szName,PS_GETCAPS,PFLAGNUM_2,0)==0) continue;
+ CallProtoService(protoList[i]->szName,PS_GETNAME,SIZEOF(protoName),(LPARAM)protoName);
+ { TCHAR* ptszProtoName = LangPackPcharToTchar( protoName );
+ mir_sntprintf( str, SIZEOF(str), TranslateT("%s Icons"), ptszProtoName );
+ mir_free( ptszProtoName );
+ }
+ j = SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_ADDSTRING,0,(LPARAM)str );
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETITEMDATA,j,(LPARAM)protoList[i]);
+ }
+ dat->protoCount=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCOUNT,0,0)-2;
+ dat->protoIcons=(struct ProtoIconsData*)mir_alloc(sizeof(struct ProtoIconsData)*dat->protoCount);
+ for(i=0;i<dat->protoCount;i++) {
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,i+2,0);
+ dat->protoIcons[i].proto=proto;
+ dat->protoIcons[i].iconPath=(char**)mir_alloc(sizeof(char*) * SIZEOF(skinIconStatusToIdStatus));
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",proto->szName,skinIconStatusToIdStatus[j]);
+ if(DBGetContactSetting(NULL,"Icons",szSetting,&dbv))
+ dat->protoIcons[i].iconPath[j]=NULL;
+ else
+ dat->protoIcons[i].iconPath[j]=dbv.pszVal;
+ } }
+
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_SETCURSEL,0,0);
+ { RECT rc,rcReorder;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_STSIMPLERIGHT),&rcReorder);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_STICONSGROUP),&rc);
+ dat->originalGroupWidth=rc.right-rc.left;
+ dat->shortGroupWidth=rcReorder.right-rc.left;
+ dat->groupHeight=rc.bottom-rc.top;
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ return TRUE;
+ }
+ case DM_REBUILDICONSPREVIEW:
+ { LVITEM lvi;
+ HIMAGELIST hIml;
+ PROTOCOLDESCRIPTOR *proto;
+ HICON hIcon;
+
+ SetCursor(LoadCursor(NULL,IDC_WAIT));
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PREVIEW));
+ hIml=ListView_GetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),LVSIL_NORMAL);
+ ImageList_RemoveAll(hIml);
+
+ lvi.mask=LVIF_TEXT|LVIF_IMAGE;
+ lvi.iSubItem=0;
+ if(proto==NULL) {
+ if (SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ for ( lvi.iItem=0; lvi.iItem < SIZEOF(mainIcons); lvi.iItem++ ) {
+ lvi.pszText = LangPackPcharToTchar( mainIcons[lvi.iItem].description );
+ hIcon = ExtractIconFromPath( dat->mainIconPath[lvi.iItem] );
+ if(hIcon==NULL) hIcon=LoadIcon(hMiranda,MAKEINTRESOURCE(mainIcons[lvi.iItem].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[lvi.iItem].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[lvi.iItem].id-SKINICON_OTHER_MIRANDA]));
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ ListView_InsertItem( GetDlgItem(hwndDlg,IDC_PREVIEW), &lvi );
+ mir_free( lvi.pszText );
+ }
+ }
+ else {
+ for( lvi.iItem=0; lvi.iItem < SIZEOF(skinIconStatusToIdStatus); lvi.iItem++ ) {
+ lvi.pszText = LangPackPcharToTchar(( LPCSTR )CallService( MS_CLIST_GETSTATUSMODEDESCRIPTION, skinIconStatusToIdStatus[lvi.iItem], 0 ));
+ hIcon=ExtractIconFromPath(dat->mainStatusPath[lvi.iItem]);
+ if(hIcon==NULL) hIcon=LoadIcon(hMiranda,MAKEINTRESOURCE(skinIconStatusToResourceId[lvi.iItem]));
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ ListView_InsertItem( GetDlgItem(hwndDlg,IDC_PREVIEW), &lvi );
+ mir_free( lvi.pszText );
+ } }
+ }
+ else {
+ int i;
+ DWORD caps2=CallProtoService(proto->szName,PS_GETCAPS,PFLAGNUM_2,0);
+ lvi.mask|=LVIF_PARAM;
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ for(lvi.iItem=0; lvi.iItem < SIZEOF(skinIconStatusToIdStatus); lvi.iItem++) {
+ if(!(caps2&skinIconStatusToPf2[lvi.iItem])) continue;
+ lvi.pszText = LangPackPcharToTchar(( LPCSTR )CallService( MS_CLIST_GETSTATUSMODEDESCRIPTION, skinIconStatusToIdStatus[lvi.iItem], 0 ));
+ lvi.lParam = lvi.iItem;
+ hIcon = ExtractIconFromPath(dat->protoIcons[i].iconPath[lvi.iItem]);
+ if(hIcon==NULL) {
+ char szPath[MAX_PATH], szFullPath[MAX_PATH],*str;
+
+ GetModuleFileNameA(GetModuleHandle(NULL), szPath, MAX_PATH);
+ str=strrchr(szPath,'\\');
+ if(str!=NULL) *str=0;
+ mir_snprintf(szFullPath, SIZEOF(szFullPath), "%s\\Icons\\proto_%s.dll,%d", szPath, dat->protoIcons[i].proto->szName, -(int)skinIconStatusToResourceId[lvi.iItem]);
+ hIcon=ExtractIconFromPath(szFullPath);
+ }
+ if(hIcon==NULL) hIcon=ExtractIconFromPath(dat->mainStatusPath[lvi.iItem]);
+ if(hIcon==NULL) hIcon=LoadIcon(hMiranda,MAKEINTRESOURCE(skinIconStatusToResourceId[lvi.iItem]));
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ ListView_InsertItem( GetDlgItem(hwndDlg,IDC_PREVIEW), &lvi );
+ } }
+
+ SetCursor(LoadCursor(NULL,IDC_ARROW));
+ break;
+ }
+ case DM_CHANGEICON:
+ { char *path=(char*)lParam;
+ PROTOCOLDESCRIPTOR *proto;
+
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ if(proto==NULL) {
+ if (SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ if(dat->mainIconPath[wParam]!=NULL) mir_free(dat->mainIconPath[wParam]);
+ dat->mainIconPath[wParam]=mir_strdup(path);
+ }
+ else {
+ if(dat->mainStatusPath[wParam]!=NULL) mir_free(dat->mainStatusPath[wParam]);
+ dat->mainStatusPath[wParam]=mir_strdup(path);
+ }
+ }
+ else {
+ LVITEM lvi;
+ int i;
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=wParam;
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvi);
+ if(dat->protoIcons[i].iconPath[lvi.lParam]!=NULL) mir_free(dat->protoIcons[i].iconPath[lvi.lParam]);
+ dat->protoIcons[i].iconPath[lvi.lParam]=mir_strdup(path);
+ }
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case DM_CHANGESPECIFICICON:
+ { struct IconPreview *ico=(struct IconPreview*)lParam;
+ PROTOCOLDESCRIPTOR *proto=(PROTOCOLDESCRIPTOR*)wParam;
+ int i;
+
+ if(proto==NULL) {
+ if (ico->main) {
+ for( i=0; i < SIZEOF(mainIcons); i++ )
+ if(mainIcons[i].id==ico->id) break;
+ if( i < SIZEOF(mainIcons)) {
+ if(dat->mainIconPath[i]!=NULL) mir_free(dat->mainIconPath[i]);
+ dat->mainIconPath[i]=mir_strdup(ico->description);
+ }
+ }
+ else {
+ for( i=0; i < SIZEOF(skinIconStatusToResourceId); i++ )
+ if(i==ico->id) break;
+ if( i < SIZEOF(skinIconStatusToIdStatus)) {
+ if(dat->mainStatusPath[i]!=NULL) mir_free(dat->mainStatusPath[i]);
+ dat->mainStatusPath[i]=mir_strdup(ico->description);
+ }
+ }
+ }
+ else {
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ if(dat->protoIcons[i].iconPath[ico->id]!=NULL) mir_free(dat->protoIcons[i].iconPath[ico->id]);
+ dat->protoIcons[i].iconPath[ico->id]=mir_strdup(ico->description);
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam)==IDC_IMPORT) {
+ dat->hwndIndex=CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ICONINDEX),GetParent(hwndDlg),DlgProcIconIndex,(LPARAM)hwndDlg);
+ EnableWindow((HWND)lParam,FALSE);
+ }
+ else if(LOWORD(wParam)==IDC_LOADICONS) {
+ char filetmp[MAX_PATH],filename[MAX_PATH];
+ OPENFILENAMEA ofn={0};
+ char filter[512],*pfilter;
+
+ filetmp[0]=0;
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.hInstance = NULL;
+ strcpy(filter,Translate("Icon Sets"));
+ strcat(filter," (*.dll)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*.DLL");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,Translate("All Files"));
+ strcat(pfilter," (*)");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = filetmp;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(filename);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "dll";
+ if(GetOpenFileNameA(&ofn)) {
+ char path[MAX_PATH];
+ int i;
+ struct IconPreview ico;
+ HICON hIcon;
+
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)filetmp, (LPARAM)filename);
+ ico.description=path;
+ if(SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ if(hIcon==NULL) continue;
+ ico.id=mainIcons[i].id;
+ ico.main=1;
+ wsprintfA(path,"%s,%d",filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ SendMessage(hwndDlg,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR*)NULL,(LPARAM)&ico);
+ }
+ }
+ else if(SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==1) {
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndDlg,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR**)NULL,(LPARAM)&ico);
+ }
+ }
+ else {
+ PROTOCOLDESCRIPTOR *proto;
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndDlg,DM_CHANGESPECIFICICON,(WPARAM)proto,(LPARAM)&ico);
+ }
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ else if(LOWORD(wParam)==IDC_GETMORE) {
+ char szVer[64],szUrl[256];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szVer),(LPARAM)szVer);
+ while(strchr(szVer,' ')) *strchr(szVer,' ')='_';
+ wsprintfA(szUrl,"http://addons.miranda-im.org/",szVer);
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szUrl);
+ break;
+ }
+ else if(wParam==MAKEWPARAM(IDC_CATEGORYLIST,CBN_SELCHANGE)) {
+ if(dat->protoCount>1)
+ {
+ SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0);
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { LVHITTESTINFO lvhti;
+ GetCursorPos(&lvhti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvhti.pt);
+ if(ListView_HitTest(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvhti)!=-1) {
+ HMENU hMenu;
+ POINT pt;
+ int cmd;
+ GetCursorPos(&pt);
+ hMenu=GetSubMenu(LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CONTEXT)),3);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hMenu,0);
+ cmd=TrackPopupMenu(hMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ switch(cmd) {
+ case ID_RESET:
+ {
+ PROTOCOLDESCRIPTOR *proto;
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0),0);
+ if(proto==NULL) {
+ if(SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCURSEL,0,0)==0) {
+ if(dat->mainIconPath[lvhti.iItem]!=NULL) {
+ mir_free(dat->mainIconPath[lvhti.iItem]);
+ dat->mainIconPath[lvhti.iItem]=NULL;
+ }
+ }
+ else {
+ if(dat->mainStatusPath[lvhti.iItem]!=NULL) {
+ mir_free(dat->mainStatusPath[lvhti.iItem]);
+ dat->mainStatusPath[lvhti.iItem]=NULL;
+ }
+ }
+ }
+ else {
+ LVITEM lvi;
+ int i;
+ for(i=0;i<dat->protoCount;i++)
+ if(proto==dat->protoIcons[i].proto) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=lvhti.iItem;
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvi);
+ if(dat->protoIcons[i].iconPath[lvi.lParam]!=NULL) {
+ mir_free(dat->protoIcons[i].iconPath[lvi.lParam]);
+ dat->protoIcons[i].iconPath[lvi.lParam]=NULL;
+ }
+ }
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ return TRUE;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ { int i,j;
+ char szSetting[64];
+ DWORD flags;
+ PROTOCOLDESCRIPTOR *proto;
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ _itoa(mainIcons[i].id,szSetting,10);
+ if(dat->mainIconPath[i]==NULL)
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ else
+ DBWriteContactSettingString(NULL,"Icons",szSetting,dat->mainIconPath[i]);
+ }
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ _itoa(skinIconStatusToIdStatus[i],szSetting,10);
+ if(dat->mainStatusPath[i]==NULL)
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ else
+ DBWriteContactSettingString(NULL,"Icons",szSetting,dat->mainStatusPath[i]);
+ }
+ for(i=0;i<dat->protoCount;i++) {
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ flags=(DWORD)CallProtoService(dat->protoIcons[i].proto->szName,PS_GETCAPS,PFLAGNUM_2,0);
+ mir_snprintf(szSetting,SIZEOF(szSetting),"%s%d",dat->protoIcons[i].proto->szName,skinIconStatusToIdStatus[j]);
+ if(dat->protoIcons[i].iconPath[j]==NULL || !(flags&skinIconStatusToPf2[j]))
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ else
+ DBWriteContactSettingString(NULL,"Icons",szSetting,dat->protoIcons[i].iconPath[j]);
+ }
+ }
+ szSetting[0]='p';
+ i=SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETCOUNT,0,0)-1;
+ _itoa(i,szSetting+1,10);
+ DBDeleteContactSetting(NULL,"Icons",szSetting);
+ for(;i>=2;i--) {
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_CATEGORYLIST,LB_GETITEMDATA,i,0);
+ _itoa(i-2,szSetting+1,10);
+ DBWriteContactSettingString(NULL,"Icons",szSetting,proto->szName);
+ }
+ FreeAllIcons();
+ LoadAllIcons();
+ NotifyEventHooks(hIconsChangedEvent,0,0);
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int i,j;
+ DestroyWindow(dat->hwndIndex);
+ for( i=0; i < SIZEOF(mainIcons); i++ )
+ if(dat->mainIconPath[i]!=NULL) mir_free(dat->mainIconPath[i]);
+ mir_free(dat->mainIconPath);
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ )
+ if(dat->mainStatusPath[i]!=NULL) mir_free(dat->mainStatusPath[i]);
+ mir_free(dat->mainStatusPath);
+ for(i=0;i<dat->protoCount;i++) {
+ for( j=0; j < SIZEOF(skinIconStatusToIdStatus); j++ ) {
+ if(dat->protoIcons[i].iconPath[j]!=NULL) mir_free(dat->protoIcons[i].iconPath[j]);
+ }
+ mir_free(dat->protoIcons[i].iconPath);
+ }
+ mir_free(dat->protoIcons);
+ mir_free(dat);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static int IconExists(const char *filename,int id)
+{
+ HICON hIcon;
+ hIcon=ExtractIconA(hMiranda,filename,-id);
+ if(hIcon==NULL) return 0;
+ if((int)hIcon==1) return 0;
+ DestroyIcon(hIcon);
+ return 1;
+}
+
+static UINT mirandaIconSetIds[]={IDI_RECVMSG,IDI_URL,IDI_ONLINE,IDI_OFFLINE,IDI_AWAY,IDI_NA};
+static int IsMirandaIconSet(const char *filename)
+{
+ int i;
+ if(_access(filename,0)!=0) return 0;
+ for( i=0; i < SIZEOF(mirandaIconSetIds); i++ )
+ if(!IconExists(filename,mirandaIconSetIds[i])) return 0;
+ return 1;
+}
+
+BOOL CALLBACK DlgProcIconIndex(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndParent,hwndDragOver;
+ static int dragging;
+ static int dragItem,dropHiLite;
+ static int originalPreviewHeight;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ hwndParent=(HWND)lParam;
+ dragging=dragItem=0;
+ TranslateDialogDefault(hwndDlg);
+ ListView_SetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR32|ILC_MASK,0,100),LVSIL_NORMAL);
+ ListView_SetIconSpacing(GetDlgItem(hwndDlg,IDC_PREVIEW),56,67);
+ { RECT rcThis,rcParent;
+ GetWindowRect(hwndDlg,&rcThis);
+ GetWindowRect(hwndParent,&rcParent);
+ OffsetRect(&rcThis,rcParent.right-rcThis.left,0);
+ OffsetRect(&rcThis,0,rcParent.top-rcThis.top);
+ GetWindowRect(GetParent(hwndParent),&rcParent);
+ if(rcThis.right>GetSystemMetrics(SM_CXSCREEN)) {
+ OffsetRect(&rcParent,GetSystemMetrics(SM_CXSCREEN)-rcThis.right,0);
+ OffsetRect(&rcThis,GetSystemMetrics(SM_CXSCREEN)-rcThis.right,0);
+ MoveWindow(GetParent(hwndParent),rcParent.left,rcParent.top,rcParent.right-rcParent.left,rcParent.bottom-rcParent.top,TRUE);
+ }
+ MoveWindow(hwndDlg,rcThis.left,rcThis.top,rcThis.right-rcThis.left,rcThis.bottom-rcThis.top,FALSE);
+ }
+ { RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_PREVIEW),&rc);
+ originalPreviewHeight=rc.bottom-rc.top;
+ }
+ { int i,item;
+ TCHAR text[128];
+ LPARAM lData;
+ for ( i = SendDlgItemMessage(hwndParent,IDC_CATEGORYLIST,LB_GETCOUNT,0,0)-1; i >= 2; i-- ) {
+ SendDlgItemMessage(hwndParent,IDC_CATEGORYLIST,LB_GETTEXT,i,(LPARAM)text);
+ lData=SendDlgItemMessage(hwndParent,IDC_CATEGORYLIST,LB_GETITEMDATA,i,0);
+ item = SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_ADDSTRING,0,(LPARAM)text);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETITEMDATA,item,lData);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETCURSEL,0,0);
+ }
+ { HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
+ MySHAutoComplete=(HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+ if(MySHAutoComplete) MySHAutoComplete(GetDlgItem(hwndDlg,IDC_ICONSET),1);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_ICONSET,"icons.dll");
+ return TRUE;
+ case DM_REBUILDICONSPREVIEW:
+ { LVITEMA lvi;
+ char filename[MAX_PATH],caption[64];
+ HIMAGELIST hIml;
+ int count,isMiranda,i;
+ HICON hIcon;
+
+ SetCursor(LoadCursor(NULL,IDC_WAIT));
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PREVIEW));
+ hIml=ListView_GetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),LVSIL_NORMAL);
+ ImageList_RemoveAll(hIml);
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,filename,SIZEOF(filename));
+
+ isMiranda=IsMirandaIconSet(filename);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_IMPORTMULTI),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TOMAIN),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TODEFICON),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TOPROTO),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_PROTOLIST),isMiranda);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_IMPORT),isMiranda);
+ { RECT rcPreview,rcGroup;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_PREVIEW),&rcPreview);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_IMPORTMULTI),&rcGroup);
+ SetWindowPos(GetDlgItem(hwndDlg,IDC_PREVIEW),0,0,0,rcPreview.right-rcPreview.left,isMiranda?originalPreviewHeight:rcGroup.bottom-rcPreview.top,SWP_NOZORDER|SWP_NOMOVE);
+ }
+
+ if(_access(filename,0)!=0) {
+ SetCursor(LoadCursor(NULL,IDC_ARROW));
+ break;
+ }
+
+ lvi.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ if(isMiranda) {
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ if(hIcon==NULL) continue;
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ DestroyIcon(hIcon);
+ lvi.pszText=Translate(mainIcons[lvi.iItem].description);
+ lvi.lParam=-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]);
+ SendMessageA( GetDlgItem(hwndDlg,IDC_PREVIEW), LVM_INSERTITEMA, 0, (LPARAM)&lvi );
+ lvi.iItem++;
+ }
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ DestroyIcon(hIcon);
+ lvi.pszText=(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,skinIconStatusToIdStatus[i],0);
+ lvi.lParam=-(int)skinIconStatusToResourceId[i];
+ SendMessageA( GetDlgItem(hwndDlg,IDC_PREVIEW), LVM_INSERTITEMA, 0, (LPARAM)&lvi );
+ lvi.iItem++;
+ }
+ }
+ count=(int)ExtractIconA(GetModuleHandle(NULL),filename,-1);
+ for(i=0;i<count;lvi.iItem++,i++) {
+ wsprintfA(caption,"%d",i+1);
+ lvi.pszText=caption;
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,i);
+ lvi.iImage=ImageList_AddIcon(hIml,hIcon);
+ DestroyIcon(hIcon);
+ lvi.lParam=i;
+ SendMessageA( GetDlgItem(hwndDlg,IDC_PREVIEW), LVM_INSERTITEMA, 0, (LPARAM)&lvi );
+ }
+ SetCursor(LoadCursor(NULL,IDC_ARROW));
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_BROWSE:
+ { char str[MAX_PATH];
+ OPENFILENAMEA ofn;
+ char filter[512],*pfilter;
+
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,str,SIZEOF(str));
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = GetParent(hwndDlg);
+ ofn.hInstance = NULL;
+ strcpy(filter,Translate("Icon Sets"));
+ strcat(filter," (*.dll;*.icl;*.exe;*.ico)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*.DLL;*.ICL;*.EXE;*.ICO");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,Translate("All Files"));
+ strcat(pfilter," (*)");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "dll";
+ if(!GetOpenFileNameA(&ofn)) break;
+ SetDlgItemTextA(hwndDlg,IDC_ICONSET,str);
+ break;
+ }
+ case IDC_GETMORE:
+ { char szVer[64],szUrl[256];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szVer),(LPARAM)szVer);
+ while(strchr(szVer,' ')) *strchr(szVer,' ')='_';
+ wsprintfA(szUrl,"http://www.miranda-im.org/download/index.php",szVer);
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szUrl);
+ break;
+ }
+ case IDC_ICONSET:
+ if(HIWORD(wParam)==EN_CHANGE)
+ SendMessage(hwndDlg,DM_REBUILDICONSPREVIEW,0,0);
+ break;
+ case IDC_TOMAIN:
+ case IDC_TODEFICON:
+ case IDC_TOPROTO:
+ EnableWindow(GetDlgItem(hwndDlg,IDC_IMPORT),IsDlgButtonChecked(hwndDlg,IDC_TOMAIN) || IsDlgButtonChecked(hwndDlg,IDC_TODEFICON) || IsDlgButtonChecked(hwndDlg,IDC_TOPROTO));
+ break;
+ case IDC_IMPORT:
+ { char filetmp[MAX_PATH],filename[MAX_PATH],path[MAX_PATH];
+ int i;
+ struct IconPreview ico;
+ HICON hIcon;
+
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,filetmp,SIZEOF(filetmp));
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)filetmp, (LPARAM)filename);
+ ico.description=path;
+ if(IsDlgButtonChecked(hwndDlg,IDC_TOMAIN)) {
+ for( i=0; i < SIZEOF(mainIcons); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ if(hIcon==NULL) continue;
+ ico.id=mainIcons[i].id;
+ ico.main=1;
+ wsprintfA(path,"%s,%d",filename,-(int)(mainIcons[i].id<SKINICON_OTHER_MIRANDA?eventIconToResourceId[mainIcons[i].id-SKINICON_EVENT_MESSAGE]:otherIconToResourceId[mainIcons[i].id-SKINICON_OTHER_MIRANDA]));
+ SendMessage(hwndParent,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR*)NULL,(LPARAM)&ico);
+ }
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_TODEFICON)) {
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndParent,DM_CHANGESPECIFICICON,(WPARAM)(PROTOCOLDESCRIPTOR**)NULL,(LPARAM)&ico);
+ }
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_TOPROTO)) {
+ PROTOCOLDESCRIPTOR *proto;
+ proto=(PROTOCOLDESCRIPTOR*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ for( i=0; i < SIZEOF(skinIconStatusToIdStatus); i++ ) {
+ hIcon=ExtractIconA(GetModuleHandle(NULL),filename,-(int)skinIconStatusToResourceId[i]);
+ if(hIcon==NULL) continue;
+ ico.id=i;
+ ico.main=0;
+ wsprintfA(path,"%s,%d",filename,-(int)skinIconStatusToResourceId[i]);
+ SendMessage(hwndParent,DM_CHANGESPECIFICICON,(WPARAM)proto,(LPARAM)&ico);
+ }
+ }
+ SendMessage(hwndParent,DM_REBUILDICONSPREVIEW,0,0);
+ break;
+ }
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if(dragging) {
+ LVHITTESTINFO lvhti;
+ int onItem=0;
+ HWND hwndOver;
+ RECT rc;
+ POINT ptDrag;
+
+ lvhti.pt.x=(short)LOWORD(lParam); lvhti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&lvhti.pt);
+ hwndOver=WindowFromPoint(lvhti.pt);
+ GetWindowRect(hwndOver,&rc);
+ ptDrag.x=lvhti.pt.x-rc.left; ptDrag.y=lvhti.pt.y-rc.top;
+ if(hwndOver!=hwndDragOver) {
+ ImageList_DragLeave(hwndDragOver);
+ hwndDragOver=hwndOver;
+ ImageList_DragEnter(hwndDragOver,ptDrag.x,ptDrag.y);
+ }
+ ImageList_DragMove(ptDrag.x,ptDrag.y);
+ if(hwndOver==GetDlgItem(hwndParent,IDC_PREVIEW)) {
+ ScreenToClient(GetDlgItem(hwndParent,IDC_PREVIEW),&lvhti.pt);
+ if(ListView_HitTest(GetDlgItem(hwndParent,IDC_PREVIEW),&lvhti)!=-1) {
+ if(lvhti.iItem!=dropHiLite) {
+ ImageList_DragLeave(hwndDragOver);
+ if(dropHiLite!=-1) ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,0,LVIS_DROPHILITED);
+ dropHiLite=lvhti.iItem;
+ ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,LVIS_DROPHILITED,LVIS_DROPHILITED);
+ UpdateWindow(GetDlgItem(hwndParent,IDC_PREVIEW));
+ ImageList_DragEnter(hwndDragOver,ptDrag.x,ptDrag.y);
+ }
+ onItem=1;
+ }
+ }
+ if(!onItem && dropHiLite!=-1) {
+ ImageList_DragLeave(hwndDragOver);
+ ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,0,LVIS_DROPHILITED);
+ UpdateWindow(GetDlgItem(hwndParent,IDC_PREVIEW));
+ ImageList_DragEnter(hwndDragOver,ptDrag.x,ptDrag.y);
+ dropHiLite=-1;
+ }
+ SetCursor(LoadCursor(NULL,onItem?IDC_ARROW:IDC_NO));
+ }
+ break;
+ case WM_LBUTTONUP:
+ if(dragging) {
+ ReleaseCapture();
+ ImageList_EndDrag();
+ dragging=0;
+ if(dropHiLite!=-1) {
+ char path[MAX_PATH],fullPath[MAX_PATH],filename[MAX_PATH];
+ LVITEM lvi;
+ GetDlgItemTextA(hwndDlg,IDC_ICONSET,fullPath,SIZEOF(fullPath));
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)fullPath, (LPARAM)filename);
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=dragItem; lvi.iSubItem=0;
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_PREVIEW),&lvi);
+ wsprintfA(path,"%s,%d",filename,(int)lvi.lParam);
+ SendMessage(hwndParent,DM_CHANGEICON,dropHiLite,(LPARAM)path);
+ ListView_SetItemState(GetDlgItem(hwndParent,IDC_PREVIEW),dropHiLite,0,LVIS_DROPHILITED);
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_PREVIEW:
+ switch(((LPNMHDR)lParam)->code) {
+ case LVN_BEGINDRAG:
+ SetCapture(hwndDlg);
+ dragging=1;
+ dragItem=((LPNMLISTVIEW)lParam)->iItem;
+ dropHiLite=-1;
+ ImageList_BeginDrag(ListView_GetImageList(GetDlgItem(hwndDlg,IDC_PREVIEW),LVSIL_NORMAL),dragItem,GetSystemMetrics(SM_CXICON)/2,GetSystemMetrics(SM_CYICON)/2);
+ { POINT pt;
+ RECT rc;
+ GetCursorPos(&pt);
+ GetWindowRect(hwndDlg,&rc);
+ ImageList_DragEnter(hwndDlg,pt.x-rc.left,pt.y-rc.top);
+ hwndDragOver=hwndDlg;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ EnableWindow(GetDlgItem(hwndParent,IDC_IMPORT),TRUE);
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/skin/sounds.c b/miranda-wine/src/modules/skin/sounds.c new file mode 100644 index 0000000..2ae2847 --- /dev/null +++ b/miranda-wine/src/modules/skin/sounds.c @@ -0,0 +1,403 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+struct SoundItem {
+ char* name;
+ TCHAR* section;
+ TCHAR* description;
+ char* tempFile;
+};
+
+static struct SoundItem *soundList = NULL;
+static int soundCount;
+static HANDLE hPlayEvent = NULL;
+
+static int ServiceSkinAddNewSound(WPARAM wParam,LPARAM lParam)
+{
+ struct SoundItem* item;
+ SKINSOUNDDESCEX *ssd=(SKINSOUNDDESCEX*)lParam;
+
+ if (ssd->cbSize!=sizeof(SKINSOUNDDESC) && ssd->cbSize!=sizeof(SKINSOUNDDESCEX))
+ return 0;
+
+ soundList=(struct SoundItem*)mir_realloc(soundList,sizeof(struct SoundItem)*(soundCount+1));
+ item = &soundList[soundCount++];
+ item->name = mir_strdup( ssd->pszName );
+ item->description = LangPackPcharToTchar( ssd->pszDescription );
+ item->section = LangPackPcharToTchar( ssd->cbSize==sizeof(SKINSOUNDDESCEX) ? ssd->pszSection : "Other" );
+ item->tempFile = NULL;
+ if ( ssd->pszDefaultFile ) {
+ DBVARIANT dbv;
+
+ if ( DBGetContactSetting(NULL, "SkinSounds", item->name, &dbv))
+ DBWriteContactSettingString(NULL, "SkinSounds", item->name, ssd->pszDefaultFile);
+ else
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+static int SkinPlaySoundDefault(WPARAM wParam, LPARAM lParam)
+{
+ char * pszFile = (char *) lParam;
+ if ( pszFile && (DBGetContactSettingByte(NULL,"Skin","UseSound",1) || (int)wParam==1)) {
+ PlaySoundA(pszFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOWAIT);
+ }
+ return 0;
+}
+
+static int ServiceSkinPlaySound(WPARAM wParam, LPARAM lParam)
+{
+ char * pszSoundName = (char *)lParam;
+ int j;
+
+ for (j=0; j<soundCount; j++) {
+ if (pszSoundName&&strcmp(soundList[j].name, pszSoundName)== 0) {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", pszSoundName, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSetting(NULL, "SkinSounds", pszSoundName, &dbv)==0) {
+ char szFull[MAX_PATH];
+
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)szFull);
+ NotifyEventHooks(hPlayEvent, 0, (LPARAM)szFull);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while( tvi.hItem != NULL ) {
+ TreeView_GetItem( hwndTree, &tvi );
+ if ( !_tcsicmp( str, name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+#define DM_REBUILD_STREE (WM_USER+1)
+#define DM_HIDEPANE (WM_USER+2)
+#define DM_SHOWPANE (WM_USER+3)
+BOOL CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndTree = NULL;
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ hwndTree = GetDlgItem(hwndDlg, IDC_SOUNDTREE);
+ SetWindowLong(hwndTree,GWL_STYLE,GetWindowLong(hwndTree,GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES);
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ SendMessage(hwndDlg, DM_REBUILD_STREE, 0, 0);
+ TreeView_SetItemState(hwndTree, 0, TVIS_SELECTED, TVIS_SELECTED);
+ return TRUE;
+
+ case DM_REBUILD_STREE:
+ {
+ TVINSERTSTRUCT tvis;
+ int i;
+
+ TreeView_SelectItem(hwndTree, NULL);
+ ShowWindow(hwndTree, SW_HIDE);
+ TreeView_DeleteAllItems(hwndTree);
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for( i=0; i < soundCount; i++ ) {
+ tvis.item.stateMask = TVIS_EXPANDED;
+ tvis.item.state = TVIS_EXPANDED;
+ tvis.hParent = FindNamedTreeItemAtRoot( hwndTree, soundList[i].section );
+ if ( tvis.hParent == NULL ) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = soundList[i].section;
+ tvis.hParent = tvis.item.hItem = TreeView_InsertItem( hwndTree, &tvis );
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(0);
+ TreeView_SetItem( hwndTree, &tvis.item );
+ }
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(!DBGetContactSettingByte(NULL,"SkinSoundsOff",soundList[i].name,0)?2:1);
+ tvis.item.lParam = i;
+ tvis.item.pszText = soundList[i].description;
+ TreeView_InsertItem( hwndTree, &tvis );
+ }
+ { TVITEM tvi;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if ( tvi.lParam == -1 )
+ TreeView_SetItemState(hwndTree, tvi.hItem, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK);
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+
+ ShowWindow(hwndTree, SW_SHOW);
+ break;
+ }
+ case DM_HIDEPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_HIDE);
+ break;
+ case DM_SHOWPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_SHOW);
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam)==IDC_PREVIEW) {
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ if (soundList[tvi.lParam].tempFile)
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)soundList[tvi.lParam].tempFile);
+ else {
+ DBVARIANT dbv;
+ if(!DBGetContactSetting(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ char szPathFull[MAX_PATH];
+
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)szPathFull);
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)szPathFull);
+ DBFreeVariant(&dbv);
+ } }
+ break;
+ }
+ if(LOWORD(wParam)==IDC_CHANGE) {
+ char str[MAX_PATH], strFull[MAX_PATH];
+ OPENFILENAMEA ofn;
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ str[0] = 0;
+ if (soundList[tvi.lParam].tempFile) {
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile);
+ }
+ else {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", soundList[tvi.lParam].name, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSetting(NULL, "SkinSounds", soundList[tvi.lParam].name, &dbv)==0) {
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)dbv.pszVal, (LPARAM)str);
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile?soundList[tvi.lParam].tempFile:"");
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)strFull, (LPARAM)str);
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = GetParent(hwndDlg);
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = "Wave Files (*.wav)\0*.WAV\0All Files (*)\0*\0";
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "wav";
+ if(!GetOpenFileNameA(&ofn)) break;
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)str, (LPARAM)strFull);
+ soundList[tvi.lParam].tempFile = mir_strdup(strFull);
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, strFull);
+ }
+ if(LOWORD(wParam)==IDC_GETMORE) {
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=5");
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ {
+ int i;
+ for(i=0;i<soundCount;i++) {
+ if(soundList[i].tempFile)
+ DBWriteContactSettingString(NULL,"SkinSounds",soundList[i].name,soundList[i].tempFile);
+ }
+ {
+ TVITEM tvi,tvic;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while(tvi.hItem!=NULL) {
+ tvi.mask = TVIF_PARAM|TVIF_HANDLE|TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if (tvi.lParam==-1) {
+ tvic.hItem = TreeView_GetChild(hwndTree, tvi.hItem);
+ while(tvic.hItem!=NULL) {
+ tvic.mask = TVIF_PARAM|TVIF_HANDLE|TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvic);
+ if(((tvic.state&TVIS_STATEIMAGEMASK)>>12==2)) {
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule="SkinSoundsOff";
+ cgs.szSetting=soundList[tvic.lParam].name;
+ CallService(MS_DB_CONTACT_DELETESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cgs);
+ }
+ else DBWriteContactSettingByte(NULL,"SkinSoundsOff",soundList[tvic.lParam].name,1);
+ tvic.hItem=TreeView_GetNextSibling(hwndTree,tvic.hItem);
+ } }
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+
+ return TRUE;
+ }
+ break;
+ case IDC_SOUNDTREE:
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA:
+ {
+ NMTREEVIEW *pnmtv = (NMTREEVIEW*)lParam;
+ TVITEM tvi = pnmtv->itemNew;
+
+ if (tvi.lParam==-1) {
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ }
+ else {
+ TCHAR buf[256];
+ DBVARIANT dbv;
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s"), soundList[tvi.lParam].section, soundList[tvi.lParam].description);
+ SetDlgItemText(hwndDlg, IDC_NAMEVAL, buf);
+ if (soundList[tvi.lParam].tempFile)
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, soundList[tvi.lParam].tempFile);
+ else if(!DBGetContactSetting(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else SetDlgItemText(hwndDlg, IDC_LOCATION, TranslateT("<not specified>"));
+ SendMessage(hwndDlg, DM_SHOWPANE, 0, 0);
+ }
+ }
+ break;
+ case TVN_KEYDOWN:
+ {
+ NMTVKEYDOWN* ptkd = (NMTVKEYDOWN*)lParam;
+ TVHITTESTINFO hti;
+
+ if (ptkd) {
+ if (ptkd->wVKey == 0x0020) {
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti)) {
+ if (hti.flags&TVHT_ONITEM) {
+ if (TreeView_GetParent(hwndTree, hti.hItem)!=TreeView_GetRoot(hwndTree)) {
+ // the stupid checkbox gets enabled here.
+ }
+ else {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case NM_CLICK:
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti)) {
+ if (hti.flags&TVHT_ONITEM) {
+ if(hti.flags&TVHT_ONITEMSTATEICON) {
+ if (TreeView_GetParent(hwndTree, hti.hItem)!=TreeView_GetRoot(hwndTree))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int InitSkinSounds(void)
+{
+ soundList=NULL;
+ soundCount=0;
+ CreateServiceFunction(MS_SKIN_ADDNEWSOUND,ServiceSkinAddNewSound);
+ CreateServiceFunction(MS_SKIN_PLAYSOUND,ServiceSkinPlaySound);
+ hPlayEvent=CreateHookableEvent(ME_SKIN_PLAYINGSOUND);
+ SetHookDefaultForHookableEvent(hPlayEvent, SkinPlaySoundDefault);
+ return 0;
+}
+
+void UninitSkinSounds(void)
+{
+ int i;
+ for(i=0;i<soundCount;i++) {
+ mir_free(soundList[i].name);
+ mir_free(soundList[i].section);
+ mir_free(soundList[i].description);
+ if (soundList[i].tempFile) mir_free(soundList[i].tempFile);
+ }
+ if(soundCount) mir_free(soundList);
+}
diff --git a/miranda-wine/src/modules/srauth/auth.c b/miranda-wine/src/modules/srauth/auth.c new file mode 100644 index 0000000..cefe88c --- /dev/null +++ b/miranda-wine/src/modules/srauth/auth.c @@ -0,0 +1,97 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+#define MS_AUTH_SHOWREQUEST "Auth/ShowRequest"
+#define MS_AUTH_SHOWADDED "Auth/ShowAdded"
+
+BOOL CALLBACK DlgProcAuthReq(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DlgProcAdded(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+int ShowReqWindow(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_AUTHREQ),NULL,DlgProcAuthReq,(LPARAM)((CLISTEVENT *)lParam)->hDbEvent);
+ return 0;
+}
+
+int ShowAddedWindow(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_ADDED),NULL,DlgProcAdded,(LPARAM)((CLISTEVENT *)lParam)->hDbEvent);
+ return 0;
+}
+
+static int AuthEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei;
+ CLISTEVENT cli;
+ char szTooltip[256];
+ HANDLE hcontact;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || (dbei.eventType!=EVENTTYPE_AUTHREQUEST && dbei.eventType!=EVENTTYPE_ADDED)) return 0;
+
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)lParam,0);
+ dbei.pBlob=mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)(HANDLE)lParam,(LPARAM)&dbei);
+
+ hcontact=*((PHANDLE)(dbei.pBlob+sizeof(DWORD)));
+
+ ZeroMemory(&cli,sizeof(cli));
+ cli.cbSize=sizeof(cli);
+ cli.hContact=hcontact;
+ cli.pszTooltip=szTooltip;
+ cli.lParam=lParam;
+ cli.hDbEvent=(HANDLE)lParam;
+
+ if(dbei.eventType==EVENTTYPE_AUTHREQUEST)
+ {
+ mir_snprintf(szTooltip,256,Translate("%u requests authorization"),*((PDWORD)dbei.pBlob));
+
+ cli.hIcon=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ cli.pszService=MS_AUTH_SHOWREQUEST;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cli);
+ mir_free(dbei.pBlob);
+ }
+ else if(dbei.eventType==EVENTTYPE_ADDED)
+ {
+ mir_snprintf(szTooltip,256,Translate("%u added you to their contact list"),*((PDWORD)dbei.pBlob));
+
+ cli.hIcon=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ cli.pszService=MS_AUTH_SHOWADDED;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cli);
+ mir_free(dbei.pBlob);
+ }
+ return 0;
+}
+
+int LoadSendRecvAuthModule(void)
+{
+ CreateServiceFunction(MS_AUTH_SHOWREQUEST,ShowReqWindow);
+ CreateServiceFunction(MS_AUTH_SHOWADDED,ShowAddedWindow);
+ HookEvent(ME_DB_EVENT_ADDED,AuthEventAdded);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/srauth/authdialogs.c b/miranda-wine/src/modules/srauth/authdialogs.c new file mode 100644 index 0000000..7307917 --- /dev/null +++ b/miranda-wine/src/modules/srauth/authdialogs.c @@ -0,0 +1,269 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+
+BOOL CALLBACK DlgProcAdded(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { DBEVENTINFO dbei;
+ DWORD *uin;
+ char *nick,*first,*last,*email;
+ HANDLE hDbEvent,hcontact;
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MIRANDA)));
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ hDbEvent=(HANDLE)lParam;
+ //blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ)
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob=mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ uin=(PDWORD)dbei.pBlob;
+ hcontact=*((PHANDLE)(dbei.pBlob+sizeof(DWORD)));
+ if ((hcontact == INVALID_HANDLE_VALUE) || !DBGetContactSettingByte(hcontact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ nick=(char*)(dbei.pBlob+sizeof(DWORD)+sizeof(HANDLE));
+ first=nick+strlen(nick)+1;
+ last=first+strlen(first)+1;
+ email=last+strlen(last)+1;
+ if (*uin)
+ SetDlgItemInt(hwndDlg,IDC_NAME,*uin,FALSE);
+ else
+ SetDlgItemText(hwndDlg,IDC_NAME,TranslateT("(Unknown)"));
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_DETAILS),GWL_USERDATA,(LONG)hcontact);
+ mir_free(dbei.pBlob);
+ return TRUE;
+ }
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ DBEVENTINFO dbei;
+ char *szProto;
+ HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+
+ szProto=dbei.szModule;
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ return TRUE;
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ADD:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=hDbEvent;
+ acs.handleType=HANDLE_EVENT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ return TRUE;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)(HANDLE)GetWindowLong((HWND)lParam,GWL_USERDATA),0);
+ return TRUE;
+ case IDOK:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=hDbEvent;
+ acs.handleType=HANDLE_EVENT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ //fall through
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK DenyReasonProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static char szReason[256];
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ SendDlgItemMessage(hwndDlg,IDC_REASON,EM_LIMITTEXT,(WPARAM)256,0);
+ return TRUE;
+
+ case WM_COMMAND:
+ if(LOWORD(wParam)!=IDOK) break;
+ {
+ DBEVENTINFO dbei;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)GetWindowLong(hwndDlg,GWL_USERDATA),(LPARAM)&dbei);
+ GetDlgItemTextA(hwndDlg,IDC_REASON,szReason,256);
+ CallProtoService(dbei.szModule,PS_AUTHDENY,(WPARAM)GetWindowLong(hwndDlg,GWL_USERDATA),(LPARAM)szReason);
+ }
+ // fall through
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK DlgProcAuthReq(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { DBEVENTINFO dbei;
+ DWORD *uin;
+ char *nick,*first,*last,*email,*reason;
+ HANDLE hDbEvent,*hcontact;
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MIRANDA)));
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ hDbEvent=(HANDLE)lParam;
+ //blob is: uin(DWORD),hcontact(HANDLE),nick(ASCIIZ),first(ASCIIZ),last(ASCIIZ),email(ASCIIZ),reason(ASCIIZ)
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob=mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ uin=(PDWORD)dbei.pBlob;
+ hcontact=*(PHANDLE)(dbei.pBlob+sizeof(DWORD));
+ nick=(char *)(dbei.pBlob+sizeof(DWORD)+sizeof(HANDLE));
+ first=nick+strlen(nick)+1;
+ last=first+strlen(first)+1;
+ email=last+strlen(last)+1;
+ reason=email+strlen(email)+1;
+ SetDlgItemTextA(hwndDlg,IDC_NAME,nick[0]?nick:Translate("(Unknown)"));
+ if (hcontact == INVALID_HANDLE_VALUE || !DBGetContactSettingByte(hcontact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ if (*uin)
+ SetDlgItemInt(hwndDlg,IDC_UIN,*uin,FALSE);
+ else SetDlgItemText(hwndDlg,IDC_UIN,TranslateT("(Unknown)"));
+ SetDlgItemTextA(hwndDlg,IDC_MAIL,email[0]?email:Translate("(Unknown)"));
+ SetDlgItemTextA(hwndDlg,IDC_REASON,reason);
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_DETAILS),GWL_USERDATA,(LONG)hcontact);
+ mir_free(dbei.pBlob);
+ return TRUE;
+ }
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ DBEVENTINFO dbei;
+ char *szProto;
+ HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+
+ szProto=dbei.szModule;
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ return TRUE;
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ADD:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=hDbEvent;
+ acs.handleType=HANDLE_EVENT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ return TRUE;
+ }
+ case IDC_DETAILS:
+ { HANDLE hcontact=(HANDLE)GetWindowLong((HANDLE)lParam,GWL_USERDATA);
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hcontact,0);
+ }
+ return TRUE;
+ case IDOK:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ DBEVENTINFO dbei;
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ CallProtoService(dbei.szModule,PS_AUTHALLOW,(WPARAM)hDbEvent,0);
+ }
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDCANCEL:
+ { HANDLE hDbEvent=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DENYREASON),hwndDlg,DenyReasonProc,(LPARAM)hDbEvent);
+ }
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
diff --git a/miranda-wine/src/modules/srawaymsg/awaymsg.c b/miranda-wine/src/modules/srawaymsg/awaymsg.c new file mode 100644 index 0000000..9bba52b --- /dev/null +++ b/miranda-wine/src/modules/srawaymsg/awaymsg.c @@ -0,0 +1,161 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+int LoadAwayMessageSending(void);
+
+static HANDLE hAwayMsgMenuItem;
+static HANDLE hWindowList;
+
+struct AwayMsgDlgData {
+ HANDLE hContact;
+ HANDLE hSeq;
+ HANDLE hAwayMsgEvent;
+};
+#define HM_AWAYMSG (WM_USER+10)
+static BOOL CALLBACK ReadAwayMsgDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct AwayMsgDlgData *dat;
+ dat=(struct AwayMsgDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct AwayMsgDlgData*)mir_alloc(sizeof(struct AwayMsgDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hContact=(HANDLE)lParam;
+ dat->hAwayMsgEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_AWAYMSG);
+ dat->hSeq=(HANDLE)CallContactService(dat->hContact,PSS_GETAWAYMSG,0,0);
+ WindowList_Add(hWindowList,hwndDlg,dat->hContact);
+ { TCHAR str[256],format[128];
+ TCHAR* contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ char* szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ WORD dwStatus = DBGetContactSettingWord(dat->hContact,szProto,"Status",ID_STATUS_OFFLINE);
+ TCHAR* status=(TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,dwStatus,GCMDF_TCHAR);
+ GetWindowText(hwndDlg,format,SIZEOF(format));
+ mir_sntprintf(str,SIZEOF(str),format,status,contactName);
+ SetWindowText(hwndDlg,str);
+ GetDlgItemText(hwndDlg,IDC_RETRIEVING,format,SIZEOF(format));
+ mir_sntprintf(str,SIZEOF(str),format,status);
+ SetDlgItemText(hwndDlg,IDC_RETRIEVING,str);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedProtoIcon(szProto, dwStatus));
+ }
+ return TRUE;
+ case HM_AWAYMSG:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_AWAYMSG) break;
+ if(ack->hProcess!=dat->hSeq) break;
+ if(ack->result!=ACKRESULT_SUCCESS) break;
+ if(dat->hAwayMsgEvent!=NULL) {UnhookEvent(dat->hAwayMsgEvent); dat->hAwayMsgEvent=NULL;}
+ SetDlgItemTextA(hwndDlg,IDC_MSG,(const char*)ack->lParam);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RETRIEVING),SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_MSG),SW_SHOW);
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("&Close"));
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ if(dat->hAwayMsgEvent!=NULL) UnhookEvent(dat->hAwayMsgEvent);
+ WindowList_Remove(hWindowList,hwndDlg);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int GetMessageCommand(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_READAWAYMSG),NULL,ReadAwayMsgDlgProc,wParam);
+ return 0;
+}
+
+static int AwayMsgPreBuildMenu(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM clmi;
+ char str[128];
+ int status;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ ZeroMemory(&clmi,sizeof(clmi));
+ clmi.cbSize=sizeof(clmi);
+ clmi.flags=CMIM_FLAGS|CMIF_NOTOFFLINE|CMIF_HIDDEN;
+
+ if(szProto!=NULL) {
+ int chatRoom = szProto?DBGetContactSettingByte((HANDLE)wParam, szProto, "ChatRoom", 0):0;
+ if ( !chatRoom ) {
+ status=DBGetContactSettingWord((HANDLE)wParam,szProto,"Status",ID_STATUS_OFFLINE);
+ wsprintfA(str,Translate("Re&ad %s Message"),(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,status,0));
+ clmi.pszName=str;
+ if(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGRECV) {
+ if(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_3,0)&Proto_Status2Flag(status)){
+ clmi.flags=CMIM_FLAGS|CMIM_NAME|CMIF_NOTOFFLINE|CMIM_ICON;
+ clmi.hIcon = LoadSkinnedProtoIcon(szProto, status);
+ }
+ }
+ }
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hAwayMsgMenuItem,(LPARAM)&clmi);
+ return 0;
+}
+
+static int AwayMsgPreShutdown(WPARAM wParam, LPARAM lParam)
+{
+ if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_CLOSE,0,0);
+ return 0;
+}
+
+int LoadAwayMsgModule(void)
+{
+ CLISTMENUITEM mi;
+
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ CreateServiceFunction(MS_AWAYMSG_SHOWAWAYMSG,GetMessageCommand);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_NOTOFFLINE;
+ mi.hIcon=NULL;
+ mi.pszContactOwner=NULL;
+ mi.pszName=Translate("Re&ad Away Message");
+ mi.pszService=MS_AWAYMSG_SHOWAWAYMSG;
+ hAwayMsgMenuItem=(HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU,AwayMsgPreBuildMenu);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,AwayMsgPreShutdown);
+ return LoadAwayMessageSending();
+}
diff --git a/miranda-wine/src/modules/srawaymsg/sendmsg.c b/miranda-wine/src/modules/srawaymsg/sendmsg.c new file mode 100644 index 0000000..83d8aa1 --- /dev/null +++ b/miranda-wine/src/modules/srawaymsg/sendmsg.c @@ -0,0 +1,414 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static DWORD protoModeMsgFlags;
+
+static char *GetDefaultMessage(int status)
+{
+ switch(status) {
+ case ID_STATUS_AWAY: return Translate("I've been away since %time%.");
+ case ID_STATUS_NA: return Translate("Give it up, I'm not in!");
+ case ID_STATUS_OCCUPIED: return Translate("Not right now.");
+ case ID_STATUS_DND: return Translate("Give a guy some peace, would ya?");
+ case ID_STATUS_FREECHAT: return Translate("I'm a chatbot!");
+ case ID_STATUS_ONLINE: return Translate("Yep, I'm here.");
+ case ID_STATUS_OFFLINE: return Translate("Nope, not here.");
+ case ID_STATUS_INVISIBLE: return Translate("I'm hiding from the mafia.");
+ case ID_STATUS_ONTHEPHONE: return Translate("That'll be the phone.");
+ case ID_STATUS_OUTTOLUNCH: return Translate("Mmm...food.");
+ case ID_STATUS_IDLE: return Translate("idleeeeeeee");
+ }
+ return NULL;
+}
+
+static char *StatusModeToDbSetting(int status,const char *suffix)
+{
+ char *prefix;
+ static char str[64];
+
+ switch(status) {
+ case ID_STATUS_AWAY: prefix="Away"; break;
+ case ID_STATUS_NA: prefix="Na"; break;
+ case ID_STATUS_DND: prefix="Dnd"; break;
+ case ID_STATUS_OCCUPIED: prefix="Occupied"; break;
+ case ID_STATUS_FREECHAT: prefix="FreeChat"; break;
+ case ID_STATUS_ONLINE: prefix="On"; break;
+ case ID_STATUS_OFFLINE: prefix="Off"; break;
+ case ID_STATUS_INVISIBLE: prefix="Inv"; break;
+ case ID_STATUS_ONTHEPHONE: prefix="Otp"; break;
+ case ID_STATUS_OUTTOLUNCH: prefix="Otl"; break;
+ case ID_STATUS_IDLE: prefix="Idl"; break;
+ default: return NULL;
+ }
+ lstrcpyA(str,prefix); lstrcatA(str,suffix);
+ return str;
+}
+
+//remember to mir_free() the return value
+static int GetAwayMessage(WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ int statusMode = (int)wParam;
+
+ if(DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(wParam,"Ignore"),0)) {
+ return (int)NULL;
+ }
+ if(DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusMode,"UsePrev"),0)) {
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusMode,"Msg"),&dbv))
+ dbv.pszVal=mir_strdup(GetDefaultMessage(statusMode));
+ }
+ else {
+ int i;
+ char substituteStr[128];
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusMode,"Default"),&dbv))
+ dbv.pszVal=mir_strdup(GetDefaultMessage(statusMode));
+ for(i=0;dbv.pszVal[i];i++) {
+ if(dbv.pszVal[i]!='%') continue;
+ if(!_strnicmp(dbv.pszVal+i,"%time%",6))
+ GetTimeFormatA(LOCALE_USER_DEFAULT,TIME_NOSECONDS,NULL,NULL,substituteStr,SIZEOF(substituteStr));
+ else if(!_strnicmp(dbv.pszVal+i,"%date%",6))
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,NULL,NULL,substituteStr,SIZEOF(substituteStr));
+ else continue;
+ if(lstrlenA(substituteStr)>6) dbv.pszVal=(char*)mir_realloc(dbv.pszVal,lstrlenA(dbv.pszVal)+1+lstrlenA(substituteStr)-6);
+ MoveMemory(dbv.pszVal+i+lstrlenA(substituteStr),dbv.pszVal+i+6,lstrlenA(dbv.pszVal)-i-5);
+ CopyMemory(dbv.pszVal+i,substituteStr,lstrlenA(substituteStr));
+ }
+ }
+ return (int)dbv.pszVal;
+}
+
+static WNDPROC OldMessageEditProc;
+
+static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CHAR:
+ if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) { //ctrl-a
+ SendMessage(hwnd, EM_SETSEL, 0, -1);
+ return 0;
+ }
+ if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w
+ SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
+ return 0;
+ }
+ if (wParam == 127 && GetKeyState(VK_CONTROL) & 0x8000) { //ctrl-backspace
+ DWORD start, end;
+ TCHAR *text;
+ int textLen;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM) & end, (LPARAM) (PDWORD) NULL);
+ SendMessage(hwnd, WM_KEYDOWN, VK_LEFT, 0);
+ SendMessage(hwnd, EM_GETSEL, (WPARAM) & start, (LPARAM) (PDWORD) NULL);
+ textLen = GetWindowTextLength(hwnd);
+ text = (TCHAR *) mir_alloc(sizeof(TCHAR) * (textLen + 1));
+ GetWindowText(hwnd, text, textLen + 1);
+ MoveMemory(text + start, text + end, sizeof(TCHAR) * (textLen + 1 - end));
+ SetWindowText(hwnd, text);
+ mir_free(text);
+ SendMessage(hwnd, EM_SETSEL, start, start);
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldMessageEditProc,hwnd,msg,wParam,lParam);
+}
+
+void ChangeAllProtoMessages(char *szProto, int statusMode,char *msg)
+{
+ int protoCount,i;
+ PROTOCOLDESCRIPTOR **proto;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&proto);
+ if (szProto) CallProtoService(szProto,PS_SETAWAYMSG,statusMode,(LPARAM)msg);
+ else {
+ for(i=0;i<protoCount;i++) {
+ if (CallProtoService(proto[i]->szName,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGSEND)
+ CallProtoService(proto[i]->szName,PS_SETAWAYMSG,statusMode,(LPARAM)msg);
+ }
+ }
+}
+
+struct SetAwayMsgData {
+ int statusMode;
+ int countdown;
+ char okButtonFormat[64];
+ char *szProto;
+ HANDLE hPreshutdown;
+};
+struct SetAwasMsgNewData {
+ char *szProto;
+ int statusMode;
+};
+
+#define DM_SRAWAY_SHUTDOWN WM_USER+10
+
+static BOOL CALLBACK SetAwayMsgDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct SetAwayMsgData *dat;
+
+ dat=(struct SetAwayMsgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch(message) {
+ case WM_INITDIALOG:
+ {
+ struct SetAwasMsgNewData *newdat = (struct SetAwasMsgNewData*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct SetAwayMsgData*)mir_alloc(sizeof(struct SetAwayMsgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->statusMode=newdat->statusMode;
+ dat->szProto=newdat->szProto;
+ mir_free(newdat);
+ SendDlgItemMessage(hwndDlg,IDC_MSG,EM_LIMITTEXT,1024,0);
+ OldMessageEditProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)MessageEditSubclassProc);
+ { char str[256],format[128];
+ GetWindowTextA(hwndDlg,format,SIZEOF(format));
+ mir_snprintf(str,SIZEOF(str),format,(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,dat->statusMode,0));
+ SetWindowTextA(hwndDlg,str);
+ }
+ GetDlgItemTextA(hwndDlg,IDOK,dat->okButtonFormat,SIZEOF(dat->okButtonFormat));
+ { char *msg=(char*)GetAwayMessage((WPARAM)dat->statusMode,0);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,msg);
+ mir_free(msg);
+ }
+ dat->countdown=5;
+ SendMessage(hwndDlg,WM_TIMER,0,0);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedProtoIcon(dat->szProto, dat->statusMode));
+ SetTimer(hwndDlg,1,1000,0);
+ dat->hPreshutdown=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,DM_SRAWAY_SHUTDOWN);
+ return TRUE;
+ }
+ case WM_TIMER:
+ if(dat->countdown==-1) {DestroyWindow(hwndDlg); break;}
+ { char str[64];
+ mir_snprintf(str,SIZEOF(str),dat->okButtonFormat,dat->countdown);
+ SetDlgItemTextA(hwndDlg,IDOK,str);
+ }
+ dat->countdown--;
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDC_MSG:
+ KillTimer(hwndDlg,1);
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("OK"));
+ break;
+ }
+ break;
+ case DM_SRAWAY_SHUTDOWN:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ { char str[1024];
+ GetDlgItemTextA(hwndDlg,IDC_MSG,str,SIZEOF(str));
+ ChangeAllProtoMessages(dat->szProto,dat->statusMode,str);
+ DBWriteContactSettingString(NULL,"SRAway",StatusModeToDbSetting(dat->statusMode,"Msg"),str);
+ }
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)OldMessageEditProc);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int StatusModeChange(WPARAM wParam,LPARAM lParam)
+{
+ BOOL bScreenSaverRunning=FALSE;
+ char *szProto = (char*)lParam;
+
+ // If its a global change check the complete PFLAGNUM_3 flags to see if a popup might be needed
+ if(!szProto) {
+ if(!(protoModeMsgFlags&Proto_Status2Flag(wParam)))
+ return 0;
+ }
+ // If its a single protocol check the PFLAGNUM_3 for the single protocol
+ else if (!(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0)&PF1_MODEMSGSEND)||!(CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_3,0)&Proto_Status2Flag(wParam)))
+ return 0;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0,&bScreenSaverRunning,FALSE);
+ if(DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(wParam,"Ignore"),0)) {
+ ChangeAllProtoMessages((char*)lParam,wParam,NULL);
+ }
+ else if(bScreenSaverRunning || DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(wParam,"NoDlg"),0)) {
+ char *msg=(char*)GetAwayMessage(wParam, 0);
+ ChangeAllProtoMessages((char*)lParam,wParam,msg);
+ mir_free(msg);
+ }
+ else {
+ struct SetAwasMsgNewData *newdat = (struct SetAwasMsgNewData*)mir_alloc(sizeof(struct SetAwasMsgNewData));
+ newdat->szProto = (char*)lParam;
+ newdat->statusMode = (int)wParam;
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_SETAWAYMSG),NULL,SetAwayMsgDlgProc,(LPARAM)newdat);
+ }
+ return 0;
+}
+
+static int statusModes[]={ID_STATUS_OFFLINE,ID_STATUS_ONLINE,ID_STATUS_AWAY,ID_STATUS_NA,ID_STATUS_OCCUPIED,ID_STATUS_DND,ID_STATUS_FREECHAT,ID_STATUS_INVISIBLE,ID_STATUS_OUTTOLUNCH,ID_STATUS_ONTHEPHONE, ID_STATUS_IDLE};
+
+struct AwayMsgInfo {
+ int ignore;
+ int noDialog;
+ int usePrevious;
+ char msg[1024];
+};
+struct AwayMsgDlgData {
+ struct AwayMsgInfo info[ SIZEOF(statusModes) ];
+ int oldPage;
+};
+static BOOL CALLBACK DlgProcAwayMsgOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct AwayMsgDlgData *dat;
+
+ dat=(struct AwayMsgDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int i,j;
+ DBVARIANT dbv;
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct AwayMsgDlgData*)mir_alloc(sizeof(struct AwayMsgDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->oldPage=-1;
+ for( i=0; i < SIZEOF(statusModes); i++ ) {
+ if(!(protoModeMsgFlags&Proto_Status2Flag(statusModes[i]))) continue;
+ { TCHAR* ptszDescr = LangPackPcharToTchar(( LPCSTR )CallService( MS_CLIST_GETSTATUSMODEDESCRIPTION, statusModes[i], 0 ));
+ j = SendDlgItemMessage( hwndDlg, IDC_STATUS, CB_ADDSTRING, 0, (LPARAM)ptszDescr );
+ mir_free( ptszDescr );
+ }
+ SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_SETITEMDATA,j,statusModes[i]);
+ dat->info[j].ignore=DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"Ignore"),0);
+ dat->info[j].noDialog=DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"NoDlg"),0);
+ dat->info[j].usePrevious=DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"UsePrev"),0);
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"Default"),&dbv))
+ if(DBGetContactSetting(NULL,"SRAway",StatusModeToDbSetting(statusModes[i],"Msg"),&dbv))
+ dbv.pszVal=mir_strdup(GetDefaultMessage(statusModes[i]));
+ lstrcpyA(dat->info[j].msg,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_SETCURSEL,0,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_STATUS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int i=SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_GETCURSEL,0,0);
+ if(dat->oldPage!=-1) {
+ dat->info[dat->oldPage].ignore=IsDlgButtonChecked(hwndDlg,IDC_DONTREPLY);
+ dat->info[dat->oldPage].noDialog=IsDlgButtonChecked(hwndDlg,IDC_NODIALOG);
+ dat->info[dat->oldPage].usePrevious=IsDlgButtonChecked(hwndDlg,IDC_USEPREVIOUS);
+ GetDlgItemTextA(hwndDlg,IDC_MSG,dat->info[dat->oldPage].msg,SIZEOF(dat->info[dat->oldPage].msg));
+ }
+ CheckDlgButton(hwndDlg,IDC_DONTREPLY,i<0?0:dat->info[i].ignore);
+ CheckDlgButton(hwndDlg,IDC_NODIALOG,i<0?0:dat->info[i].noDialog);
+ CheckDlgButton(hwndDlg,IDC_USEPREVIOUS,i<0?0:dat->info[i].usePrevious);
+ CheckDlgButton(hwndDlg,IDC_USESPECIFIC,i<0?0:!dat->info[i].usePrevious);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,i<0?"":dat->info[i].msg);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_NODIALOG),i<0?0:!dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_USEPREVIOUS),i<0?0:!dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_USESPECIFIC),i<0?0:!dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),i<0?0:!(dat->info[i].ignore || dat->info[i].usePrevious));
+ dat->oldPage=i;
+ }
+ return 0;
+ case IDC_DONTREPLY:
+ case IDC_USEPREVIOUS:
+ case IDC_USESPECIFIC:
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ break;
+ case IDC_MSG:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ { int i,status;
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ for(i=SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ status=SendDlgItemMessage(hwndDlg,IDC_STATUS,CB_GETITEMDATA,i,0);
+ DBWriteContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"Ignore"),(BYTE)dat->info[i].ignore);
+ DBWriteContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"NoDlg"),(BYTE)dat->info[i].noDialog);
+ DBWriteContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"UsePrev"),(BYTE)dat->info[i].usePrevious);
+ DBWriteContactSettingString(NULL,"SRAway",StatusModeToDbSetting(status,"Default"),dat->info[i].msg);
+ }
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int AwayMsgOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 870000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_AWAYMSG);
+ odp.pszTitle = "Status Messages";
+ odp.pszGroup = "Status";
+ odp.pfnDlgProc = DlgProcAwayMsgOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int AwayMsgSendModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ int i,protoCount;
+ PROTOCOLDESCRIPTOR **proto;
+
+ protoModeMsgFlags=0;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&proto);
+ for(i=0;i<protoCount;i++)
+ protoModeMsgFlags|=CallProtoService(proto[i]->szName,PS_GETCAPS,PFLAGNUM_3,0);
+ if(protoModeMsgFlags) {
+ HookEvent(ME_CLIST_STATUSMODECHANGE,StatusModeChange);
+ HookEvent(ME_OPT_INITIALISE,AwayMsgOptInitialise);
+ }
+ return 0;
+}
+
+int LoadAwayMessageSending(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,AwayMsgSendModulesLoaded);
+ CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSG, GetAwayMessage);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/sremail/email.c b/miranda-wine/src/modules/sremail/email.c new file mode 100644 index 0000000..3a44d96 --- /dev/null +++ b/miranda-wine/src/modules/sremail/email.c @@ -0,0 +1,92 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static HANDLE hEMailMenuItem;
+
+void SendEmailThread(char *szUrl)
+{
+ ShellExecuteA(NULL,"open",szUrl,"","",SW_SHOW);
+ mir_free(szUrl);
+ return;
+}
+
+static int SendEMailCommand(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv;
+ char *szUrl;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if(szProto==NULL || DBGetContactSetting((HANDLE)wParam,szProto,"e-mail",&dbv)) {
+ if(DBGetContactSetting((HANDLE)wParam,"UserInfo","Mye-mail0",&dbv)) {
+ MessageBox((HWND)lParam,TranslateT("User has not registered an e-mail address"),TranslateT("Send e-mail"),MB_OK);
+ return 1;
+ }
+ }
+ szUrl=(char*)mir_alloc(lstrlenA(dbv.pszVal)+8);
+ lstrcpyA(szUrl,"mailto:");
+ lstrcatA(szUrl,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ forkthread(SendEmailThread,0,szUrl);
+ return 0;
+}
+
+static int EMailPreBuildMenu(WPARAM wParam, LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ DBVARIANT dbv = { 0 };
+ char *szProto;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS;
+
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL || DBGetContactSetting((HANDLE)wParam, szProto, "e-mail",& dbv)) {
+ if (DBGetContactSetting((HANDLE)wParam, "UserInfo", "Mye-mail0", &dbv))
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hEMailMenuItem, (LPARAM)&mi);
+ if (dbv.pszVal) DBFreeVariant(&dbv);
+ return 0;
+}
+
+int LoadSendRecvEMailModule(void)
+{
+ CLISTMENUITEM mi;
+
+ CreateServiceFunction(MS_EMAIL_SENDEMAIL, SendEMailCommand);
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000010000;
+ mi.flags = 0;
+ mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SENDEMAIL));
+ mi.pszContactOwner = NULL;
+ mi.pszName = Translate("&E-mail");
+ mi.pszService = MS_EMAIL_SENDEMAIL;
+ hEMailMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, EMailPreBuildMenu);
+
+ return 0;
+}
diff --git a/miranda-wine/src/modules/srfile/file.c b/miranda-wine/src/modules/srfile/file.c new file mode 100644 index 0000000..f69ccbf --- /dev/null +++ b/miranda-wine/src/modules/srfile/file.c @@ -0,0 +1,287 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "file.h"
+
+static HANDLE *hFileMenu;
+static int hFileMenuCount = 0;
+
+static int SendFileCommand(WPARAM wParam,LPARAM lParam)
+{
+ struct FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ fsd.ppFiles=NULL;
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ return 0;
+}
+
+static int SendSpecificFiles(WPARAM wParam,LPARAM lParam)
+{
+ struct FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ fsd.ppFiles=(const char**)lParam;
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ return 0;
+}
+
+static int GetReceivedFilesFolder(WPARAM wParam,LPARAM lParam)
+{
+ GetContactReceivedFilesDir((HANDLE)wParam,(char*)lParam,MAX_PATH);
+ return 0;
+}
+
+static int RecvFileCommand(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILERECV),NULL,DlgProcRecvFile,lParam);
+ return 0;
+}
+
+static int FileEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO dbei={0};
+ CLISTEVENT cle={0};
+
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || dbei.eventType!=EVENTTYPE_FILE) return 0;
+
+ cle.cbSize=sizeof(cle);
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)lParam;
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && !DBGetContactSettingByte((HANDLE)wParam,"CList","NotOnList",0)) {
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILERECV),NULL,DlgProcRecvFile,(LPARAM)&cle);
+ }
+ else {
+ char *contactName;
+ char szTooltip[256];
+
+ SkinPlaySound("RecvFile");
+ cle.hIcon=LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ cle.pszService="SRFile/RecvFile";
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,wParam,0);
+ mir_snprintf(szTooltip,SIZEOF(szTooltip),Translate("File from %s"),contactName);
+ cle.pszTooltip=szTooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ }
+ return 0;
+}
+
+void CreateDirectoryTree(char *szDir)
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash,szTestDir[MAX_PATH];
+
+ lstrcpynA(szTestDir,szDir,SIZEOF(szTestDir));
+ if((dwAttributes=GetFileAttributesA(szTestDir))!=0xffffffff
+ && dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return;
+ pszLastBackslash=strrchr(szTestDir,'\\');
+ if(pszLastBackslash==NULL) {GetCurrentDirectoryA(MAX_PATH,szDir); return;}
+ *pszLastBackslash='\0';
+ CreateDirectoryTree(szTestDir);
+ CreateDirectoryA(szTestDir,NULL);
+}
+
+int SRFile_GetRegValue(HKEY hKeyBase,const char *szSubKey,const char *szValue,char *szOutput,int cbOutput)
+{
+ HKEY hKey;
+ DWORD cbOut=cbOutput;
+
+ if(RegOpenKeyExA(hKeyBase,szSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS) return 0;
+ if(RegQueryValueExA(hKey,szValue,NULL,NULL,(PBYTE)szOutput,&cbOut)!=ERROR_SUCCESS) {RegCloseKey(hKey); return 0;}
+ RegCloseKey(hKey);
+ return 1;
+}
+
+void GetSensiblyFormattedSize(DWORD size,TCHAR *szOut,int cchOut,int unitsOverride,int appendUnits,int *unitsUsed)
+{
+ if(!unitsOverride) {
+ if(size<1000) unitsOverride=UNITS_BYTES;
+ else if(size<100*1024) unitsOverride=UNITS_KBPOINT1;
+ else if(size<1024*1024) unitsOverride=UNITS_KBPOINT0;
+ else unitsOverride=UNITS_MBPOINT2;
+ }
+ if(unitsUsed) *unitsUsed=unitsOverride;
+ switch(unitsOverride) {
+ case UNITS_BYTES: mir_sntprintf(szOut,cchOut,_T("%u%s%s"),size,appendUnits?_T(" "):_T(""),appendUnits?TranslateT("bytes"):_T("")); break;
+ case UNITS_KBPOINT1: mir_sntprintf(szOut,cchOut,_T("%.1lf%s"),size/1024.0,appendUnits?_T(" KB"):_T("")); break;
+ case UNITS_KBPOINT0: mir_sntprintf(szOut,cchOut,_T("%u%s"),size/1024,appendUnits?_T(" KB"):_T("")); break;
+ default: mir_sntprintf(szOut,cchOut,_T("%.2lf%s"),size/1048576.0,appendUnits?_T(" MB"):_T("")); break;
+ }
+}
+
+// Tripple redirection sucks but is needed to nullify the array pointer
+void FreeFilesMatrix(char ***files)
+{
+
+ char **pFile;
+
+ if (*files == NULL)
+ return;
+
+ // Free each filename in the pointer array
+ pFile = *files;
+ while (*pFile != NULL)
+ {
+ mir_free(*pFile);
+ *pFile = NULL;
+ pFile++;
+ }
+
+ // Free the array itself
+ mir_free(*files);
+ *files = NULL;
+
+}
+
+void FreeProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *fts)
+{
+ if(fts->currentFile) mir_free(fts->currentFile);
+ if(fts->files) {
+ int i;
+ for(i=0;i<fts->totalFiles;i++) mir_free(fts->files[i]);
+ mir_free(fts->files);
+ }
+ if(fts->workingDir) mir_free(fts->workingDir);
+}
+
+void CopyProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest,PROTOFILETRANSFERSTATUS *src)
+{
+ *dest=*src;
+ if(src->currentFile) dest->currentFile=mir_strdup(src->currentFile);
+ if(src->files) {
+ int i;
+ dest->files=(char**)mir_alloc(sizeof(char*)*src->totalFiles);
+ for(i=0;i<src->totalFiles;i++)
+ dest->files[i]=mir_strdup(src->files[i]);
+ }
+ if(src->workingDir) dest->workingDir=mir_strdup(src->workingDir);
+}
+
+static void RemoveUnreadFileEvents(void)
+{
+ DBEVENTINFO dbei={0};
+ HANDLE hDbEvent,hContact;
+
+ dbei.cbSize=sizeof(dbei);
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact) {
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ if(!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_FILE)
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)hContact,(LPARAM)hDbEvent);
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0);
+ }
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+}
+
+static int SRFileModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ PROTOCOLDESCRIPTOR **protocol;
+ int protoCount,i;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000020000;
+ mi.flags=CMIF_NOTOFFLINE;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ mi.pszName=Translate("&File");
+ mi.pszService=MS_FILE_SENDFILE;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protocol);
+ for(i=0;i<protoCount;i++) {
+ if(protocol[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ if(CallProtoService(protocol[i]->szName,PS_GETCAPS,PFLAGNUM_1,0)&PF1_FILESEND) {
+ mi.pszContactOwner=protocol[i]->szName;
+ hFileMenu = (HANDLE*)mir_realloc(hFileMenu,sizeof(HANDLE)*(hFileMenuCount+1));
+ hFileMenu[hFileMenuCount] = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ hFileMenuCount++;
+ }
+ }
+ RemoveUnreadFileEvents();
+ return 0;
+}
+
+static int hUpdateIcons = 0;
+int FilePreBuildContactMenu(WPARAM wParam,LPARAM lParam) {
+ if (hUpdateIcons) {
+ CLISTMENUITEM mi;
+ int i;
+
+ hUpdateIcons = 0;
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS|CMIM_ICON;
+ mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_FILE);
+
+ for(i=0;i<hFileMenuCount;i++)
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hFileMenu[i], (LPARAM)&mi);
+ }
+ return 0;
+}
+
+int FileIconsChanged(WPARAM wParam,LPARAM lParam) {
+ hUpdateIcons = 1;
+ return 0;
+}
+
+int FileShutdownProc(WPARAM wParam,LPARAM lParam) {
+ mir_free(hFileMenu);
+ return 0;
+}
+
+int LoadSendRecvFileModule(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,SRFileModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED,FileEventAdded);
+ HookEvent(ME_OPT_INITIALISE,FileOptInitialise);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU,FilePreBuildContactMenu);
+ HookEvent(ME_SKIN_ICONSCHANGED,FileIconsChanged);
+ HookEvent(ME_SYSTEM_SHUTDOWN,FileShutdownProc);
+ CreateServiceFunction(MS_FILE_SENDFILE,SendFileCommand);
+ CreateServiceFunction(MS_FILE_SENDSPECIFICFILES,SendSpecificFiles);
+ CreateServiceFunction(MS_FILE_GETRECEIVEDFILESFOLDER,GetReceivedFilesFolder);
+ CreateServiceFunction("SRFile/RecvFile",RecvFileCommand);
+ SkinAddNewSoundEx("RecvFile",Translate("File"),Translate("Incoming"));
+ SkinAddNewSoundEx("FileDone",Translate("File"),Translate("Complete"));
+ SkinAddNewSoundEx("FileFailed",Translate("File"),Translate("Error"));
+ SkinAddNewSoundEx("FileDenied",Translate("File"),Translate("Denied"));
+ // Upgrade Routine for File Received Path - Remove me after 0.3.4
+ {
+ DBVARIANT dbv;
+
+ if(!DBGetContactSetting(NULL,"SRFile","RecvFilesDir",&dbv)) {
+ char szPath[MAX_PATH];
+
+ mir_snprintf(szPath, SIZEOF(szPath), "%s%s%s", dbv.pszVal, dbv.pszVal[strlen(dbv.pszVal)-1]=='\\'?"":"\\" , "%userid%");
+ DBFreeVariant(&dbv);
+ DBWriteContactSettingString(NULL,"SRFile","RecvFilesDirAdv",szPath);
+ DBDeleteContactSetting(NULL,"SRFile","RecvFilesDir");
+ }
+ }
+ // End Upgrade
+ return 0;
+}
diff --git a/miranda-wine/src/modules/srfile/file.h b/miranda-wine/src/modules/srfile/file.h new file mode 100644 index 0000000..2c578b4 --- /dev/null +++ b/miranda-wine/src/modules/srfile/file.h @@ -0,0 +1,88 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#define VIRUSSCAN_DISABLE 0
+#define VIRUSSCAN_AFTERDL 1
+#define VIRUSSCAN_DURINGDL 2
+
+#define FILERESUME_ASK 0
+//1,2,3,4: resume, overwrite, rename, skip: from proto library
+#define FILERESUMEF_ALL 0x80
+#define FILERESUME_RESUMEALL (FILERESUME_RESUME|FILERESUMEF_ALL)
+#define FILERESUME_OVERWRITEALL (FILERESUME_OVERWRITE|FILERESUMEF_ALL)
+#define FILERESUME_RENAMEALL (FILERESUME_RENAME|FILERESUMEF_ALL)
+#define FILERESUME_CANCEL 0xFFFFFFFF
+
+#define M_FILEEXISTSDLGREPLY (WM_USER+200)
+#define M_PRESHUTDOWN (WM_USER+201)
+
+struct FileSendData {
+ HANDLE hContact;
+ const char **ppFiles;
+};
+
+#define BYTESRECVEDHISTORYCOUNT 10 //the number of bytes recved is sampled once a second and the last 10 are used to get the transfer speed
+struct FileDlgData {
+ HWND hwndTransfer;
+ HANDLE fs;
+ HANDLE hContact;
+ HANDLE hDbEvent;
+ HANDLE hNotifyEvent;
+ char **files;
+ HICON hUIIcons[4];
+ int send;
+ int closeIfFileChooseCancelled;
+ int resumeBehaviour;
+ int bytesRecvedHistory[BYTESRECVEDHISTORYCOUNT];
+ int bytesRecvedHistorySize;
+ int waitingForAcceptance;
+ PROTOFILETRANSFERSTATUS transferStatus;
+ int *fileVirusScanned;
+ HANDLE hPreshutdownEvent;
+ DWORD dwTicks;
+};
+
+//file.c
+void CreateDirectoryTree(char *szDir);
+#define UNITS_BYTES 1 // 0<=size<1000: "%d bytes"
+#define UNITS_KBPOINT1 2 // 1000<=size<100*1024: "%.1f KB"
+#define UNITS_KBPOINT0 3 // 100*1024<=size<1024*1024: "%d KB"
+#define UNITS_MBPOINT2 4 // 1024*1024<=size: "%.2f MB"
+void GetSensiblyFormattedSize(DWORD size,TCHAR *szOut,int cchOut,int unitsOverride,int appendUnits,int *unitsUsed);
+void FreeFilesMatrix(char ***files); //loving that triple indirection
+void FreeProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *fts);
+void CopyProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest,PROTOFILETRANSFERSTATUS *src);
+int SRFile_GetRegValue(HKEY hKeyBase,const char *szSubKey,const char *szValue,char *szOutput,int cbOutput);
+//filesenddlg.c
+BOOL CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//filerecv.c
+BOOL CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+void GetContactReceivedFilesDir(HANDLE hContact,char *szDir,int cchDir);
+int BrowseForFolder(HWND hwnd,char *szPath);
+//fileexistsdlg.c
+BOOL CALLBACK DlgProcFileExists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//filexferdlg.c
+BOOL CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//fileopts.c
+int FileOptInitialise(WPARAM wParam,LPARAM lParam);
+
diff --git a/miranda-wine/src/modules/srfile/fileexistsdlg.c b/miranda-wine/src/modules/srfile/fileexistsdlg.c new file mode 100644 index 0000000..73d2bf3 --- /dev/null +++ b/miranda-wine/src/modules/srfile/fileexistsdlg.c @@ -0,0 +1,331 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <shlobj.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+static void SetControlToUnixTime(HWND hwndDlg, UINT idCtrl, time_t unixTime)
+{
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ char szTime[64],szDate[64],szOutput[128];
+
+ liFiletime.QuadPart=(BIGI(11644473600)+(__int64)unixTime)*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,szTime,SIZEOF(szTime));
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,szDate,SIZEOF(szDate));
+ wsprintfA(szOutput,"%s %s",szDate,szTime);
+ SetDlgItemTextA(hwndDlg,idCtrl,szOutput);
+}
+
+#define C_CONTEXTMENU 0
+#define C_PROPERTIES 1
+// not defined in VC++ 6.0 SE
+#ifndef CMF_EXTENDEDVERBS
+#define CMF_EXTENDEDVERBS 0x00000100
+#endif
+static void DoAnnoyingShellCommand(HWND hwnd,const char *szFilename,int cmd,POINT *ptCursor)
+{
+ IMalloc *pShellMalloc;
+
+ OleInitialize(NULL);
+ if(SHGetMalloc(&pShellMalloc)==NOERROR) {
+ IShellFolder *pDesktopFolder;
+ if(SHGetDesktopFolder(&pDesktopFolder)==NOERROR) {
+ WCHAR wszFilename[MAX_PATH];
+ ITEMIDLIST *pCurrentIdl;
+ MultiByteToWideChar(CP_ACP,0,szFilename,-1,wszFilename,SIZEOF(wszFilename));
+ if(pDesktopFolder->lpVtbl->ParseDisplayName(pDesktopFolder,NULL,NULL,wszFilename,NULL,&pCurrentIdl,NULL)==NOERROR) {
+ if(pCurrentIdl->mkid.cb) {
+ ITEMIDLIST *pidl,*pidlNext,*pidlFilename;
+ IShellFolder *pFileFolder;
+
+ for(pidl=pCurrentIdl;;) {
+ pidlNext=(ITEMIDLIST*)((PBYTE)pidl+pidl->mkid.cb);
+ if(pidlNext->mkid.cb==0) {
+ pidlFilename=pShellMalloc->lpVtbl->Alloc(pShellMalloc,pidl->mkid.cb+sizeof(pidl->mkid.cb));
+ CopyMemory(pidlFilename,pidl,pidl->mkid.cb+sizeof(pidl->mkid.cb));
+ pidl->mkid.cb=0;
+ break;
+ }
+ pidl=pidlNext;
+ }
+ if(pDesktopFolder->lpVtbl->BindToObject(pDesktopFolder,pCurrentIdl,NULL,&IID_IShellFolder,&pFileFolder)==NOERROR) {
+ IContextMenu *pContextMenu;
+ if(pFileFolder->lpVtbl->GetUIObjectOf(pFileFolder,NULL,1,&pidlFilename,&IID_IContextMenu,NULL,&pContextMenu)==NOERROR) {
+ switch(cmd) {
+ case C_PROPERTIES:
+ { CMINVOKECOMMANDINFO ici={0};
+ ici.cbSize=sizeof(ici);
+ ici.hwnd=hwnd;
+ ici.lpVerb="properties";
+ ici.nShow=SW_SHOW;
+ pContextMenu->lpVtbl->InvokeCommand(pContextMenu,&ici);
+ break;
+ }
+ case C_CONTEXTMENU:
+ { HMENU hMenu;
+ hMenu=CreatePopupMenu();
+ if(SUCCEEDED(pContextMenu->lpVtbl->QueryContextMenu(pContextMenu,hMenu,0,1000,65535,(GetKeyState(VK_SHIFT)&0x8000?CMF_EXTENDEDVERBS:0)|CMF_NORMAL))) {
+ int cmd;
+ cmd=TrackPopupMenu(hMenu,TPM_RETURNCMD,ptCursor->x,ptCursor->y,0,hwnd,NULL);
+ if(cmd) {
+ CMINVOKECOMMANDINFO ici={0};
+ ici.cbSize=sizeof(ici);
+ ici.hwnd=hwnd;
+ ici.lpVerb=MAKEINTRESOURCEA(cmd-1000);
+ ici.nShow=SW_SHOW;
+ pContextMenu->lpVtbl->InvokeCommand(pContextMenu,&ici);
+ }
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+ }
+ pContextMenu->lpVtbl->Release(pContextMenu);
+ }
+ pFileFolder->lpVtbl->Release(pFileFolder);
+ }
+ pShellMalloc->lpVtbl->Free(pShellMalloc,pidlFilename);
+ }
+ pShellMalloc->lpVtbl->Free(pShellMalloc,pCurrentIdl);
+ }
+ pDesktopFolder->lpVtbl->Release(pDesktopFolder);
+ }
+ pShellMalloc->lpVtbl->Release(pShellMalloc);
+ }
+ OleUninitialize();
+}
+
+static WNDPROC pfnIconWindowProc;
+static LRESULT CALLBACK IconCtrlSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_LBUTTONDBLCLK:
+ ShellExecuteA(hwnd,NULL,((PROTOFILETRANSFERSTATUS*)GetWindowLong(GetParent(hwnd),GWL_USERDATA))->currentFile,NULL,NULL,SW_SHOW);
+ break;
+ case WM_RBUTTONUP:
+ { POINT pt;
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwnd,&pt);
+ DoAnnoyingShellCommand(hwnd,((PROTOFILETRANSFERSTATUS*)GetWindowLong(GetParent(hwnd),GWL_USERDATA))->currentFile,C_CONTEXTMENU,&pt);
+ return 0;
+ }
+ }
+ return CallWindowProc(pfnIconWindowProc,hwnd,msg,wParam,lParam);
+}
+
+struct loadiconsstartinfo {
+ HWND hwndDlg;
+ char *szFilename;
+};
+void __cdecl LoadIconsAndTypesThread(struct loadiconsstartinfo *info)
+{
+ SHFILEINFOA fileInfo;
+
+ OleInitialize(NULL);
+ if(SHGetFileInfoA(info->szFilename,0,&fileInfo,sizeof(fileInfo),SHGFI_TYPENAME|SHGFI_ICON|SHGFI_LARGEICON)) {
+ char *pszExtension,*pszFilename;
+ char szExtension[64];
+ char szIconFile[MAX_PATH];
+
+ pszFilename=strrchr(info->szFilename,'\\');
+ if(pszFilename==NULL) pszFilename=info->szFilename;
+ pszExtension=strrchr(pszFilename,'.');
+ if(pszExtension) lstrcpynA(szExtension,pszExtension+1,SIZEOF(szExtension));
+ else {pszExtension="."; szExtension[0]='\0';}
+ CharUpperA(szExtension);
+ if(fileInfo.szTypeName[0]=='\0')
+ wsprintfA(fileInfo.szTypeName,Translate("%s File"),szExtension);
+ SetDlgItemTextA(info->hwndDlg,IDC_EXISTINGTYPE,fileInfo.szTypeName);
+ SetDlgItemTextA(info->hwndDlg,IDC_NEWTYPE,fileInfo.szTypeName);
+ SendDlgItemMessage(info->hwndDlg,IDC_EXISTINGICON,STM_SETICON,(WPARAM)fileInfo.hIcon,0);
+ szIconFile[0]='\0';
+ if(!lstrcmpA(szExtension,"EXE")) {
+ SRFile_GetRegValue(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons","2",szIconFile,SIZEOF(szIconFile));
+ }
+ else {
+ char szTypeName[MAX_PATH];
+ if(SRFile_GetRegValue(HKEY_CLASSES_ROOT,pszExtension,NULL,szTypeName,SIZEOF(szTypeName))) {
+ lstrcatA(szTypeName,"\\DefaultIcon");
+ if(SRFile_GetRegValue(HKEY_CLASSES_ROOT,szTypeName,NULL,szIconFile,SIZEOF(szIconFile))) {
+ if(strstr(szIconFile,"%1"))
+ SRFile_GetRegValue(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons","0",szIconFile,SIZEOF(szIconFile));
+ else szIconFile[0]='\0';
+ }
+ }
+ }
+ if(szIconFile[0]) {
+ int iconIndex;
+ HICON hIcon;
+ char *pszComma=strrchr(szIconFile,',');
+ if(pszComma==NULL) iconIndex=0;
+ else {iconIndex=atoi(pszComma+1); *pszComma='\0';}
+ hIcon=ExtractIconA(GetModuleHandle(NULL),szIconFile,iconIndex);
+ if(hIcon) fileInfo.hIcon=hIcon;
+ }
+ SendDlgItemMessage(info->hwndDlg,IDC_NEWICON,STM_SETICON,(WPARAM)fileInfo.hIcon,0);
+ }
+ OleUninitialize();
+ mir_free(info->szFilename);
+ mir_free(info);
+}
+
+BOOL CALLBACK DlgProcFileExists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PROTOFILETRANSFERSTATUS *fts;
+
+ fts=(PROTOFILETRANSFERSTATUS*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch(msg) {
+ case WM_INITDIALOG:
+ { TCHAR szSize[64];
+ struct _stat statbuf;
+ struct loadiconsstartinfo *lisi;
+ HWND hwndFocus;
+
+ SetPropA(hwndDlg,"Miranda.Preshutdown",HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN));
+
+ TranslateDialogDefault(hwndDlg);
+ fts=(PROTOFILETRANSFERSTATUS*)mir_alloc(sizeof(PROTOFILETRANSFERSTATUS));
+ CopyProtoFileTransferStatus(fts,(PROTOFILETRANSFERSTATUS*)lParam);
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)fts);
+ SetDlgItemTextA(hwndDlg,IDC_FILENAME,fts->currentFile);
+ SetControlToUnixTime(hwndDlg,IDC_NEWDATE,fts->currentFileTime);
+ GetSensiblyFormattedSize(fts->currentFileSize,szSize,SIZEOF(szSize),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_NEWSIZE,szSize);
+
+ pfnIconWindowProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_EXISTINGICON),GWL_WNDPROC,(LONG)IconCtrlSubclassProc);
+
+ hwndFocus=GetDlgItem(hwndDlg,IDC_RESUME);
+ if(_stat(fts->currentFile,&statbuf)==0) {
+ SetControlToUnixTime(hwndDlg,IDC_EXISTINGDATE,statbuf.st_mtime);
+ GetSensiblyFormattedSize(statbuf.st_size,szSize,SIZEOF(szSize),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_EXISTINGSIZE,szSize);
+ if(statbuf.st_size>(int)fts->currentFileSize) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_RESUME),FALSE);
+ hwndFocus=GetDlgItem(hwndDlg,IDC_OVERWRITE);
+ }
+ }
+ lisi=(struct loadiconsstartinfo*)mir_alloc(sizeof(struct loadiconsstartinfo));
+ lisi->hwndDlg=hwndDlg;
+ lisi->szFilename=mir_strdup(fts->currentFile);
+ //can be a little slow, so why not?
+ forkthread(LoadIconsAndTypesThread,0,lisi);
+ SetFocus(hwndFocus);
+ SetWindowLong(hwndFocus,GWL_STYLE,GetWindowLong(hwndFocus,GWL_STYLE)|BS_DEFPUSHBUTTON);
+ return FALSE;
+ }
+ case WM_COMMAND:
+ { PROTOFILERESUME pfr={0};
+ switch(LOWORD(wParam)) {
+ case IDC_OPENFILE:
+ ShellExecuteA(hwndDlg,NULL,fts->currentFile,NULL,NULL,SW_SHOW);
+ return FALSE;
+ case IDC_OPENFOLDER:
+ { char szFile[MAX_PATH];
+ char *pszLastBackslash;
+ lstrcpynA(szFile,fts->currentFile,SIZEOF(szFile));
+ pszLastBackslash=strrchr(szFile,'\\');
+ if(pszLastBackslash) *pszLastBackslash='\0';
+ ShellExecuteA(hwndDlg,NULL,szFile,NULL,NULL,SW_SHOW);
+ return FALSE;
+ }
+ case IDC_PROPERTIES:
+ DoAnnoyingShellCommand(hwndDlg,fts->currentFile,C_PROPERTIES,NULL);
+ return FALSE;
+ case IDC_RESUME:
+ pfr.action=FILERESUME_RESUME;
+ break;
+ case IDC_RESUMEALL:
+ pfr.action=FILERESUME_RESUMEALL;
+ break;
+ case IDC_OVERWRITE:
+ pfr.action=FILERESUME_OVERWRITE;
+ break;
+ case IDC_OVERWRITEALL:
+ pfr.action=FILERESUME_OVERWRITEALL;
+ break;
+ case IDC_SAVEAS:
+ { OPENFILENAMEA ofn={0};
+ char filter[512],*pfilter;
+ char str[MAX_PATH];
+
+ lstrcpynA(str,fts->currentFile,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY;
+ strcpy(filter,Translate("All Files"));
+ strcat(filter," (*)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str);
+ ofn.nMaxFileTitle=MAX_PATH;
+ if(!GetSaveFileNameA(&ofn)) break;
+ pfr.szFilename=mir_strdup(str);
+ pfr.action=FILERESUME_RENAME;
+ break;
+ }
+ case IDC_SKIP:
+ pfr.action=FILERESUME_SKIP;
+ break;
+ case IDCANCEL:
+ pfr.action=FILERESUME_CANCEL;
+ break;
+ default:
+ return FALSE;
+ }
+ { PROTOFILERESUME *pfrCopy;
+ pfrCopy=(PROTOFILERESUME*)mir_alloc(sizeof(pfr));
+ CopyMemory(pfrCopy,&pfr,sizeof(pfr));
+ PostMessage(GetParent(hwndDlg),M_FILEEXISTSDLGREPLY,(WPARAM)mir_strdup(fts->currentFile),(LPARAM)pfrCopy);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+ case WM_CLOSE:
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDCANCEL));
+ break;
+ case M_PRESHUTDOWN:
+ {
+ PostMessage(hwndDlg,WM_CLOSE,0,0);
+ break;
+ }
+ case WM_DESTROY:
+ UnhookEvent(GetPropA(hwndDlg,"Miranda.Preshutdown")); // GetProp() will return NULL if it couldnt find anything
+ DestroyIcon((HICON)SendDlgItemMessage(hwndDlg,IDC_EXISTINGICON,STM_GETICON,0,0));
+ DestroyIcon((HICON)SendDlgItemMessage(hwndDlg,IDC_NEWICON,STM_GETICON,0,0));
+ FreeProtoFileTransferStatus(fts);
+ mir_free(fts);
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srfile/fileopts.c b/miranda-wine/src/modules/srfile/fileopts.c new file mode 100644 index 0000000..3208f89 --- /dev/null +++ b/miranda-wine/src/modules/srfile/fileopts.c @@ -0,0 +1,227 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "file.h"
+
+#define VSCAN_MCAFEE 1
+#define VSCAN_DRSOLOMON 2
+#define VSCAN_NORTON 3
+#define VSCAN_CA 4
+
+struct virusscannerinfo {
+ char *szProductName;
+ char *szExeRegPath;
+ char *szExeRegValue;
+ char *szCommandLine;
+};
+
+static struct virusscannerinfo virusScanners[]={
+ {"Network Associates/McAfee VirusScan","SOFTWARE\\McAfee\\VirusScan","Scan32EXE","\"%s\" %%f /nosplash /comp /autoscan /autoexit /noboot"},
+ {"Dr Solomon's VirusScan (Network Associates)","SOFTWARE\\Network Associates\\TVD\\VirusScan\\AVConsol\\General","szScannerExe","\"%s\" %%f /uinone /noboot /comp /prompt /autoexit"},
+ {"Norton AntiVirus","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Navw32.exe",NULL,"\"%s\" %%f /b- /m- /s+ /noresults"},
+ {"Computer Associates/Inoculate IT","Software\\Antivirus","ImageFilename","\"%s\" %%f /display=progress /exit"},
+ {"Computer Associates eTrust","SOFTWARE\\ComputerAssociates\\Anti-Virus\\Resident","VetPath","\"%s\" %%f /display=progress /exit"},
+ {"Kaspersky Anti-Virus","SOFTWARE\\KasperskyLab\\Components\\101","EXEName","\"%s\" /S /Q %%f"},
+};
+
+#define M_UPDATEENABLING (WM_USER+100)
+#define M_SCANCMDLINESELCHANGE (WM_USER+101)
+static BOOL CALLBACK DlgProcFileOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { DBVARIANT dbv;
+
+ TranslateDialogDefault(hwndDlg);
+ {
+ char str[MAX_PATH];
+ GetContactReceivedFilesDir(NULL,str,SIZEOF(str));
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,str);
+ }
+ { HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
+
+ MySHAutoComplete=(HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+ if(MySHAutoComplete) MySHAutoComplete(GetWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),GW_CHILD),1);
+ }
+ CheckDlgButton(hwndDlg, IDC_AUTOACCEPT, DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOMIN, DBGetContactSettingByte(NULL,"SRFile","AutoMin",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOCLOSE, DBGetContactSettingByte(NULL,"SRFile","AutoClose",0) ? BST_CHECKED : BST_UNCHECKED);
+ switch(DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE)) {
+ case VIRUSSCAN_AFTERDL: CheckDlgButton(hwndDlg, IDC_SCANAFTERDL, BST_CHECKED); break;
+ case VIRUSSCAN_DURINGDL: CheckDlgButton(hwndDlg, IDC_SCANDURINGDL, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_NOSCANNER, BST_CHECKED); break;
+ }
+ CheckDlgButton(hwndDlg, IDC_WARNBEFOREOPENING, DBGetContactSettingByte(NULL,"SRFile","WarnBeforeOpening",1) ? BST_CHECKED : BST_UNCHECKED);
+ { char szScanExe[MAX_PATH];
+ int i,iItem;
+ for( i=0; i < SIZEOF(virusScanners); i++ ) {
+ if(SRFile_GetRegValue(HKEY_LOCAL_MACHINE,virusScanners[i].szExeRegPath,virusScanners[i].szExeRegValue,szScanExe,SIZEOF(szScanExe))) {
+ iItem=SendDlgItemMessageA(hwndDlg,IDC_SCANCMDLINE,CB_ADDSTRING,0,(LPARAM)virusScanners[i].szProductName);
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETITEMDATA,iItem,i);
+ }
+ }
+ }
+ if(DBGetContactSetting(NULL,"SRFile","ScanCmdLine",&dbv)==0) {
+ SetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else {
+ if(SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETCOUNT,0,0)) {
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETCURSEL,0,0);
+ PostMessage(hwndDlg,M_SCANCMDLINESELCHANGE,0,0);
+ }
+ }
+ switch(DBGetContactSettingByte(NULL,"SRFile","IfExists",FILERESUME_ASK)) {
+ case FILERESUME_RESUMEALL: CheckDlgButton(hwndDlg, IDC_RESUME, BST_CHECKED); break;
+ case FILERESUME_OVERWRITEALL: CheckDlgButton(hwndDlg, IDC_OVERWRITE, BST_CHECKED); break;
+ case FILERESUME_RENAMEALL: CheckDlgButton(hwndDlg, IDC_RENAME, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_ASK, BST_CHECKED); break;
+ }
+ SendMessage(hwndDlg,M_UPDATEENABLING,0,0);
+ return TRUE;
+ }
+ case M_UPDATEENABLING:
+ { int on=!IsDlgButtonChecked(hwndDlg,IDC_NOSCANNER);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ST_CMDLINE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SCANCMDLINE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SCANCMDLINEBROWSE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ST_CMDLINEHELP),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOMIN),IsDlgButtonChecked(hwndDlg,IDC_AUTOACCEPT));
+ break;
+ }
+ case M_SCANCMDLINESELCHANGE:
+ { char str[512],szScanExe[MAX_PATH];
+ int iScanner=SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETCURSEL,0,0),0);
+ if(iScanner >= SIZEOF(virusScanners) || iScanner<0) break;
+ str[0]='\0';
+ if(SRFile_GetRegValue(HKEY_LOCAL_MACHINE,virusScanners[iScanner].szExeRegPath,virusScanners[iScanner].szExeRegValue,szScanExe,SIZEOF(szScanExe)))
+ wsprintfA(str,virusScanners[iScanner].szCommandLine,szScanExe);
+ SetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str);
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_FILEDIR:
+ if((HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) return 0;
+ break;
+ case IDC_FILEDIRBROWSE:
+ { char str[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,str,SIZEOF(str));
+ if(BrowseForFolder(hwndDlg,str))
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,str);
+ break;
+ }
+ case IDC_AUTOACCEPT:
+ case IDC_NOSCANNER:
+ case IDC_SCANAFTERDL:
+ case IDC_SCANDURINGDL:
+ SendMessage(hwndDlg,M_UPDATEENABLING,0,0);
+ break;
+ case IDC_SCANCMDLINE:
+ if(HIWORD(wParam)==CBN_SELCHANGE) PostMessage(hwndDlg,M_SCANCMDLINESELCHANGE,0,0);
+ else if(HIWORD(wParam)!=CBN_EDITCHANGE) return 0;
+ break;
+ case IDC_SCANCMDLINEBROWSE:
+ { char str[MAX_PATH+2];
+ OPENFILENAMEA ofn={0};
+ char filter[512],*pfilter;
+
+ GetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ strcpy(filter,Translate("Executable Files"));
+ strcat(filter," (*.exe)");
+ pfilter=filter+strlen(filter)+1;
+ strcpy(pfilter,"*.exe");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,Translate("All Files"));
+ strcat(pfilter," (*)");
+ pfilter=pfilter+strlen(pfilter)+1;
+ strcpy(pfilter,"*");
+ pfilter=pfilter+strlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str)-2;
+ if(str[0]=='"') {
+ char *pszQuote=strchr(str+1,'"');
+ if(pszQuote) *pszQuote='\0';
+ MoveMemory(str,str+1,lstrlenA(str));
+ }
+ else {
+ char *pszSpace=strchr(str,' ');
+ if(pszSpace) *pszSpace='\0';
+ }
+ ofn.nMaxFileTitle=MAX_PATH;
+ if(!GetOpenFileNameA(&ofn)) break;
+ if(strchr(str,' ')!=NULL) {
+ MoveMemory(str+1,str,SIZEOF(str)-2);
+ str[0]='"';
+ lstrcatA(str,"\"");
+ }
+ SetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str);
+ break;
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { char str[512];
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,str,SIZEOF(str));
+ DBWriteContactSettingString(NULL,"SRFile","RecvFilesDirAdv",str);
+ DBWriteContactSettingByte(NULL,"SRFile","AutoAccept",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOACCEPT));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoMin",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOMIN));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoClose",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOCLOSE));
+ DBWriteContactSettingByte(NULL,"SRFile","UseScanner",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_SCANAFTERDL)?VIRUSSCAN_AFTERDL:(IsDlgButtonChecked(hwndDlg,IDC_SCANDURINGDL)?VIRUSSCAN_DURINGDL:VIRUSSCAN_DISABLE)));
+ GetDlgItemTextA(hwndDlg,IDC_SCANCMDLINE,str,SIZEOF(str));
+ DBWriteContactSettingString(NULL,"SRFile","ScanCmdLine",str);
+ DBWriteContactSettingByte(NULL,"SRFile","WarnBeforeOpening",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_WARNBEFOREOPENING));
+ DBWriteContactSettingByte(NULL,"SRFile","IfExists",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_ASK)?FILERESUME_ASK:(IsDlgButtonChecked(hwndDlg,IDC_RESUME)?FILERESUME_RESUMEALL:(IsDlgButtonChecked(hwndDlg,IDC_OVERWRITE)?FILERESUME_OVERWRITEALL:FILERESUME_RENAMEALL))));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int FileOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FILETRANSFER);
+ odp.pszTitle = "File Transfers";
+ odp.pszGroup = "Events";
+ odp.pfnDlgProc = DlgProcFileOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = IDC_VIRUSSCANNERGROUP;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
diff --git a/miranda-wine/src/modules/srfile/filerecvdlg.c b/miranda-wine/src/modules/srfile/filerecvdlg.c new file mode 100644 index 0000000..602cb2c --- /dev/null +++ b/miranda-wine/src/modules/srfile/filerecvdlg.c @@ -0,0 +1,431 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <shlobj.h>
+#include "file.h"
+
+#define MAX_MRU_DIRS 5
+
+static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd,LPARAM lParam)
+{
+ SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS);
+ return TRUE;
+}
+
+static void GetLowestExistingDirName(const char *szTestDir,char *szExistingDir,int cchExistingDir)
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash;
+
+ lstrcpynA(szExistingDir,szTestDir,cchExistingDir);
+ while((dwAttributes=GetFileAttributesA(szExistingDir))!=0xffffffff && !(dwAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
+ pszLastBackslash=strrchr(szExistingDir,'\\');
+ if(pszLastBackslash==NULL) {*szExistingDir='\0'; break;}
+ *pszLastBackslash='\0';
+ }
+ if(szExistingDir[0]=='\0') GetCurrentDirectoryA(cchExistingDir,szExistingDir);
+}
+
+static const char validFilenameChars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!&{}-=#@~,. ";
+static void RemoveInvalidFilenameChars(char *szString)
+{
+ int i;
+ for(i=strspn(szString,validFilenameChars);szString[i];i+=strspn(szString+i+1,validFilenameChars)+1)
+ if(szString[i]>=0) szString[i]='%';
+}
+
+static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
+{
+ char szDir[MAX_PATH];
+ switch(uMsg) {
+ case BFFM_INITIALIZED:
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData);
+ break;
+ case BFFM_SELCHANGED:
+ if (SHGetPathFromIDListA((LPITEMIDLIST) lp ,szDir))
+ SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
+ break;
+ }
+ return 0;
+}
+
+int BrowseForFolder(HWND hwnd,char *szPath)
+{
+ BROWSEINFOA bi={0};
+ LPMALLOC pMalloc;
+ ITEMIDLIST *pidlResult;
+ int result=0;
+
+ if(SUCCEEDED(OleInitialize(NULL))) {
+ if(SUCCEEDED(CoGetMalloc(1,&pMalloc))) {
+ bi.hwndOwner=hwnd;
+ bi.pszDisplayName=szPath;
+ bi.lpszTitle=Translate("Select Folder");
+ bi.ulFlags=BIF_NEWDIALOGSTYLE|BIF_EDITBOX|BIF_RETURNONLYFSDIRS; // Use this combo instead of BIF_USENEWUI
+ bi.lpfn=BrowseCallbackProc;
+ bi.lParam=(LPARAM)szPath;
+
+ pidlResult=SHBrowseForFolderA(&bi);
+ if(pidlResult) {
+ SHGetPathFromIDListA(pidlResult,szPath);
+ lstrcatA(szPath,"\\");
+ result=1;
+ }
+ pMalloc->lpVtbl->Free(pMalloc,pidlResult);
+ pMalloc->lpVtbl->Release(pMalloc);
+ }
+ OleUninitialize();
+ }
+ return result;
+}
+
+static void ReplaceStr(char str[], int len, char *from, char *to) {
+ char *tmp;
+
+ if (tmp=strstr(str, from)) {
+ int pos = tmp - str;
+ int tlen = lstrlenA(from);
+
+ tmp = mir_strdup(str);
+ if (lstrlenA(to)>tlen)
+ tmp = (char*)mir_realloc(tmp, lstrlenA(tmp)+1+lstrlenA(to)-tlen);
+
+ MoveMemory(tmp+pos+lstrlenA(to), tmp+pos+tlen, lstrlenA(tmp)+1-pos-tlen);
+ CopyMemory(tmp+pos, to, lstrlenA(to));
+ mir_snprintf(str, len, "%s", tmp);
+ mir_free(tmp);
+ }
+}
+
+void GetContactReceivedFilesDir(HANDLE hContact,char *szDir,int cchDir)
+{
+ DBVARIANT dbv;
+ char *szRecvFilesDir, szTemp[MAX_PATH];
+ int len;
+
+ if(DBGetContactSetting(NULL,"SRFile","RecvFilesDirAdv",&dbv)||lstrlenA(dbv.pszVal)==0) {
+ char szDbPath[MAX_PATH];
+
+ CallService(MS_DB_GETPROFILEPATH,(WPARAM)MAX_PATH,(LPARAM)szDbPath);
+ lstrcatA(szDbPath,"\\");
+ lstrcatA(szDbPath,Translate("Received Files"));
+ lstrcatA(szDbPath,"\\%userid%");
+ szRecvFilesDir=mir_strdup(szDbPath);
+ }
+ else {
+ char szDrive[_MAX_DRIVE];
+ _splitpath(dbv.pszVal, szDrive, NULL, NULL, NULL);
+ if ( szDrive[0] == 0 && memcmp( dbv.pszVal, "\\\\", 2 ) != 0 ) {
+ char szDbPath[MAX_PATH];
+ CallService(MS_DB_GETPROFILEPATH,(WPARAM)MAX_PATH,(LPARAM)szDbPath);
+ lstrcatA(szDbPath,"\\");
+ lstrcatA(szDbPath,dbv.pszVal);
+ szRecvFilesDir=mir_strdup(szDbPath);
+ }
+ else szRecvFilesDir=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ lstrcpynA(szTemp,szRecvFilesDir,SIZEOF(szTemp));
+ if (hContact) {
+ CONTACTINFO ci;
+ char szNick[64];
+ char szUsername[64];
+ char szProto[64];
+
+ szNick[0] = '\0';
+ szUsername[0] = '\0';
+ szProto[0] = '\0';
+
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ ci.szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ ci.dwFlag = CNF_UNIQUEID;
+ mir_snprintf(szProto, SIZEOF(szProto), "%s", ci.szProto);
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_snprintf(szUsername, SIZEOF(szUsername), "%s", ci.pszVal);
+ miranda_sys_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_snprintf(szUsername, SIZEOF(szUsername), "%u", ci.dVal);
+ break;
+ } }
+
+ mir_snprintf(szNick, SIZEOF(szNick), "%s", (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+ if (lstrlenA(szUsername)==0)
+ mir_snprintf(szUsername, SIZEOF(szUsername), "%s", (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+
+ RemoveInvalidFilenameChars(szNick);
+ RemoveInvalidFilenameChars(szUsername);
+ RemoveInvalidFilenameChars(szProto);
+ ReplaceStr(szTemp, SIZEOF(szTemp), "%nick%", szNick);
+ ReplaceStr(szTemp, SIZEOF(szTemp), "%userid%", szUsername);
+ ReplaceStr(szTemp, SIZEOF(szTemp), "%proto%", szProto);
+ }
+ lstrcpynA(szDir,szTemp,cchDir);
+ mir_free(szRecvFilesDir);
+ len=lstrlenA(szDir);
+ if(len+1<cchDir && szDir[len-1]!='\\') lstrcpyA(szDir+len,"\\");
+}
+
+BOOL CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat;
+
+ dat=(struct FileDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TCHAR *contactName;
+ char szPath[450];
+
+ TranslateDialogDefault(hwndDlg);
+
+ dat=(struct FileDlgData*)mir_calloc(sizeof(struct FileDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hContact=((CLISTEVENT*)lParam)->hContact;
+ dat->hDbEvent=((CLISTEVENT*)lParam)->hDbEvent;
+ dat->hPreshutdownEvent=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN);
+ dat->dwTicks=GetTickCount();
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE));
+ EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0);
+ dat->hUIIcons[0]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[1]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[2]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[3]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[3]);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ SetDlgItemText(hwndDlg,IDC_FROM,contactName);
+ GetContactReceivedFilesDir(dat->hContact,szPath,SIZEOF(szPath));
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,szPath);
+ { int i;
+ char idstr[32];
+ DBVARIANT dbv;
+ HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
+
+ MySHAutoComplete=(HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+ if(MySHAutoComplete) MySHAutoComplete(GetWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),GW_CHILD),1);
+ for(i=0;i<MAX_MRU_DIRS;i++) {
+ wsprintfA(idstr,"MruDir%d",i);
+ if(DBGetContactSetting(NULL,"SRFile",idstr,&dbv)) break;
+ SendDlgItemMessageA(hwndDlg,IDC_FILEDIR,CB_ADDSTRING,0,(LPARAM)dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)dat->hContact,(LPARAM)dat->hDbEvent);
+
+ { DBEVENTINFO dbei={0};
+ DBTIMETOSTRINGT dbtts;
+ TCHAR datetimestr[64];
+
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei);
+ dat->fs=(HANDLE)*(PDWORD)dbei.pBlob;
+ lstrcpynA(szPath, dbei.pBlob+4, min(dbei.cbBlob+1,SIZEOF(szPath)));
+ SetDlgItemTextA(hwndDlg,IDC_FILENAMES,szPath);
+ lstrcpynA(szPath, dbei.pBlob+4+strlen(dbei.pBlob+4)+1, min(dbei.cbBlob-4-strlen(dbei.pBlob+4),SIZEOF(szPath)));
+ SetDlgItemTextA(hwndDlg,IDC_MSG,szPath);
+ mir_free(dbei.pBlob);
+
+ dbtts.szFormat = _T("t d");
+ dbtts.szDest = datetimestr;
+ dbtts.cbDest = SIZEOF(datetimestr);
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp, ( LPARAM )&dbtts);
+ SetDlgItemText(hwndDlg, IDC_DATE, datetimestr);
+ }
+ { char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ } }
+ if (hasName)
+ SetDlgItemTextA(hwndDlg, IDC_NAME, buf );
+ else
+ SetDlgItemText(hwndDlg, IDC_NAME, contactName);
+ } }
+
+ if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ RECT rcBtn1,rcBtn2,rcDateCtrl;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_ADD),&rcBtn1);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rcBtn2);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_DATE),&rcDateCtrl);
+ SetWindowPos(GetDlgItem(hwndDlg,IDC_DATE),0,0,0,rcDateCtrl.right-rcDateCtrl.left-(rcBtn2.left-rcBtn1.left),rcDateCtrl.bottom-rcDateCtrl.top,SWP_NOZORDER|SWP_NOMOVE);
+ }
+ else if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0)) {
+ //don't check auto-min here to fix BUG#647620
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK));
+ }
+ if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD),SW_HIDE);
+ return TRUE;
+ }
+ case M_FILEEXISTSDLGREPLY:
+ return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ } } }
+
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+ case WM_COMMAND:
+ if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)dat->hContact ))
+ break;
+
+ switch ( LOWORD( wParam )) {
+ case IDC_FILEDIRBROWSE:
+ {
+ char szDirName[MAX_PATH],szExistingDirName[MAX_PATH];
+
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,szDirName,SIZEOF(szDirName));
+ GetLowestExistingDirName(szDirName,szExistingDirName,SIZEOF(szExistingDirName));
+ if(BrowseForFolder(hwndDlg,szExistingDirName))
+ SetDlgItemTextA(hwndDlg,IDC_FILEDIR,szExistingDirName);
+ return TRUE;
+ }
+ case IDOK:
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ { //most recently used directories
+ char szRecvDir[MAX_PATH],szDefaultRecvDir[MAX_PATH];
+ GetDlgItemTextA(hwndDlg,IDC_FILEDIR,szRecvDir,SIZEOF(szRecvDir));
+ GetContactReceivedFilesDir(NULL,szDefaultRecvDir,SIZEOF(szDefaultRecvDir));
+ if(_strnicmp(szRecvDir,szDefaultRecvDir,lstrlenA(szDefaultRecvDir))) {
+ char idstr[32];
+ int i;
+ DBVARIANT dbv;
+ for(i=MAX_MRU_DIRS-2;i>=0;i--) {
+ wsprintfA(idstr,"MruDir%d",i);
+ if(DBGetContactSetting(NULL,"SRFile",idstr,&dbv)) continue;
+ wsprintfA(idstr,"MruDir%d",i+1);
+ DBWriteContactSettingString(NULL,"SRFile",idstr,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ DBWriteContactSettingString(NULL,"SRFile",idstr,szRecvDir);
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAMES),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIRBROWSE),FALSE);
+ dat->hwndTransfer=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILETRANSFERINFO),hwndDlg,DlgProcFileTransfer);
+ //check for auto-minimize here to fix BUG#647620
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && DBGetContactSettingByte(NULL,"SRFile","AutoMin",0))
+ ShowWindow(hwndDlg,SW_SHOWMINIMIZED);
+ return TRUE;
+ case IDCANCEL:
+ if (dat->fs) CallContactService(dat->hContact,PSS_FILEDENY,(WPARAM)dat->fs,(LPARAM)Translate("Cancelled"));
+ dat->fs=NULL; /* the protocol will free the handle */
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD), SW_HIDE);
+ return TRUE;
+ }
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ break;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ return TRUE;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ return TRUE;
+ }
+ break;
+
+ case M_PRESHUTDOWN:
+ if (IsWindow(dat->hwndTransfer)) PostMessage(dat->hwndTransfer,WM_CLOSE,0,0);
+ break;
+
+ case WM_DESTROY:
+ if(dat->hPreshutdownEvent) UnhookEvent(dat->hPreshutdownEvent);
+ if(dat->hwndTransfer) DestroyWindow(dat->hwndTransfer);
+ DestroyIcon(dat->hUIIcons[3]);
+ DestroyIcon(dat->hUIIcons[2]);
+ DestroyIcon(dat->hUIIcons[1]);
+ DestroyIcon(dat->hUIIcons[0]);
+ mir_free(dat);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srfile/filesenddlg.c b/miranda-wine/src/modules/srfile/filesenddlg.c new file mode 100644 index 0000000..fe6ada6 --- /dev/null +++ b/miranda-wine/src/modules/srfile/filesenddlg.c @@ -0,0 +1,380 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+static void SetFileListAndSizeControls(HWND hwndDlg,struct FileDlgData *dat)
+{
+ int fileCount=0,dirCount=0,totalSize=0,i;
+ struct _stat statbuf;
+ TCHAR str[64];
+
+ for(i=0;dat->files[i];i++) {
+ if(_stat(dat->files[i],&statbuf)==0) {
+ if(statbuf.st_mode&_S_IFDIR) dirCount++;
+ else fileCount++;
+ totalSize+=statbuf.st_size;
+ }
+ }
+ GetSensiblyFormattedSize(totalSize,str,SIZEOF(str),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_TOTALSIZE,str);
+ if(i>1) {
+ TCHAR szFormat[32];
+ if(fileCount && dirCount) {
+ mir_sntprintf(szFormat,SIZEOF(szFormat),_T("%s, %s"),TranslateTS(fileCount==1?_T("%d file"):_T("%d files")),TranslateTS(dirCount==1?_T("%d directory"):_T("%d directories")));
+ mir_sntprintf(str,SIZEOF(str),szFormat,fileCount,dirCount);
+ }
+ else if(fileCount) {
+ lstrcpy(szFormat,TranslateT("%d files"));
+ mir_sntprintf(str,SIZEOF(str),szFormat,fileCount);
+ }
+ else {
+ lstrcpy(szFormat,TranslateT("%d directories"));
+ mir_sntprintf(str,SIZEOF(str),szFormat,dirCount);
+ }
+ SetDlgItemText(hwndDlg,IDC_FILE,str);
+ }
+ else SetDlgItemTextA(hwndDlg,IDC_FILE,dat->files[0]);
+}
+
+static void FilenameToFileList(HWND hwndDlg, struct FileDlgData* dat, const TCHAR* buf)
+{
+ DWORD dwFileAttributes;
+
+ // Make sure that the file matrix is empty (the user may select files several times)
+ FreeFilesMatrix(&dat->files);
+
+ // Get the file attributes of selection
+ dwFileAttributes = GetFileAttributes( buf );
+ if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
+ return;
+
+ // Check if the selection is a directory or a file
+ if ( GetFileAttributes( buf ) & FILE_ATTRIBUTE_DIRECTORY ) {
+ const TCHAR* pBuf;
+ int nNumberOfFiles = 0;
+ int nTemp;
+ int fileOffset;
+
+ // :NOTE: The first string in the buffer is the directory, followed by a
+ // NULL separated list of all files
+
+ // fileOffset is the offset to the first file.
+ fileOffset = lstrlen(buf) + 1;
+
+ // Count number of files
+ pBuf = buf + fileOffset;
+ while ( *pBuf ) {
+ pBuf += lstrlen(pBuf) + 1;
+ nNumberOfFiles++;
+ }
+
+ // Allocate memory for a pointer array
+ if (( dat->files = (char**)mir_alloc((nNumberOfFiles + 1) * sizeof(char*))) == NULL )
+ return;
+
+ // Fill the array
+ pBuf = buf + fileOffset;
+ nTemp = 0;
+ while(*pBuf)
+ {
+ // Allocate space for path+filename
+ int cbFileNameLen = lstrlen( pBuf );
+ dat->files[nTemp] = mir_alloc(fileOffset + cbFileNameLen + 1);
+
+ // Add path to filename and copy into array
+ #if defined( _UNICODE )
+ WideCharToMultiByte( CP_ACP, 0, buf, fileOffset-1, dat->files[nTemp], fileOffset - 1, 0, 0 );
+ dat->files[nTemp][fileOffset-1] = '\\';
+ WideCharToMultiByte( CP_ACP, 0, pBuf, -1, dat->files[nTemp] + fileOffset - (buf[fileOffset-2]=='\\'?1:0), cbFileNameLen+1, 0, 0 );
+ #else
+ CopyMemory(dat->files[nTemp], buf, fileOffset-1 );
+ dat->files[nTemp][fileOffset-1] = '\\';
+ strcpy(dat->files[nTemp] + fileOffset - (buf[fileOffset-2]=='\\'?1:0), pBuf);
+ #endif
+ // Move pointers to next file...
+ pBuf += cbFileNameLen + 1;
+ nTemp++;
+ }
+ // Terminate array
+ dat->files[nNumberOfFiles] = NULL;
+ }
+ // ...the selection is a single file
+ else
+ {
+ if (( dat->files = (char**)mir_alloc(2 * sizeof(char*))) == NULL ) // Leaks when aborted
+ return;
+
+ #if defined( _UNICODE )
+ {
+ char szFileName[ MAX_PATH ];
+ BOOL bUsed;
+ WideCharToMultiByte( CP_ACP, 0, buf, -1, szFileName, MAX_PATH, NULL, &bUsed );
+ if ( bUsed ) {
+ WIN32_FIND_DATA dat;
+ HANDLE hSearch = FindFirstFile( buf, &dat );
+ if ( hSearch != INVALID_HANDLE_VALUE ) {
+ WideCharToMultiByte( CP_ACP, 0, dat.cAlternateFileName, -1, szFileName, MAX_PATH, 0, 0 );
+ FindClose( hSearch );
+ } }
+
+ dat->files[0] = mir_strdup(szFileName);
+ }
+ #else
+ dat->files[0] = mir_strdup(buf);
+ #endif
+
+ dat->files[1] = NULL;
+ }
+
+ // Update dialog text with new file selection
+ SetFileListAndSizeControls(hwndDlg, dat);
+}
+
+#define M_FILECHOOSEDONE (WM_USER+100)
+void __cdecl ChooseFilesThread(HWND hwndDlg)
+{
+ TCHAR filter[128], *pfilter;
+ TCHAR* buf = ( TCHAR* )mir_alloc( sizeof(TCHAR)*32767 );
+ if ( buf == NULL )
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )( TCHAR* )NULL );
+ else {
+ OPENFILENAME ofn = {0};
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ lstrcpy( filter, TranslateT( "All Files" ));
+ lstrcat( filter, _T(" (*)" ));
+ pfilter = filter + lstrlen( filter )+1;
+ lstrcpy( pfilter, _T( "*" ));
+ pfilter = filter + lstrlen( filter )+1;
+ pfilter[ 0 ] = '\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = buf; *buf = 0;
+ ofn.nMaxFile = 32767;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY;
+ if ( GetOpenFileName( &ofn ))
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )buf );
+ else {
+ mir_free( buf );
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )( TCHAR* )NULL );
+} } }
+
+static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd,LPARAM lParam)
+{
+ SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS);
+ return TRUE;
+}
+
+static WNDPROC OldSendEditProc;
+static LRESULT CALLBACK SendEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CHAR:
+ if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ case WM_SYSCHAR:
+ if((wParam=='s' || wParam=='S') && GetKeyState(VK_MENU)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldSendEditProc,hwnd,msg,wParam,lParam);
+}
+
+BOOL CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat;
+
+ dat=(struct FileDlgData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct FileSendData *fsd=(struct FileSendData*)lParam;
+
+ dat=(struct FileDlgData*)mir_alloc(sizeof(struct FileDlgData));
+ memset(dat,0,sizeof(struct FileDlgData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(long)dat);
+ dat->hContact=fsd->hContact;
+ dat->send=1;
+ dat->hPreshutdownEvent=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN);
+ dat->fs=NULL;
+ dat->dwTicks=GetTickCount();
+
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_FILE));
+ EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0);
+ OldSendEditProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)SendEditSubclassProc);
+
+ dat->hUIIcons[0]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[1]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hUIIcons[2]=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hUIIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ if(fsd->ppFiles!=NULL && fsd->ppFiles[0]!=NULL) {
+ int totalCount,i;
+ for(totalCount=0;fsd->ppFiles[totalCount];totalCount++);
+ dat->files=(char**)mir_alloc(sizeof(char*)*(totalCount+1)); // Leaks
+ for(i=0;i<totalCount;i++)
+ dat->files[i]=mir_strdup(fsd->ppFiles[i]);
+ dat->files[totalCount]=NULL;
+ SetFileListAndSizeControls(hwndDlg,dat);
+ }
+ {
+ char *szProto;
+ TCHAR* contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ SetDlgItemText(hwndDlg,IDC_TO,contactName);
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ }
+ }
+ if ( hasName )
+ SetDlgItemTextA(hwndDlg,IDC_NAME,buf);
+ else
+ SetDlgItemText(hwndDlg,IDC_NAME,contactName);
+ }
+ }
+ if(fsd->ppFiles==NULL) {
+ dat->closeIfFileChooseCancelled=1;
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_CHOOSE,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDC_CHOOSE));
+ }
+ return TRUE;
+ }
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ }
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+ case M_FILECHOOSEDONE:
+ if( lParam != 0 ) {
+ FilenameToFileList( hwndDlg, dat, ( TCHAR* )lParam );
+ mir_free(( TCHAR* )lParam );
+ dat->closeIfFileChooseCancelled = 0;
+ }
+ else if(dat->closeIfFileChooseCancelled) DestroyWindow(hwndDlg);
+ EnableWindow(hwndDlg,TRUE);
+ break;
+ case WM_COMMAND:
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHOOSE:
+ EnableWindow(hwndDlg,FALSE);
+ //GetOpenFileName() creates its own message queue which prevents any incoming events being processed
+ forkthread(ChooseFilesThread,0,hwndDlg);
+ break;
+ case IDOK:
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAME),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_CHOOSE),FALSE);
+ dat->hwndTransfer=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILETRANSFERINFO),hwndDlg,DlgProcFileTransfer);
+ return TRUE;
+ case IDCANCEL:
+ if(dat->hwndTransfer) return SendMessage(dat->hwndTransfer,msg,wParam,lParam);
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ break;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ return TRUE;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ return TRUE;
+ }
+ break;
+ case M_PRESHUTDOWN:
+ {
+ if (IsWindow(dat->hwndTransfer)) PostMessage(dat->hwndTransfer,WM_CLOSE,0,0);
+ break;
+ }
+ case WM_DESTROY:
+ if(dat->hPreshutdownEvent) UnhookEvent(dat->hPreshutdownEvent);
+ if(dat->hwndTransfer) DestroyWindow(dat->hwndTransfer);
+ FreeFilesMatrix(&dat->files);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_MSG),GWL_WNDPROC,(LONG)OldSendEditProc);
+ DestroyIcon(dat->hUIIcons[2]);
+ DestroyIcon(dat->hUIIcons[1]);
+ DestroyIcon(dat->hUIIcons[0]);
+ mir_free(dat);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srfile/filexferdlg.c b/miranda-wine/src/modules/srfile/filexferdlg.c new file mode 100644 index 0000000..468ce47 --- /dev/null +++ b/miranda-wine/src/modules/srfile/filexferdlg.c @@ -0,0 +1,562 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <io.h>
+#include "file.h"
+
+#define HM_RECVEVENT (WM_USER+10)
+
+static int CheckVirusScanned(HWND hwnd,struct FileDlgData *dat,int i)
+{
+ if(dat->send) return 1;
+ if(dat->fileVirusScanned[i]) return 1;
+ if(DBGetContactSettingByte(NULL,"SRFile","WarnBeforeOpening",1)==0) return 1;
+ return IDYES==MessageBox(hwnd,TranslateT("This file has not yet been scanned for viruses. Are you certain you want to open it?"),TranslateT("File Received"),MB_YESNO|MB_DEFBUTTON2);
+}
+
+#define M_VIRUSSCANDONE (WM_USER+100)
+struct virusscanthreadstartinfo {
+ char *szFile;
+ int returnCode;
+ HWND hwndReply;
+};
+
+static void SetOpenFileButtonStyle(HWND hwndButton,int downarrow,int enabled)
+{
+ if(downarrow) {
+ SendMessage(hwndButton,BUTTONSETARROW,1,0);
+ }
+ else {
+ SendMessage(hwndButton,BUTTONSETARROW,0,0);
+ }
+ EnableWindow(hwndButton,enabled);
+}
+
+static void __cdecl RunVirusScannerThread(struct virusscanthreadstartinfo *info)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFOA si={0};
+ DBVARIANT dbv;
+ char szCmdLine[768];
+
+ if(!DBGetContactSetting(NULL,"SRFile","ScanCmdLine",&dbv)) {
+ if(dbv.pszVal[0]) {
+ char *pszReplace;
+ si.cb=sizeof(si);
+ pszReplace=strstr(dbv.pszVal,"%f");
+ if(pszReplace) {
+ if(info->szFile[lstrlenA(info->szFile)-1]=='\\') info->szFile[lstrlenA(info->szFile)-1]='\0';
+ *pszReplace=0;
+ mir_snprintf(szCmdLine,SIZEOF(szCmdLine),"%s\"%s\"%s",dbv.pszVal,info->szFile,pszReplace+2);
+ }
+ else lstrcpynA(szCmdLine,dbv.pszVal,SIZEOF(szCmdLine));
+ if(CreateProcessA(NULL,szCmdLine,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) {
+ if(WaitForSingleObject(pi.hProcess,3600*1000)==WAIT_OBJECT_0)
+ PostMessage(info->hwndReply,M_VIRUSSCANDONE,info->returnCode,0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ mir_free(info->szFile);
+ mir_free(info);
+}
+
+static void SetFilenameControls(HWND hwndDlg,PROTOFILETRANSFERSTATUS *fts)
+{
+ char str[MAX_PATH];
+ HWND hwndFilename;
+
+ { TCHAR msg[MAX_PATH];
+ GetDlgItemText(hwndDlg,IDC_FILENAME,msg,SIZEOF(msg));
+ if(msg[0]) return;
+
+ wsprintf(msg,TranslateT("Current file (%d of %d)"),fts->currentFileNumber+1,fts->totalFiles);
+ SetDlgItemText(hwndDlg,IDC_CURRENTFILEGROUP,msg);
+ }
+
+ hwndFilename=GetDlgItem(hwndDlg,IDC_FILENAME);
+ lstrcpynA(str,fts->currentFile,SIZEOF(str));
+ if(strchr(str,'\\')) {
+ RECT rcFilename;
+ HDC hdc;
+ SIZE textSize;
+ HFONT hFont;
+ int driveNameLen,driveAndEllipsisLen=0;
+ char *pszBackslash;
+
+ GetClientRect(hwndFilename,&rcFilename);
+ hdc = GetDC(hwndFilename);
+ hFont = SelectObject(hdc,(HFONT)SendMessage(hwndFilename,WM_GETFONT,0,0));
+ if(str[0] && str[1]==':' && str[2]=='\\') driveNameLen=3;
+ else if(str[0]=='\\' && str[1]=='\\') {
+ if((pszBackslash=strchr(str+2,'\\'))!=NULL && (pszBackslash=strchr(pszBackslash+1,'\\'))!=NULL)
+ driveNameLen=pszBackslash-str+1;
+ else driveNameLen=2;
+ }
+ else driveNameLen=0;
+ for(;;) {
+ GetTextExtentPoint32A(hdc,str,lstrlenA(str),&textSize);
+ if(textSize.cx<rcFilename.right) break;
+ pszBackslash=strchr(str+(driveAndEllipsisLen?driveAndEllipsisLen:driveNameLen),'\\');
+ if(pszBackslash==NULL) {
+ lstrcpyA(str,strrchr(fts->currentFile,'\\')+1);
+ break;
+ }
+ if(driveAndEllipsisLen)
+ MoveMemory(str+driveAndEllipsisLen,pszBackslash+1,lstrlenA(pszBackslash));
+ else {
+ MoveMemory(str+driveNameLen+4,pszBackslash,lstrlenA(pszBackslash)+1);
+ CopyMemory(str+driveNameLen,"...\\",4);
+ driveAndEllipsisLen=driveNameLen+4;
+ }
+ }
+ SelectObject(hdc,hFont);
+ ReleaseDC(hwndFilename,hdc);
+ }
+ SetWindowTextA(hwndFilename,str);
+}
+
+BOOL CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat=NULL;
+
+ dat=(struct FileDlgData*)GetWindowLong(GetParent(hwndDlg),GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat->hNotifyEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_RECVEVENT);
+ dat->transferStatus.currentFileNumber=-1;
+ if(dat->send) {
+ char szMsg[450];
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_MSG,szMsg,SIZEOF(szMsg));
+ dat->fs=(HANDLE)CallContactService(dat->hContact,PSS_FILE,(WPARAM)szMsg,(LPARAM)dat->files);
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Request sent, waiting for acceptance..."));
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),dat->files[1]!=NULL,1);
+ dat->waitingForAcceptance=1;
+ }
+ else { //recv
+ char szSavePath[MAX_PATH];
+
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_FILEDIR,szSavePath,SIZEOF(szSavePath));
+ CreateDirectoryTree(szSavePath);
+ dat->fs=(HANDLE)CallContactService(dat->hContact,PSS_FILEALLOW,(WPARAM)dat->fs,(LPARAM)szSavePath);
+ dat->transferStatus.workingDir=mir_strdup(szSavePath);
+ if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) dat->resumeBehaviour=FILERESUME_ASK;
+ else dat->resumeBehaviour=DBGetContactSettingByte(NULL,"SRFile","IfExists",FILERESUME_ASK);
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Waiting for connection..."));
+ }
+ {
+ /* check we actually got an fs handle back from the protocol */
+ if (!dat->fs) {
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Unable to initiate transfer."));
+ dat->waitingForAcceptance=0;
+ }
+ }
+ { LOGFONT lf;
+ HFONT hFont;
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEGROUP,WM_GETFONT,0,0);
+ GetObject(hFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEGROUP,WM_SETFONT,(WPARAM)hFont,0);
+ SendDlgItemMessage(hwndDlg,IDC_ALLFILESGROUP,WM_SETFONT,(WPARAM)hFont,0);
+ }
+ { RECT rcParentClient;
+ RECT rcThisDlg;
+ BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+ GetClientRect(GetParent(hwndDlg),&rcParentClient);
+ GetClientRect(hwndDlg,&rcThisDlg);
+ SetWindowPos(hwndDlg,HWND_TOP,0,rcParentClient.bottom-rcThisDlg.bottom,0,0,SWP_NOSIZE);
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(GetModuleHandleA("USER32"),"AnimateWindow");
+ if(MyAnimateWindow)
+ MyAnimateWindow(hwndDlg,200,AW_ACTIVATE|AW_SLIDE|AW_VER_NEGATIVE);
+ else ShowWindow(hwndDlg,SW_SHOW);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_OPENFILE,BUTTONSETDEFAULT,1,0);
+ if(!dat->waitingForAcceptance) SetTimer(hwndDlg,1,1000,NULL);
+ return TRUE;
+ case WM_TIMER:
+ MoveMemory(dat->bytesRecvedHistory+1,dat->bytesRecvedHistory,sizeof(dat->bytesRecvedHistory)-sizeof(dat->bytesRecvedHistory[0]));
+ dat->bytesRecvedHistory[0]=dat->transferStatus.totalProgress;
+ if ( dat->bytesRecvedHistorySize < SIZEOF(dat->bytesRecvedHistory))
+ dat->bytesRecvedHistorySize++;
+
+ { TCHAR szSpeed[32], szTime[32], szDisplay[96];
+ SYSTEMTIME st;
+ ULARGE_INTEGER li;
+ FILETIME ft;
+
+ GetSensiblyFormattedSize((dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1])/dat->bytesRecvedHistorySize,szSpeed,SIZEOF(szSpeed),0,1,NULL);
+ if(dat->bytesRecvedHistory[0]==dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1])
+ lstrcpy(szTime,_T("??:??:??"));
+ else {
+ li.QuadPart=BIGI(10000000)*(dat->transferStatus.currentFileSize-dat->transferStatus.currentFileProgress)*dat->bytesRecvedHistorySize/(dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]);
+ ft.dwHighDateTime=li.HighPart; ft.dwLowDateTime=li.LowPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,&st,NULL,szTime,SIZEOF(szTime));
+ }
+ mir_sntprintf(szDisplay,SIZEOF(szDisplay),_T("%s/%s (%s %s)"),szSpeed,TranslateT("sec"),szTime,TranslateT("remaining"));
+ SetDlgItemText(hwndDlg,IDC_CURRENTSPEED,szDisplay);
+ if(dat->bytesRecvedHistory[0]!=dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]) {
+ li.QuadPart=BIGI(10000000)*(dat->transferStatus.totalBytes-dat->transferStatus.totalProgress)*dat->bytesRecvedHistorySize/(dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]);
+ ft.dwHighDateTime=li.HighPart; ft.dwLowDateTime=li.LowPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,&st,NULL,szTime,SIZEOF(szTime));
+ }
+ mir_sntprintf(szDisplay,SIZEOF(szDisplay),_T("%s/%s (%s %s)"),szSpeed,TranslateT("sec"),szTime,TranslateT("remaining"));
+ SetDlgItemText(hwndDlg,IDC_ALLSPEED,szDisplay);
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(GetParent(hwndDlg));
+ break;
+ case IDC_OPENFOLDER:
+ ShellExecuteA(NULL,NULL,dat->transferStatus.workingDir,NULL,NULL,SW_SHOW);
+ break;
+
+ case IDC_OPENFILE:
+ {
+ char **files;
+
+ if (dat->send)
+ if (dat->files == NULL)
+ files = dat->transferStatus.files;
+ else
+ files = dat->files;
+ else
+ files=dat->files;
+
+ if (files == NULL || *files == NULL)
+ break;
+
+
+ // Only one single file
+ if (files[1] == NULL) {
+ if (!CheckVirusScanned(hwndDlg, dat, 0))
+ break;
+ ShellExecuteA(NULL, NULL, files[0], NULL, NULL, SW_SHOW);
+ }
+ // Multiple files
+ else {
+ RECT rc;
+ int i,limit;
+ char *pszFilename,*pszNewFileName;
+ HMENU hMenu = CreatePopupMenu();
+
+ if (dat->send)
+ limit = dat->transferStatus.totalFiles;
+ else
+ limit = dat->transferStatus.currentFileNumber;
+
+ // Loop over all transfered files and add them to the menu
+ for (i = 0; i < limit; i++) {
+ pszFilename = strrchr(files[i], '\\');
+ if (pszFilename == NULL)
+ pszFilename = files[i];
+ else
+ pszFilename++;
+ {
+ if (pszFilename) {
+ int pszlen;
+ char *p;
+
+ pszNewFileName = (char*)mir_alloc(strlen(pszFilename)*2);
+ p = pszNewFileName;
+ for (pszlen=0; pszlen<(int)strlen(pszFilename); pszlen++) {
+ *p++ = pszFilename[pszlen];
+ if (pszFilename[pszlen]=='&')
+ *p++ = '&';
+ }
+ *p = '\0';
+ AppendMenuA(hMenu, MF_STRING, i+1, pszNewFileName);
+ mir_free(pszNewFileName);
+ }
+ }
+ }
+
+ GetWindowRect((HWND)lParam, &rc);
+ i = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ DestroyMenu(hMenu);
+
+ if (i && CheckVirusScanned(hwndDlg, dat, i))
+ ShellExecuteA(NULL, NULL, files[i-1], NULL, NULL, SW_SHOW);
+ }
+
+ break;
+ }
+
+ }
+ break;
+ case M_FILEEXISTSDLGREPLY:
+ { PROTOFILERESUME *pfr=(PROTOFILERESUME*)lParam;
+ char *szOriginalFilename=(char*)wParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+
+ EnableWindow(hwndDlg,TRUE);
+ switch(pfr->action) {
+ case FILERESUME_CANCEL:
+ if (dat->fs) CallContactService(dat->hContact,PSS_FILECANCEL,(WPARAM)dat->fs,0);
+ dat->fs=NULL;
+ DestroyWindow(GetParent(hwndDlg));
+ mir_free(szOriginalFilename);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ mir_free(pfr);
+ return 0;
+ case FILERESUME_RESUMEALL:
+ case FILERESUME_OVERWRITEALL:
+ dat->resumeBehaviour=wParam;
+ pfr->action&=~FILERESUMEF_ALL;
+ break;
+ case FILERESUME_RENAMEALL:
+ pfr->action=FILERESUME_RENAME;
+ { char *pszExtension,*pszFilename;
+ int i;
+ if((pszFilename=strrchr(szOriginalFilename,'\\'))==NULL) pszFilename=szOriginalFilename;
+ if((pszExtension=strrchr(pszFilename+1,'.'))==NULL) pszExtension=pszFilename+lstrlenA(pszFilename);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ pfr->szFilename=(char*)mir_alloc((pszExtension-szOriginalFilename)+21+lstrlenA(pszExtension));
+ for(i=1;;i++) {
+ sprintf((char*)pfr->szFilename,"%.*s (%u)%s",pszExtension-szOriginalFilename,szOriginalFilename,i,pszExtension);
+ if(_access(pfr->szFilename,0)!=0) break;
+ }
+ }
+ break;
+ }
+ mir_free(szOriginalFilename);
+ CallProtoService(szProto,PS_FILERESUME,(WPARAM)dat->fs,(LPARAM)pfr);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ mir_free(pfr);
+ break;
+ }
+ case HM_RECVEVENT:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ if (ack->hProcess!=dat->fs) break; /* icq abuses this sometimes */
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_FILE) break;
+
+ if(dat->waitingForAcceptance) {
+ SetTimer(hwndDlg,1,1000,NULL);
+ dat->waitingForAcceptance=0;
+ }
+ switch(ack->result) {
+ case ACKRESULT_SENTREQUEST: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Decision sent")); break;
+ case ACKRESULT_CONNECTING: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Connecting...")); break;
+ case ACKRESULT_CONNECTED: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Connected")); break;
+ case ACKRESULT_INITIALISING: SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Initialising...")); break;
+ case ACKRESULT_NEXTFILE:
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Moving to next file..."));
+ SetDlgItemTextA(hwndDlg,IDC_FILENAME,"");
+ if(dat->transferStatus.currentFileNumber==1 && dat->transferStatus.totalFiles>1 && !dat->send)
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),1,1);
+ if(dat->transferStatus.currentFileNumber!=-1 && dat->files && !dat->send && DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE)==VIRUSSCAN_DURINGDL) {
+ if(GetFileAttributesA(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY)
+ PostMessage(hwndDlg,M_VIRUSSCANDONE,dat->transferStatus.currentFileNumber,0);
+ else {
+ struct virusscanthreadstartinfo *vstsi;
+ vstsi=(struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo));
+ vstsi->hwndReply=hwndDlg;
+ vstsi->szFile=mir_strdup(dat->files[dat->transferStatus.currentFileNumber]);
+ vstsi->returnCode=dat->transferStatus.currentFileNumber;
+ forkthread((void (*)(void*))RunVirusScannerThread,0,vstsi);
+ }
+ }
+ break;
+ case ACKRESULT_FILERESUME:
+ {
+ PROTOFILETRANSFERSTATUS *fts=(PROTOFILETRANSFERSTATUS*)ack->lParam;
+
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ CopyProtoFileTransferStatus(&dat->transferStatus,fts);
+ SetFilenameControls(hwndDlg,fts);
+ if(_access(fts->currentFile,0)!=0) break;
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("File already exists"));
+ if(dat->resumeBehaviour==FILERESUME_ASK) {
+ ShowWindow(hwndDlg,SW_SHOWNORMAL);
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_FILEEXISTS),hwndDlg,DlgProcFileExists,(LPARAM)fts);
+ EnableWindow(hwndDlg,FALSE);
+ }
+ else {
+ PROTOFILERESUME *pfr;
+ pfr=(PROTOFILERESUME*)mir_alloc(sizeof(PROTOFILERESUME));
+ pfr->action=dat->resumeBehaviour;
+ pfr->szFilename=NULL;
+ PostMessage(hwndDlg,M_FILEEXISTSDLGREPLY,(WPARAM)mir_strdup(fts->currentFile),(LPARAM)pfr);
+ }
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,1);
+ return TRUE;
+ }
+ case ACKRESULT_DATA:
+ {
+ PROTOFILETRANSFERSTATUS *fts=(PROTOFILETRANSFERSTATUS*)ack->lParam;
+ TCHAR str[256],szSizeDone[32],szSizeTotal[32],*contactName;
+ int units;
+
+ /* HACK: for 0.3.3, limit updates to around 1.1 ack per second */
+ if (fts->totalProgress!=fts->totalBytes && GetTickCount() - dat->dwTicks < 650) break; // the last update was less than a second ago!
+ dat->dwTicks=GetTickCount();
+
+/* FIXME: There is a leak with this, and a major performance issue with creating and freeing this list EVERY DAMN ACK! */
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ CopyProtoFileTransferStatus(&dat->transferStatus,fts);
+ if(dat->fileVirusScanned==NULL) dat->fileVirusScanned=(int*)mir_calloc(sizeof(int) * fts->totalFiles);
+ if(!dat->send) {
+ if(dat->files==NULL) dat->files=(char**)mir_calloc((fts->totalFiles+1)*sizeof(char*));
+ if(fts->currentFileNumber<fts->totalFiles) dat->files[fts->currentFileNumber]=mir_strdup(fts->currentFile);
+ }
+/* FIXME: There is a performance issue of creating this list here if it does not exist */
+
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateTS(fts->sending?_T("Sending..."):_T("Receiving...")));
+ SetFilenameControls(hwndDlg,fts);
+ SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEPROGRESS, PBM_SETPOS, fts->currentFileSize?(WPARAM)(BIGI(100)*fts->currentFileProgress/fts->currentFileSize):0, 0);
+ SendDlgItemMessage(hwndDlg,IDC_ALLFILESPROGRESS, PBM_SETPOS, fts->totalBytes?(WPARAM)(BIGI(100)*fts->totalProgress/fts->totalBytes):0, 0);
+
+ GetSensiblyFormattedSize(fts->currentFileSize,szSizeTotal,SIZEOF(szSizeTotal),0,1,&units);
+ GetSensiblyFormattedSize(fts->currentFileProgress,szSizeDone,SIZEOF(szSizeTotal),units,0,NULL);
+ mir_sntprintf(str,SIZEOF(str),_T("%s / %s (%d%%)"),szSizeDone,szSizeTotal,fts->currentFileSize?(int)(BIGI(100)*fts->currentFileProgress/fts->currentFileSize):0);
+ SetDlgItemText(hwndDlg,IDC_CURRENTTRANSFERRED,str);
+
+ GetSensiblyFormattedSize(fts->totalBytes,szSizeTotal,SIZEOF(szSizeTotal),0,1,&units);
+ GetSensiblyFormattedSize(fts->totalProgress,szSizeDone,SIZEOF(szSizeTotal),units,0,NULL);
+ mir_sntprintf(str,SIZEOF(str),_T("%s / %s (%d%%)"),szSizeDone,szSizeTotal,fts->totalBytes?(int)(BIGI(100)*fts->totalProgress/fts->totalBytes):0);
+ SetDlgItemText(hwndDlg,IDC_ALLTRANSFERRED,str);
+
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ mir_sntprintf(str,SIZEOF(str),_T("%d%%: %s: %s"),fts->totalBytes?(int)(BIGI(100)*fts->totalProgress/fts->totalBytes):0,contactName,TranslateTS(dat->send?(fts->totalFiles==1?_T("Sending file"):_T("Sending files")):(fts->totalFiles==1?_T("Receiving file"):_T("Receiving files"))));
+ SetWindowText(GetParent(hwndDlg),str);
+ break;
+ }
+ case ACKRESULT_SUCCESS:
+ {
+ dat->fs=NULL; /* protocol will free structure */
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Transfer completed"));
+ if (ack->result==ACKRESULT_SUCCESS) SkinPlaySound("FileDone");
+ if(!dat->send) { //receiving
+ int useScanner=DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE);
+ if(useScanner!=VIRUSSCAN_DISABLE) {
+ struct virusscanthreadstartinfo *vstsi;
+ vstsi=(struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo));
+ vstsi->hwndReply=hwndDlg;
+ if(useScanner==VIRUSSCAN_DURINGDL) {
+ vstsi->returnCode=dat->transferStatus.currentFileNumber;
+ if(GetFileAttributesA(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY) {
+ PostMessage(hwndDlg,M_VIRUSSCANDONE,vstsi->returnCode,0);
+ mir_free(vstsi);
+ vstsi=NULL;
+ }
+ else vstsi->szFile=mir_strdup(dat->files[dat->transferStatus.currentFileNumber]);
+ }
+ else {
+ vstsi->szFile=mir_strdup(dat->transferStatus.workingDir);
+ vstsi->returnCode=-1;
+ }
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Scanning for viruses..."));
+ if(vstsi) forkthread((void (*)(void*))RunVirusScannerThread,0,vstsi);
+ }
+ dat->transferStatus.currentFileNumber=dat->transferStatus.totalFiles;
+ }
+ else { //sending
+ DBEVENTINFO dbei={0};
+ char szMsg[450],szFilenames[1024];
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_FILE,szFilenames,SIZEOF(szFilenames));
+ GetDlgItemTextA(GetParent(hwndDlg),IDC_MSG,szMsg,SIZEOF(szMsg));
+ dbei.cbSize=sizeof(dbei);
+ dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ dbei.eventType=EVENTTYPE_FILE;
+ dbei.flags=DBEF_SENT;
+ dbei.timestamp=time(NULL);
+ dbei.cbBlob=sizeof(DWORD)+lstrlenA(szFilenames)+lstrlenA(szMsg)+2;
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ *(PDWORD)dbei.pBlob=0;
+ lstrcpyA(dbei.pBlob+sizeof(DWORD),szFilenames);
+ lstrcpyA(dbei.pBlob+sizeof(DWORD)+lstrlenA(szFilenames)+1,szMsg);
+ CallService(MS_DB_EVENT_ADD,(WPARAM)dat->hContact,(LPARAM)&dbei);
+ if (dbei.pBlob)
+ mir_free(dbei.pBlob);
+ dat->files=NULL; //protocol library frees this
+ }
+ }
+ //fall through
+ case ACKRESULT_FAILED:
+ dat->fs=NULL; /* protocol will free structure */
+ KillTimer(hwndDlg,1);
+ if(!dat->send) SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),dat->transferStatus.totalFiles>1,1);
+ SetDlgItemText(hwndDlg,IDCANCEL,TranslateT("Close"));
+ if (dat->hNotifyEvent) UnhookEvent(dat->hNotifyEvent);
+ dat->hNotifyEvent=NULL;
+ if(ack->result==ACKRESULT_FAILED) {
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("File transfer failed"));
+ SkinPlaySound("FileFailed");
+ } else
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoClose",0))
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDCANCEL));
+ break;
+
+ case ACKRESULT_DENIED:
+ dat->fs=NULL; /* protocol will free structure */
+ SkinPlaySound("FileDenied");
+ KillTimer(hwndDlg, 1);
+ if (!dat->send) SetOpenFileButtonStyle(GetDlgItem(hwndDlg, IDC_OPENFILE), dat->transferStatus.totalFiles > 1, 1);
+ SetDlgItemText(hwndDlg, IDCANCEL, TranslateT("Close"));
+ SetDlgItemText(hwndDlg, IDC_STATUS, TranslateT("File transfer denied"));
+ UnhookEvent(dat->hNotifyEvent);
+ dat->hNotifyEvent = NULL;
+ break;
+
+ }
+ break;
+ }
+ case M_VIRUSSCANDONE:
+ { int done=1,i;
+ if((int)wParam==-1) {
+ for(i=0;i<dat->transferStatus.totalFiles;i++) dat->fileVirusScanned[i]=1;
+ }
+ else {
+ dat->fileVirusScanned[wParam]=1;
+ for(i=0;i<dat->transferStatus.totalFiles;i++) if(!dat->fileVirusScanned[i]) {done=0; break;}
+ }
+ if(done) SetDlgItemText(hwndDlg,IDC_STATUS,TranslateT("Transfer and virus scan complete"));
+ break;
+ }
+ case WM_DESTROY:
+ KillTimer(hwndDlg,1);
+ if(dat->fs) CallContactService(dat->hContact,PSS_FILECANCEL,(WPARAM)dat->fs,0);
+ dat->fs=NULL;
+ if(dat->hNotifyEvent) {UnhookEvent(dat->hNotifyEvent); dat->hNotifyEvent=NULL;}
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ if(!dat->send) FreeFilesMatrix(&dat->files);
+ if(dat->fileVirusScanned) mir_free(dat->fileVirusScanned);
+ { HFONT hFont;
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_CURRENTFILEGROUP,WM_GETFONT,0,0);
+ DeleteObject(hFont);
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/srurl/url.c b/miranda-wine/src/modules/srurl/url.c new file mode 100644 index 0000000..9ae10d4 --- /dev/null +++ b/miranda-wine/src/modules/srurl/url.c @@ -0,0 +1,203 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <m_url.h>
+#include "url.h"
+
+HANDLE hUrlWindowList = NULL;
+static HANDLE hEventContactSettingChange = NULL;
+HANDLE hContactDeleted=NULL;
+HANDLE *hUrlContactMenu=NULL;
+int hUrlContactMenuCount=0;
+
+BOOL CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static int ReadUrlCommand(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_URLRECV),NULL,DlgProcUrlRecv,lParam);
+ return 0;
+}
+
+static int UrlEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTEVENT cle;
+ DBEVENTINFO dbei;
+ char *contactName;
+ char szTooltip[256];
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || dbei.eventType!=EVENTTYPE_URL) return 0;
+
+ SkinPlaySound("RecvUrl");
+ ZeroMemory(&cle,sizeof(cle));
+ cle.cbSize=sizeof(cle);
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)lParam;
+ cle.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+ cle.pszService="SRUrl/ReadUrl";
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,wParam,0);
+ mir_snprintf(szTooltip,SIZEOF(szTooltip),Translate("URL from %s"),contactName);
+ cle.pszTooltip=szTooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ return 0;
+}
+
+static int SendUrlCommand(WPARAM wParam,LPARAM lParam)
+{
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_URLSEND),NULL,DlgProcUrlSend,wParam);
+ return 0;
+}
+
+static void RestoreUnreadUrlAlerts(void)
+{
+ CLISTEVENT cle={0};
+ DBEVENTINFO dbei={0};
+ char toolTip[256];
+ HANDLE hDbEvent,hContact;
+
+ dbei.cbSize=sizeof(dbei);
+ cle.cbSize=sizeof(cle);
+ cle.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+ cle.pszService="SRUrl/ReadUrl";
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact) {
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ if(!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_URL) {
+ cle.hContact=hContact;
+ cle.hDbEvent=hDbEvent;
+ mir_snprintf(toolTip,SIZEOF(toolTip),Translate("URL from %s"),(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+ cle.pszTooltip=toolTip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ }
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0);
+ }
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+}
+
+static int ContactSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if(lstrcmpA(cws->szModule,"CList") && (szProto==NULL || lstrcmpA(cws->szModule,szProto))) return 0;
+ WindowList_Broadcast(hUrlWindowList,DM_UPDATETITLE,0,0);
+ return 0;
+}
+
+static int SRUrlModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM mi;
+ PROTOCOLDESCRIPTOR **protocol;
+ int protoCount,i;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000040000;
+ mi.flags=0;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+ mi.pszName=Translate("Web Page Address (&URL)");
+ mi.pszService=MS_URL_SENDURL;
+ CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&protoCount,(LPARAM)&protocol);
+ for(i=0;i<protoCount;i++) {
+ if(protocol[i]->type!=PROTOTYPE_PROTOCOL) continue;
+ if(CallProtoService(protocol[i]->szName,PS_GETCAPS,PFLAGNUM_1,0)&PF1_URLSEND) {
+ mi.pszContactOwner=protocol[i]->szName;
+ hUrlContactMenu=mir_realloc(hUrlContactMenu,(hUrlContactMenuCount+1)*sizeof(HANDLE));
+ hUrlContactMenu[hUrlContactMenuCount++]=(HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ }
+ }
+ RestoreUnreadUrlAlerts();
+ return 0;
+}
+
+static int UrlMenuIconChanged(WPARAM wParam, LPARAM lParam)
+{
+
+ if (hUrlContactMenu) {
+
+ int j;
+ CLISTMENUITEM mi;
+
+ mi.cbSize=sizeof(mi);
+ mi.flags=CMIM_ICON;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_URL);
+
+ for (j=0; j<hUrlContactMenuCount; j++) {
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hUrlContactMenu[j],(LPARAM)&mi);
+ }
+
+ }
+ return 0;
+}
+
+static int SRUrlShutdown(WPARAM wParam,LPARAM lParam)
+{
+
+ if (hEventContactSettingChange) UnhookEvent(hEventContactSettingChange);
+ if (hContactDeleted) UnhookEvent(hContactDeleted);
+ if (hUrlWindowList) {
+ WindowList_BroadcastAsync(hUrlWindowList,WM_CLOSE,0,0);
+ }
+ if (hUrlContactMenu) {
+ mir_free(hUrlContactMenu); hUrlContactMenu=NULL;
+ hUrlContactMenuCount=0;
+ }
+ return 0;
+
+}
+
+int UrlContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ HWND h;
+ h=WindowList_Find(hUrlWindowList,(HANDLE)wParam);
+ if (h) {
+ SendMessage(h,WM_CLOSE,0,0);
+ }
+ return 0;
+}
+
+int LoadSendRecvUrlModule(void)
+{
+ hUrlWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ HookEvent(ME_SYSTEM_MODULESLOADED,SRUrlModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED,UrlEventAdded);
+ HookEvent(ME_SKIN_ICONSCHANGED,UrlMenuIconChanged);
+ hEventContactSettingChange = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+ hContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, UrlContactDeleted);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,SRUrlShutdown);
+ CreateServiceFunction(MS_URL_SENDURL,SendUrlCommand);
+ CreateServiceFunction("SRUrl/ReadUrl",ReadUrlCommand);
+ SkinAddNewSoundEx("RecvUrl",Translate("URL"),Translate("Incoming"));
+ return 0;
+}
+
diff --git a/miranda-wine/src/modules/srurl/url.h b/miranda-wine/src/modules/srurl/url.h new file mode 100644 index 0000000..de8f442 --- /dev/null +++ b/miranda-wine/src/modules/srurl/url.h @@ -0,0 +1,43 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#define TIMEOUT_URLSEND 9000
+#define HM_EVENTSENT (WM_USER+10)
+#define DM_UPDATETITLE (WM_USER+11)
+
+#define DDEMESSAGETIMEOUT 1000
+
+
+struct UrlRcvData {
+ HANDLE hContact;
+ HANDLE hDbEvent;
+ HICON hIcons[4];
+};
+
+struct UrlSendData {
+ HANDLE hContact;
+ HANDLE hSendId;
+ HANDLE hAckEvent;
+ char *sendBuffer;
+ HICON hIcons[4];
+};
diff --git a/miranda-wine/src/modules/srurl/urldialogs.c b/miranda-wine/src/modules/srurl/urldialogs.c new file mode 100644 index 0000000..083d825 --- /dev/null +++ b/miranda-wine/src/modules/srurl/urldialogs.c @@ -0,0 +1,737 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include "url.h"
+
+
+BOOL CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+extern HANDLE hUrlWindowList;
+
+
+BOOL CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct UrlRcvData *dat = NULL;
+
+ dat=(struct UrlRcvData *)GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_URL));
+
+ dat=(struct UrlRcvData*)mir_alloc(sizeof(struct UrlRcvData));
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)dat);
+
+ dat->hContact = ((CLISTEVENT*)lParam)->hContact;
+ dat->hDbEvent = ((CLISTEVENT*)lParam)->hDbEvent;
+
+ WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact);
+
+ {
+ DBEVENTINFO dbei;
+ DBTIMETOSTRINGT dbtts;
+ TCHAR* contactName;
+ TCHAR msg[128];
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei);
+ SetDlgItemTextA(hwndDlg,IDC_URL,dbei.pBlob);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,dbei.pBlob+lstrlenA(dbei.pBlob)+1);
+ mir_free(dbei.pBlob);
+
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)dat->hContact,(LPARAM)dat->hDbEvent);
+
+ contactName=(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ mir_sntprintf(msg,SIZEOF(msg),TranslateT("URL from %s"),contactName);
+ SetWindowText(hwndDlg,msg);
+ SetDlgItemText(hwndDlg,IDC_FROM,contactName);
+ SendDlgItemMessage(hwndDlg,IDOK,BUTTONSETARROW,1,0);
+ { TCHAR str[128];
+ dbtts.szFormat = _T("t d");
+ dbtts.szDest = str;
+ dbtts.cbDest = SIZEOF(str);
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, dbei.timestamp, (LPARAM)&dbtts);
+ SetDlgItemText(hwndDlg, IDC_DATE, str);
+ } }
+
+ // From message dlg
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+
+ dat->hIcons[0]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[1]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[2]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[3]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[3]);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ SendMessage(hwndDlg,DM_UPDATETITLE,0,0);
+ // From message dlg end
+
+ Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,"SRUrl","recv");
+ return TRUE;
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+
+ case DM_UPDATETITLE:
+ {
+ char newtitle[256],oldtitle[256];
+ char *szStatus,*contactName,*pszNewTitleStart;
+ char *szProto;
+
+ pszNewTitleStart=Translate("URL from ");
+
+ if (dat->hContact) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ }
+ }
+
+ //
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,0);
+ SetDlgItemTextA(hwndDlg,IDC_NAME,hasName?buf:contactName);
+
+ szStatus=(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,szProto==NULL?ID_STATUS_OFFLINE:DBGetContactSettingWord(dat->hContact,szProto,"Status",ID_STATUS_OFFLINE),0);
+ mir_snprintf(newtitle,SIZEOF(newtitle),"%s %s (%s)", pszNewTitleStart, contactName, szStatus);
+ }
+ }
+ else
+ lstrcpynA(newtitle, pszNewTitleStart, SIZEOF(newtitle));
+
+ GetWindowTextA(hwndDlg,oldtitle,SIZEOF(oldtitle));
+
+ if(lstrcmpA(newtitle,oldtitle)) //swt() flickers even if the title hasn't actually changed
+ SetWindowTextA(hwndDlg,newtitle);
+
+ break;
+
+ }
+
+ case WM_COMMAND:
+ if (dat)
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch(LOWORD(wParam))
+ {
+ case IDOK:
+ { HMENU hMenu,hSubMenu;
+ RECT rc;
+ char url[256];
+
+ hMenu=LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu=GetSubMenu(hMenu,6);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hSubMenu,0);
+ GetWindowRect((HWND)lParam, &rc);
+ GetDlgItemTextA(hwndDlg, IDC_URL, url, SIZEOF(url));
+ switch(TrackPopupMenu(hSubMenu,TPM_RETURNCMD,rc.left,rc.bottom,0,hwndDlg,NULL)) {
+ case IDM_OPENNEW:
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)url);
+ break;
+ case IDM_OPENEXISTING:
+ CallService(MS_UTILS_OPENURL,0,(LPARAM)url);
+ break;
+ case IDM_COPYLINK:
+ { HGLOBAL hData;
+ if(!OpenClipboard(hwndDlg)) break;
+ EmptyClipboard();
+ hData=GlobalAlloc(GMEM_MOVEABLE,lstrlenA(url)+1);
+ lstrcpyA((char*)GlobalLock(hData),url);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_TEXT,hData);
+ CloseClipboard();
+ break;
+ }
+ }
+ }
+ return TRUE;
+
+ case IDC_USERMENU:
+ {
+ RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_ADD:
+ {
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto=0;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ }
+ break;
+ case IDC_REPLY:
+ CallService(MS_MSG_SENDMESSAGE,(WPARAM)dat->hContact,0);
+ //fall through
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ WindowList_Remove(hUrlWindowList, hwndDlg);
+ {int i;for(i=0; i < SIZEOF(dat->hIcons); i++ ) DestroyIcon(dat->hIcons[i]);}
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRUrl","recv");
+ break;
+ }
+ return FALSE;
+}
+
+static int ddeAcked,ddeData;
+static ATOM hSzDdeData;
+static HWND hwndDde;
+static HGLOBAL hGlobalDdeData;
+static LRESULT DdeMessage(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ ATOM hSzItem;
+
+ switch(msg) {
+ case WM_DDE_ACK:
+ ddeAcked=1;
+ hwndDde=(HWND)wParam;
+ return 0;
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT)&hGlobalDdeData,(PUINT)&hSzItem);
+ ddeData=1;
+ if(hGlobalDdeData) {
+ DDEDATA *data;
+ data=(DDEDATA*)GlobalLock(hGlobalDdeData);
+ if(data->fAckReq) {
+ DDEACK ack={0};
+ PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwndDlg,PackDDElParam(WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem));
+ }
+ else GlobalDeleteAtom(hSzItem);
+ GlobalUnlock(hGlobalDdeData);
+ }
+ else GlobalDeleteAtom(hSzItem);
+ return 0;
+ }
+ return 0;
+}
+
+static HGLOBAL DoDdeRequest(const char *szItemName,HWND hwndDlg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDlg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return NULL;
+ }
+ timeoutTick=GetTickCount()+5000;
+ ddeData=0; ddeAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(ddeData || ddeAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ } while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!ddeData) {
+ GlobalDeleteAtom(hSzItemName);
+ return NULL;
+ }
+
+ return hGlobalDdeData;
+}
+
+static void FreeDdeRequestData(HGLOBAL hData)
+{
+ DDEDATA *data;
+ data=(DDEDATA*)GlobalLock(hData);
+ if(data->fRelease) {
+ GlobalUnlock(hData);
+ GlobalFree(hData);
+ }
+ else GlobalUnlock(hData);
+}
+
+static void AddBrowserPageToCombo(char *url,HWND hwndCombo)
+{
+ char *title,*frame,*end;
+
+ if(url[0]!='"') return;
+ url++;
+ title=strchr(url,'"');
+ if(title==NULL) return;
+ *title='\0'; title++;
+ if(*title) {
+ title+=2;
+ frame=strchr(title,'"');
+ if(frame==NULL) return;
+ *frame='\0'; frame++;
+ if(*frame) {
+ frame+=2;
+ end=strchr(frame,'"');
+ if(end==NULL) return;
+ *end='\0';
+ }
+ else frame=NULL;
+ }
+ else title=frame=NULL;
+ if(frame==NULL || *frame==0) {
+ char *szItemData;
+ int i;
+ char szExistingUrl[1024];
+
+ for(i=SendMessage(hwndCombo,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ if(SendMessage(hwndCombo,CB_GETLBTEXTLEN,i,0) >= SIZEOF(szExistingUrl))
+ continue;
+ SendMessageA(hwndCombo,CB_GETLBTEXT,i,(LPARAM)szExistingUrl);
+ if(!lstrcmpA(szExistingUrl,url)) return;
+ }
+ i=SendMessageA(hwndCombo,CB_ADDSTRING,0,(LPARAM)url);
+ szItemData=mir_strdup(title);
+ SendMessage(hwndCombo,CB_SETITEMDATA,i,(LPARAM)szItemData);
+ }
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static void GetOpenBrowserUrlsForBrowser(const char *szBrowser,HWND hwndDlg,HWND hwndCombo)
+{
+ ATOM hSzBrowser,hSzTopic;
+ int windowCount,i;
+ DWORD *windowId;
+ DWORD dwResult;
+ HGLOBAL hData;
+ DDEDATA *data;
+ int dataLength;
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+
+ hSzTopic=GlobalAddAtomA("WWW_ListWindows");
+ ddeAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDlg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !ddeAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return;
+ }
+ hData=DoDdeRequest("WWW_ListWindows",hwndDlg);
+ if(hData==NULL) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return;
+ }
+ dataLength=GlobalSize(hData)-offsetof(DDEDATA,Value);
+ data=(DDEDATA*)GlobalLock(hData);
+ windowCount=dataLength/sizeof(DWORD);
+ windowId=(PDWORD)mir_alloc(sizeof(DWORD)*windowCount);
+ memcpy(windowId,data->Value,windowCount*sizeof(DWORD));
+ GlobalUnlock(hData);
+ FreeDdeRequestData(hData);
+ PostMessage(hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDlg,0);
+ GlobalDeleteAtom(hSzTopic);
+
+ hSzTopic=GlobalAddAtomA("WWW_GetWindowInfo");
+ ddeAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDlg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !ddeAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(windowId);
+ return;
+ }
+ for(i=0;i<windowCount;i++) {
+ if(windowId[i]==0) break;
+ { char str[16];
+ wsprintfA(str,"%d",windowId[i]);
+ hData=DoDdeRequest(str,hwndDlg);
+ }
+ if(hData!=NULL) {
+ dataLength=GlobalSize(hData)-offsetof(DDEDATA,Value);
+ data=(DDEDATA*)GlobalLock(hData);
+ AddBrowserPageToCombo(data->Value,hwndCombo);
+ GlobalUnlock(hData);
+ FreeDdeRequestData(hData);
+ }
+ }
+ PostMessage(hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDlg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(windowId);
+}
+
+static void GetOpenBrowserUrls(HWND hwndDlg,HWND hwndCombo)
+{
+ GetOpenBrowserUrlsForBrowser("opera",hwndDlg,hwndCombo);
+ GetOpenBrowserUrlsForBrowser("netscape",hwndDlg,hwndCombo);
+ GetOpenBrowserUrlsForBrowser("iexplore",hwndDlg,hwndCombo);
+}
+
+static WNDPROC OldSendEditProc;
+static LRESULT CALLBACK SendEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CHAR:
+ if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ case WM_SYSCHAR:
+ if((wParam=='s' || wParam=='S') && GetKeyState(VK_MENU)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldSendEditProc,hwnd,msg,wParam,lParam);
+}
+
+BOOL CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct UrlSendData *dat;
+
+ dat=(struct UrlSendData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, 450, 0);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_URL));
+ dat=(struct UrlSendData*)mir_alloc(sizeof(struct UrlSendData));
+ SetWindowLong(hwndDlg,GWL_USERDATA,(LONG)dat);
+ dat->hContact=(HANDLE)lParam;
+ dat->hAckEvent=NULL;
+ dat->hSendId=NULL;
+ dat->sendBuffer=NULL;
+
+ WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact);
+
+ { TCHAR *str = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,GCDNF_TCHAR);
+ SetDlgItemText(hwndDlg,IDC_NAME,str);
+ }
+
+ GetOpenBrowserUrls(hwndDlg,GetDlgItem(hwndDlg,IDC_URLS));
+ SendDlgItemMessage(hwndDlg, IDC_URLS, CB_SETCURSEL, 0, 0);
+ if (SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCOUNT,0,0))SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_URLS,CBN_SELCHANGE),0);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), (SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCURSEL, 0, 0) == CB_ERR)?FALSE:TRUE);
+ Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,"SRUrl","send");
+ OldSendEditProc=(WNDPROC)SetWindowLong(GetDlgItem(hwndDlg,IDC_MESSAGE),GWL_WNDPROC,(LONG)SendEditSubclassProc);
+ OldSendEditProc=(WNDPROC)SetWindowLong(GetWindow(GetDlgItem(hwndDlg,IDC_URLS),GW_CHILD),GWL_WNDPROC,(LONG)SendEditSubclassProc);
+
+ // From message dlg
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+
+ dat->hIcons[0]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[1]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[2]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_HISTORY),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ dat->hIcons[3]=(HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_DOWNARROW),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[0]);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[1]);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[2]);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BM_SETIMAGE,IMAGE_ICON,(LPARAM)dat->hIcons[3]);
+ SendDlgItemMessage(hwndDlg,IDC_ADD,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_DETAILS,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_HISTORY,BUTTONSETASFLATBTN,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_USERMENU,BUTTONSETASFLATBTN,0,0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_ADD), BUTTONADDTOOLTIP, (WPARAM)Translate("Add Contact Permanently to List"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_USERMENU), BUTTONADDTOOLTIP, (WPARAM)Translate("User Menu"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_DETAILS), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's Details"), 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("View User's History"), 0);
+
+ SendMessage(hwndDlg,DM_UPDATETITLE,0,0);
+ // From message dlg end
+
+ return TRUE;
+ case WM_DDE_DATA:
+ case WM_DDE_ACK:
+ return DdeMessage(hwndDlg,msg,wParam,lParam);
+ case WM_TIMER:
+ if (wParam==0)
+ {//ICQ sendurl timed out
+ KillTimer(hwndDlg,0);
+ MessageBox(hwndDlg,TranslateT("Send timed out"),_T(""),MB_OK);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_URLS),TRUE);
+ SendDlgItemMessage(hwndDlg,IDC_MESSAGE,EM_SETREADONLY,FALSE,0);
+ }
+ break;
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ }
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+
+ case DM_UPDATETITLE:
+ {
+ char newtitle[256],oldtitle[256];
+ char *szStatus,*contactName,*pszNewTitleStart;
+ char *szProto;
+
+ pszNewTitleStart=Translate("Send URL to");
+
+ if (dat->hContact) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ }
+ }
+
+ contactName=(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)dat->hContact,0);
+ SetDlgItemTextA(hwndDlg,IDC_NAME,hasName?buf:contactName);
+
+ szStatus=(char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,szProto==NULL?ID_STATUS_OFFLINE:DBGetContactSettingWord(dat->hContact,szProto,"Status",ID_STATUS_OFFLINE),0);
+ mir_snprintf(newtitle,SIZEOF(newtitle),"%s %s (%s)", pszNewTitleStart, contactName, szStatus);
+ }
+ }
+ else
+ lstrcpynA(newtitle, pszNewTitleStart, SIZEOF(newtitle));
+
+ GetWindowTextA(hwndDlg,oldtitle,SIZEOF(oldtitle));
+
+ if(lstrcmpA(newtitle,oldtitle)) //swt() flickers even if the title hasn't actually changed
+ SetWindowTextA(hwndDlg,newtitle);
+
+ break;
+
+ }
+
+ case WM_COMMAND:
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ char *body,*url;
+ int bodySize,urlSize;
+
+ urlSize=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_URLS))+1;
+ url=(char*)mir_alloc(urlSize);
+ GetDlgItemTextA(hwndDlg,IDC_URLS,url,urlSize);
+ if (url[0] == 0) {
+ mir_free(url);
+ break;
+ }
+ bodySize=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_MESSAGE))+1;
+ body=(char*)mir_alloc(bodySize);
+ GetDlgItemTextA(hwndDlg,IDC_MESSAGE,body,bodySize);
+
+ dat->sendBuffer=(char*)mir_realloc(dat->sendBuffer,lstrlenA(url)+lstrlenA(body)+2);
+ lstrcpyA(dat->sendBuffer,url);
+ lstrcpyA(dat->sendBuffer+lstrlenA(url)+1,body);
+ dat->hAckEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_EVENTSENT);
+ dat->hSendId=(HANDLE)CallContactService(dat->hContact,PSS_URL,0,(LPARAM)dat->sendBuffer);
+ mir_free(url);
+ mir_free(body);
+
+ //create a timeout timer
+ SetTimer(hwndDlg,0,TIMEOUT_URLSEND,NULL);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_URLS),FALSE);
+ SendDlgItemMessage(hwndDlg,IDC_MESSAGE,EM_SETREADONLY,TRUE,0);
+
+ return TRUE;
+ }
+
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_URLS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int i, urlSize;
+ char *title;
+ i=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCURSEL,0,0);
+ title=(char*)SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETITEMDATA,(WPARAM)i,0);
+ SetDlgItemTextA(hwndDlg,IDC_MESSAGE,title);
+ urlSize=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETLBTEXTLEN,(WPARAM)i,0);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK), (urlSize>0));
+ }
+ else if(HIWORD(wParam)==CBN_EDITCHANGE) {
+ int urlSize = GetWindowTextLength(GetDlgItem(hwndDlg,IDC_URLS));
+ EnableWindow(GetDlgItem(hwndDlg,IDOK), (urlSize>0));
+ }
+ break;
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto=0;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ }
+ break;
+ }
+ break;
+ case HM_EVENTSENT:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ DBEVENTINFO dbei;
+ if(ack->hProcess!=dat->hSendId) break;
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_URL || ack->result!=ACKRESULT_SUCCESS) break;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.eventType=EVENTTYPE_URL;
+ dbei.flags=DBEF_SENT;
+ dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ dbei.timestamp=time(NULL);
+ dbei.cbBlob=strlen(dat->sendBuffer)+strlen(dat->sendBuffer+strlen(dat->sendBuffer)+1)+2;
+ dbei.pBlob=dat->sendBuffer;
+ CallService(MS_DB_EVENT_ADD,(WPARAM)dat->hContact,(LPARAM)&dbei);
+ KillTimer(hwndDlg,0);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case WM_DESTROY:
+ WindowList_Remove(hUrlWindowList, hwndDlg);
+ {int i;for(i=0; i < SIZEOF(dat->hIcons); i++ ) DestroyIcon(dat->hIcons[i]);}
+ SetWindowLong(GetWindow(GetDlgItem(hwndDlg,IDC_URLS),GW_CHILD),GWL_WNDPROC,(LONG)OldSendEditProc);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_MESSAGE),GWL_WNDPROC,(LONG)OldSendEditProc);
+ if(dat->hAckEvent) UnhookEvent(dat->hAckEvent);
+ if(dat->sendBuffer!=NULL) mir_free(dat->sendBuffer);
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRUrl","send");
+ { int i;
+ for(i=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCOUNT,0,0)-1;i>=0;i--)
+ mir_free((char*)SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETITEMDATA,i,0));
+ }
+ break;
+ }
+
+ return FALSE;
+
+}
diff --git a/miranda-wine/src/modules/userinfo/contactinfo.c b/miranda-wine/src/modules/userinfo/contactinfo.c new file mode 100644 index 0000000..978a34a --- /dev/null +++ b/miranda-wine/src/modules/userinfo/contactinfo.c @@ -0,0 +1,503 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static HFONT hEmailFont=NULL;
+static HCURSOR hHandCursor=NULL;
+
+static BOOL CALLBACK EditUserEmailDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ if(*(char*)lParam) SetWindowText(hwndDlg,TranslateT("Edit E-Mail Address"));
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_EMAIL,(char*)lParam);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),*(char*)lParam);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,(char*)GetWindowLong(hwndDlg,GWL_USERDATA),256);
+ //fall through
+ case IDCANCEL:
+ EndDialog(hwndDlg,wParam);
+ case IDC_EMAIL:
+ if(HIWORD(wParam)==EN_CHANGE)
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),GetWindowTextLength(GetDlgItem(hwndDlg,IDC_EMAIL)));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK EditUserPhoneDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { char *szText=(char*)lParam;
+ int i,item,countryCount;
+ struct CountryListEntry *countries;
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ if(szText[0]) SetWindowTextA(hwndDlg,"Edit Phone Number");
+ TranslateDialogDefault(hwndDlg);
+ if(lstrlenA(szText)>4 && !lstrcmpA(szText+lstrlenA(szText)-4," SMS")) {
+ CheckDlgButton(hwndDlg,IDC_SMS,BST_CHECKED);
+ szText[lstrlenA(szText)-4]='\0';
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),szText[0]);
+ SendDlgItemMessage(hwndDlg,IDC_AREA,EM_LIMITTEXT,31,0);
+ SendDlgItemMessage(hwndDlg,IDC_NUMBER,EM_LIMITTEXT,63,0);
+ CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&countryCount,(LPARAM)&countries);
+ for(i=0;i<countryCount;i++) {
+ if(countries[i].id==0 || countries[i].id==0xFFFF) continue;
+ item=SendDlgItemMessageA(hwndDlg,IDC_COUNTRY,CB_ADDSTRING,0,(LPARAM)countries[i].szName);
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETITEMDATA,item,countries[i].id);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_PHONE,szText);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ static int noRecursion=0;
+
+ case IDOK:
+ { char *szText=(char*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ int isValid=1;
+ GetDlgItemTextA(hwndDlg,IDC_PHONE,szText,252);
+ if(lstrlenA(szText)<7 || szText[0]!='+') isValid=0;
+ if(isValid) isValid=(lstrlenA(szText+1)==(int)strspn(szText+1,"0123456789 ()-"));
+ if(!isValid) {
+ MessageBox(hwndDlg,TranslateT("The phone number should start with a + and consist of numbers, spaces, brackets and hyphens only."),TranslateT("Invalid Phone Number"),MB_OK);
+ break;
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_SMS)) lstrcatA(szText," SMS");
+ }
+ //fall through
+ case IDCANCEL:
+ EndDialog(hwndDlg,wParam);
+ case IDC_COUNTRY:
+ if(HIWORD(wParam)!=CBN_SELCHANGE) break;
+ case IDC_AREA:
+ case IDC_NUMBER:
+ if(LOWORD(wParam)!=IDC_COUNTRY && HIWORD(wParam)!=EN_CHANGE) break;
+ if(noRecursion) break;
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ { char szPhone[96],szArea[32],szNumber[64];
+ GetDlgItemTextA(hwndDlg,IDC_AREA,szArea,SIZEOF(szArea));
+ GetDlgItemTextA(hwndDlg,IDC_NUMBER,szNumber,SIZEOF(szNumber));
+ mir_snprintf(szPhone,SIZEOF(szPhone),"+%u (%s) %s",SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETCURSEL,0,0),0),szArea,szNumber);
+ noRecursion=1;
+ SetDlgItemTextA(hwndDlg,IDC_PHONE,szPhone);
+ noRecursion=0;
+ }
+ break;
+ case IDC_PHONE:
+ if(HIWORD(wParam)!=EN_UPDATE) break;
+ if(noRecursion) break;
+ noRecursion=1;
+ { char szText[256],*pText,*pArea,*pNumber;
+ int isValid=1;
+ GetDlgItemTextA(hwndDlg,IDC_PHONE,szText,SIZEOF(szText));
+ if(szText[0]!='+') isValid=0;
+ if(isValid) {
+ int i,country=strtol(szText+1,&pText,10);
+ if(pText-szText>4) isValid=0;
+ else for(i=SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETCOUNT,0,0)-1;i>=0;i--)
+ if(country==SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETITEMDATA,i,0))
+ {SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETCURSEL,i,0); break;}
+ if(i<0) isValid=0;
+ }
+ if(isValid) {
+ pArea=pText+strcspn(pText,"0123456789");
+ pText=pArea+strspn(pArea,"0123456789");
+ if(*pText) {
+ *pText='\0';
+ pNumber=pText+1+strcspn(pText+1,"0123456789");
+ SetDlgItemTextA(hwndDlg,IDC_NUMBER,pNumber);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_AREA,pArea);
+ }
+ if(!isValid) {
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETCURSEL,-1,0);
+ SetDlgItemTextA(hwndDlg,IDC_AREA,"");
+ SetDlgItemTextA(hwndDlg,IDC_NUMBER,"");
+ }
+ }
+ noRecursion=0;
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),GetWindowTextLength(GetDlgItem(hwndDlg,IDC_PHONE)));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int IsOverEmail(HWND hwndDlg,TCHAR* szEmail,int cchEmail)
+{
+ RECT rc;
+ HWND hwndEmails;
+ TCHAR szText[256];
+ HDC hdc;
+ SIZE textSize;
+ LVHITTESTINFO hti;
+
+ hwndEmails=GetDlgItem(hwndDlg,IDC_EMAILS);
+ GetCursorPos(&hti.pt);
+ ScreenToClient(hwndEmails,&hti.pt);
+ GetClientRect(hwndEmails,&rc);
+ if(!PtInRect(&rc,hti.pt)) return 0;
+ if(ListView_SubItemHitTest(hwndEmails,&hti)==-1) return 0;
+ if(hti.iSubItem!=1) return 0;
+ if(!(hti.flags&LVHT_ONITEMLABEL)) return 0;
+ ListView_GetSubItemRect(hwndEmails,hti.iItem,1,LVIR_LABEL,&rc);
+ ListView_GetItemText(hwndEmails,hti.iItem,1,szText,SIZEOF(szText));
+ hdc=GetDC(hwndEmails);
+ SelectObject(hdc,hEmailFont);
+ GetTextExtentPoint32(hdc,szText,lstrlen(szText),&textSize);
+ ReleaseDC(hwndEmails,hdc);
+ if(hti.pt.x<rc.left+textSize.cx) {
+ if(szEmail && cchEmail) lstrcpyn(szEmail,szText,cchEmail);
+ return 1;
+ }
+ return 0;
+}
+
+#define M_REMAKELISTS (WM_USER+1)
+BOOL CALLBACK ContactDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ if(hEmailFont) DeleteObject(hEmailFont);
+ { LOGFONT lf;
+ hEmailFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_EMAILS,WM_GETFONT,0,0);
+ GetObject(hEmailFont,sizeof(lf),&lf);
+ lf.lfUnderline=1;
+ hEmailFont=CreateFontIndirect(&lf);
+ }
+ if(hHandCursor==NULL) {
+ if(IsWinVer2000Plus()) hHandCursor=LoadCursor(NULL,IDC_HAND);
+ else hHandCursor=LoadCursor(GetModuleHandle(NULL),MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ }
+ TranslateDialogDefault(hwndDlg);
+ { LVCOLUMN lvc;
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_EMAILS),&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask=LVCF_WIDTH;
+ lvc.cx=rc.right/4;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),0,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),0,&lvc);
+ lvc.cx=rc.right-rc.right/4-40;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),1,&lvc);
+ lvc.cx=rc.right-rc.right/4-90;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),1,&lvc);
+ lvc.cx=50;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),2,&lvc);
+ lvc.cx=20;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),2,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),3,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),3,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),4,&lvc);
+ }
+ return TRUE;
+ case M_REMAKELISTS:
+ { char *szProto;
+ LVITEM lvi;
+ int i;
+ char idstr[33];
+ TCHAR idstr2[33];
+ DBVARIANT dbv;
+ HANDLE hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ //e-mails
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_EMAILS));
+ lvi.mask=LVIF_TEXT|LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-1);
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=-1;;i++) {
+ if(i==-1) {
+ if(DBGetContactSettingTString(hContact,szProto,"e-mail",&dbv))
+ continue;
+ lvi.pszText=TranslateT("Primary");
+ }
+ else {
+ wsprintfA(idstr, "e-mail%d", i );
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ wsprintf(idstr2,_T("%d"),i+2);
+ }
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_EMAILS),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.iSubItem=0;
+ for(i=0;;i++) {
+ lvi.lParam=i;
+ wsprintfA(idstr,"Mye-mail%d",i);
+ if(DBGetContactSettingTString(hContact,"UserInfo",idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ wsprintf(idstr2,TranslateT("Custom %d"),i+1);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_EMAILS),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.mask=LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-2);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ //phones
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PHONES));
+ lvi.mask=LVIF_TEXT|LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-1);
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ if(!DBGetContactSettingTString(hContact,szProto,"Phone",&dbv)) {
+ lvi.pszText=TranslateT("Primary");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"Fax",&dbv)) {
+ lvi.pszText=TranslateT("Fax");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"Cellular",&dbv)) {
+ lvi.pszText=TranslateT("Mobile");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ if(lstrlenA(dbv.pszVal)>4 && !lstrcmpA(dbv.pszVal+lstrlenA(dbv.pszVal)-4," SMS")) {
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,2,_T("y"));
+ dbv.ptszVal[lstrlen(dbv.ptszVal)-4]='\0';
+ }
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"CompanyPhone",&dbv)) {
+ lvi.pszText=TranslateT("Work Phone");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"CompanyFax",&dbv)) {
+ lvi.pszText=TranslateT("Work Fax");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.iSubItem=0;
+ for(i=0;;i++) {
+ lvi.lParam=i;
+ wsprintfA(idstr,"MyPhone%d",i);
+ if(DBGetContactSettingTString(hContact,"UserInfo",idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ wsprintf(idstr2,TranslateT("Custom %d"),i+1);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ if(lstrlen(dbv.ptszVal)>4 && !lstrcmp(dbv.ptszVal+lstrlen(dbv.ptszVal)-4,_T(" SMS"))) {
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,2,_T("y"));
+ dbv.ptszVal[lstrlen(dbv.ptszVal)-4]='\0';
+ }
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.mask=LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-2);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_INFOCHANGED:
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ break;
+ }
+ break;
+ case IDC_EMAILS:
+ case IDC_PHONES:
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_CUSTOMDRAW:
+ { NMLVCUSTOMDRAW *nm=(NMLVCUSTOMDRAW*)lParam;
+ switch(nm->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,CDRF_NOTIFYSUBITEMDRAW);
+ return TRUE;
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ RECT rc;
+ HICON hIcon;
+ ListView_GetSubItemRect(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,LVIR_LABEL,&rc);
+ if(nm->iSubItem==1 && nm->nmcd.hdr.idFrom==IDC_EMAILS) {
+ HFONT hoFont;
+ TCHAR szText[256];
+ ListView_GetItemText(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,szText,SIZEOF(szText));
+ hoFont=(HFONT)SelectObject(nm->nmcd.hdc,hEmailFont);
+ SetTextColor(nm->nmcd.hdc,RGB(0,0,255));
+ DrawText(nm->nmcd.hdc,szText,-1,&rc,DT_END_ELLIPSIS|DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ SelectObject(nm->nmcd.hdc,hoFont);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,CDRF_SKIPDEFAULT);
+ return TRUE;
+ }
+ if(nm->nmcd.lItemlParam==(LPARAM)(-2) && nm->iSubItem-3==(nm->nmcd.hdr.idFrom==IDC_PHONES))
+ hIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ADDCONTACT),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ else if(nm->iSubItem>1 && nm->nmcd.lItemlParam!=(LPARAM)(-1) && nm->nmcd.lItemlParam!=(LPARAM)(-2)) {
+ static int iconResources[3]={IDI_RENAME,IDI_DELETE};
+ if(nm->iSubItem==2 && nm->nmcd.hdr.idFrom==IDC_PHONES) {
+ TCHAR szText[2];
+ ListView_GetItemText(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,szText,SIZEOF(szText));
+ if(szText[0]) hIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SMS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ }
+ else hIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(iconResources[nm->iSubItem-3+(nm->nmcd.hdr.idFrom==IDC_EMAILS)]),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0);
+ }
+ else break;
+ DrawIconEx(nm->nmcd.hdc,(rc.left+rc.right-GetSystemMetrics(SM_CXSMICON))/2,(rc.top+rc.bottom-GetSystemMetrics(SM_CYSMICON))/2,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,CDRF_SKIPDEFAULT);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case NM_CLICK:
+ { NMLISTVIEW *nm=(NMLISTVIEW*)lParam;
+ LVITEM lvi;
+ TCHAR szEmail[256];
+ HANDLE hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ char *szIdTemplate=nm->hdr.idFrom==IDC_PHONES?"MyPhone%d":"Mye-mail%d";
+ LVHITTESTINFO hti;
+
+ if(IsOverEmail(hwndDlg,szEmail,SIZEOF(szEmail))) {
+ TCHAR szExec[264];
+ lstrcpy(szExec, _T("mailto:"));
+ lstrcat(szExec,szEmail);
+ ShellExecute(hwndDlg,_T("open"),szExec,NULL,NULL,SW_SHOW);
+ break;
+ }
+ if(nm->iSubItem<2) break;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(nm->hdr.hwndFrom,&hti.pt);
+ if(ListView_SubItemHitTest(nm->hdr.hwndFrom,&hti)==-1) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=hti.iItem;
+ lvi.iSubItem=0;
+ ListView_GetItem(nm->hdr.hwndFrom,&lvi);
+ if(lvi.lParam==(LPARAM)(-1)) break;
+ if(lvi.lParam==(LPARAM)(-2)) {
+ if(hti.iSubItem-3==(nm->hdr.idFrom==IDC_PHONES)) {
+ //add
+ char szNewData[256]="",idstr[33];
+ int i;
+ DBVARIANT dbv;
+ if(IDOK!=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(nm->hdr.idFrom==IDC_PHONES?IDD_ADDPHONE:IDD_ADDEMAIL),hwndDlg,nm->hdr.idFrom==IDC_PHONES?EditUserPhoneDlgProc:EditUserEmailDlgProc,(LPARAM)szNewData))
+ break;
+ for(i=0;;i++) {
+ wsprintfA(idstr,szIdTemplate,i);
+ if(DBGetContactSetting(hContact,"UserInfo",idstr,&dbv)) break;
+ DBFreeVariant(&dbv);
+ }
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,szNewData);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ }
+ else {
+ if(hti.iSubItem-3==(nm->hdr.idFrom==IDC_PHONES)) {
+ //delete
+ int i;
+ char idstr[33];
+ DBVARIANT dbv;
+ for(i=lvi.lParam;;i++) {
+ wsprintfA(idstr,szIdTemplate,i+1);
+ if(DBGetContactSetting(hContact,"UserInfo",idstr,&dbv)) break;
+ wsprintfA(idstr,szIdTemplate,i);
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ wsprintfA(idstr,szIdTemplate,i);
+ DBDeleteContactSetting(hContact,"UserInfo",idstr);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ else if(hti.iSubItem-2==(nm->hdr.idFrom==IDC_PHONES)) {
+ //edit
+ char szText[256],idstr[33];
+ DBVARIANT dbv;
+ wsprintfA(idstr,szIdTemplate,lvi.lParam);
+ if(DBGetContactSetting(hContact,"UserInfo",idstr,&dbv)) break;
+ lstrcpynA(szText,dbv.pszVal,SIZEOF(szText));
+ DBFreeVariant(&dbv);
+ if(IDOK!=DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(nm->hdr.idFrom==IDC_PHONES?IDD_ADDPHONE:IDD_ADDEMAIL),hwndDlg,nm->hdr.idFrom==IDC_PHONES?EditUserPhoneDlgProc:EditUserEmailDlgProc,(LPARAM)szText))
+ break;
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,szText);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_SETCURSOR:
+ if(LOWORD(lParam)!=HTCLIENT) break;
+ if(GetForegroundWindow()==GetParent(hwndDlg)) {
+ POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hwndDlg,&pt);
+ SetFocus(ChildWindowFromPoint(hwndDlg,pt)); //ugly hack because listviews ignore their first click
+ }
+ if(IsOverEmail(hwndDlg,NULL,0)) {
+ SetCursor(hHandCursor);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/src/modules/userinfo/stdinfo.c b/miranda-wine/src/modules/userinfo/stdinfo.c new file mode 100644 index 0000000..79928bd --- /dev/null +++ b/miranda-wine/src/modules/userinfo/stdinfo.c @@ -0,0 +1,541 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+BOOL CALLBACK ContactDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void Utf8Decode( char* str, wchar_t** ucs2 );
+
+
+#define SVS_NORMAL 0
+#define SVS_GENDER 1
+#define SVS_ZEROISUNSPEC 2
+#define SVS_IP 3
+#define SVS_COUNTRY 4
+#define SVS_MONTH 5
+#define SVS_SIGNED 6
+#define SVS_TIMEZONE 7
+#define SVS_ICQVERSION 8
+
+static void SetValue(HWND hwndDlg,int idCtrl,HANDLE hContact,char *szModule,char *szSetting,int special)
+{
+ DBVARIANT dbv;
+ char str[80],*pstr = NULL;
+ TCHAR* ptstr = NULL;
+ int unspecified=0;
+
+ dbv.type=DBVT_DELETED;
+ if(szModule==NULL) unspecified=1;
+ else unspecified=DBGetContactSettingW(hContact,szModule,szSetting,&dbv);
+ if(!unspecified) {
+ switch(dbv.type) {
+ case DBVT_BYTE:
+ if(special==SVS_GENDER) {
+ if(dbv.cVal=='M') ptstr=TranslateT("Male");
+ else if(dbv.cVal=='F') ptstr=TranslateT("Female");
+ else unspecified=1;
+ }
+ else if(special==SVS_MONTH) {
+ if(dbv.bVal>0 && dbv.bVal<=12) {
+ pstr=str;
+ GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_SABBREVMONTHNAME1-1+dbv.bVal,str,SIZEOF(str));
+ }
+ else unspecified=1;
+ }
+ else if(special==SVS_TIMEZONE) {
+ if(dbv.cVal==-100) unspecified=1;
+ else {
+ pstr=str;
+ sprintf(str,dbv.cVal?"GMT%+d:%02d":"GMT",-dbv.cVal/2,(dbv.cVal&1)*30);
+ }
+ }
+ else {
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.bVal==0);
+ pstr=_itoa(special==SVS_SIGNED?dbv.cVal:dbv.bVal,str,10);
+ }
+ break;
+ case DBVT_WORD:
+ if(special==SVS_COUNTRY) {
+ pstr=(char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,dbv.wVal,0);
+ unspecified=pstr==NULL;
+ }
+ else if (special == SVS_ICQVERSION) {
+ if (dbv.wVal != 0) {
+ static char *szVersionDescr[] = {"", "ICQ 1.x", "ICQ 2.x", "Unknown", "ICQ98", "Unknown", "ICQ99 / licq", "ICQ2000", "ICQ2001-2003, Miranda or Trillian", "ICQ Lite"};
+ pstr = str;
+ wsprintfA(str, "%d: %s", dbv.wVal, dbv.wVal > 9 ? Translate("Unknown") : Translate(szVersionDescr[dbv.wVal]));
+ }
+ else unspecified = 1;
+ }
+ else {
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.wVal==0);
+ pstr=_itoa(special==SVS_SIGNED?dbv.sVal:dbv.wVal,str,10);
+ }
+ break;
+ case DBVT_DWORD:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.dVal==0);
+ if(special==SVS_IP) {
+ struct in_addr ia;
+ ia.S_un.S_addr=htonl(dbv.dVal);
+ pstr=inet_ntoa(ia);
+ if(dbv.dVal==0) unspecified=1;
+ }
+ else pstr=_itoa(special==SVS_SIGNED?dbv.lVal:dbv.dVal,str,10);
+ break;
+ case DBVT_ASCIIZ:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.pszVal[0]=='\0');
+ pstr=dbv.pszVal;
+ break;
+ case DBVT_UTF8:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.pszVal[0]=='\0');
+ #if defined( _UNICODE )
+ if ( !unspecified )
+ { WCHAR* wszStr;
+ Utf8Decode( dbv.pszVal, &wszStr );
+ SetDlgItemTextW( hwndDlg, idCtrl, wszStr);
+ mir_free( wszStr );
+ goto LBL_Exit;
+ }
+ #endif
+ pstr=dbv.pszVal;
+ Utf8Decode( dbv.pszVal, NULL );
+ break;
+ default: pstr=str; lstrcpyA(str,"???"); break;
+ } }
+
+ if (unspecified)
+ SetDlgItemText(hwndDlg, idCtrl, TranslateT("<not specified>"));
+ else if ( ptstr != NULL )
+ SetDlgItemText(hwndDlg, idCtrl, ptstr);
+ else
+ SetDlgItemTextA(hwndDlg, idCtrl, pstr);
+
+#if defined( _UNICODE )
+LBL_Exit:
+#endif
+ EnableWindow(GetDlgItem(hwndDlg, idCtrl), !unspecified);
+ DBFreeVariant(&dbv);
+}
+
+static BOOL CALLBACK SummaryDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED )
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_NICK,hContact,szProto,"Nick",0);
+ SetValue(hwndDlg,IDC_FIRSTNAME,hContact,szProto,"FirstName",0);
+ SetValue(hwndDlg,IDC_LASTNAME,hContact,szProto,"LastName",0);
+ SetValue(hwndDlg,IDC_EMAIL,hContact,szProto,"e-mail",0);
+ SetValue(hwndDlg,IDC_AGE,hContact,szProto,"Age",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_GENDER,hContact,szProto,"Gender",SVS_GENDER);
+ SetValue(hwndDlg,IDC_DOBDAY,hContact,szProto,"BirthDay",0);
+ SetValue(hwndDlg,IDC_DOBMONTH,hContact,szProto,"BirthMonth",SVS_MONTH);
+ SetValue(hwndDlg,IDC_DOBYEAR,hContact,szProto,"BirthYear",0);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_EMAIL:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_EMAIL))) {
+ char szExec[264],szEmail[256];
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,szEmail,SIZEOF(szEmail));
+ lstrcpyA(szExec,"mailto:");
+ lstrcatA(szExec,szEmail);
+ ShellExecuteA(hwndDlg,"open",szExec,NULL,NULL,SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK LocationDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ TranslateDialogDefault(hwndDlg);
+ SetTimer(hwndDlg,1,1000,NULL);
+ SendMessage(hwndDlg,WM_TIMER,0,0);
+ return TRUE;
+ case WM_TIMER:
+ { char *szProto;
+ HANDLE hContact=(HANDLE)GetWindowLong(hwndDlg,GWL_USERDATA);
+ int timezone;
+ FILETIME ft;
+ LARGE_INTEGER lift;
+ char szTime[80];
+ SYSTEMTIME st;
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ timezone=DBGetContactSettingByte(hContact,szProto,"Timezone",256);
+ if(timezone==256 || (char)timezone==-100) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LOCALTIME),FALSE);
+ SetDlgItemText(hwndDlg,IDC_LOCALTIME,TranslateT("<not specified>"));
+ }
+ else {
+ TIME_ZONE_INFORMATION tzi;
+
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LOCALTIME),TRUE);
+ timezone=(char)timezone;
+ GetSystemTimeAsFileTime(&ft);
+ switch (GetTimeZoneInformation(&tzi)) {
+ case TIME_ZONE_ID_DAYLIGHT:
+ timezone+=tzi.DaylightBias/30;
+ break;
+ }
+ lift.QuadPart=*(__int64*)&ft;
+ lift.QuadPart-=(__int64)timezone*BIGI(30)*BIGI(60)*BIGI(10000000);
+ *(__int64*)&ft=lift.QuadPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,szTime,SIZEOF(szTime));
+ SetDlgItemTextA(hwndDlg,IDC_LOCALTIME,szTime);
+ }
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED )
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_STREET,hContact,szProto,"Street",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_CITY,hContact,szProto,"City",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STATE,hContact,szProto,"State",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_ZIP,hContact,szProto,"ZIP",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_COUNTRY,hContact,szProto,"Country",SVS_COUNTRY);
+ SetValue(hwndDlg,IDC_LANGUAGE1,hContact,szProto,"Language1",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_LANGUAGE2,hContact,szProto,"Language2",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_LANGUAGE3,hContact,szProto,"Language3",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_TIMEZONE,hContact,szProto,"Timezone",SVS_TIMEZONE);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK WorkDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED)
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_COMPANY,hContact,szProto,"Company",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_DEPARTMENT,hContact,szProto,"CompanyDepartment",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_POSITION,hContact,szProto,"CompanyPosition",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STREET,hContact,szProto,"CompanyStreet",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_CITY,hContact,szProto,"CompanyCity",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STATE,hContact,szProto,"CompanyState",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_ZIP,hContact,szProto,"CompanyZIP",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_COUNTRY,hContact,szProto,"CompanyCountry",SVS_COUNTRY);
+ SetValue(hwndDlg,IDC_WEBPAGE,hContact,szProto,"CompanyHomepage",SVS_ZEROISUNSPEC);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_WEBPAGE:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_WEBPAGE))) {
+ char szPage[256];
+ GetDlgItemTextA(hwndDlg,IDC_WEBPAGE,szPage,SIZEOF(szPage));
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szPage);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+// Resizes all columns in a listview (report style)
+// to make all text visible
+void ResizeColumns(HWND hwndLV)
+{
+ int nCol = 0; LVCOLUMN lvCol;
+ lvCol.mask = LVCF_WIDTH;
+ while(ListView_GetColumn(hwndLV, nCol++, &lvCol))
+ ListView_SetColumnWidth(hwndLV, nCol-1, LVSCW_AUTOSIZE);
+}
+
+static BOOL CALLBACK BackgroundDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { LVCOLUMN lvc;
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_PAST),&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask=LVCF_WIDTH;
+ lvc.cx=rc.right/3;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PAST),0,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_INTERESTS),0,&lvc);
+ lvc.cx=rc.right-rc.right/3;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PAST),1,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_INTERESTS),1,&lvc);
+ }
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_PAST),LVS_EX_LABELTIP,LVS_EX_LABELTIP);
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_INTERESTS),LVS_EX_LABELTIP,LVS_EX_LABELTIP);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED)
+ { char *szProto;
+ LVITEM lvi;
+ int i;
+ char idstr[33];
+ DBVARIANT dbv,dbvText;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_WEBPAGE,hContact,szProto,"Homepage",SVS_ZEROISUNSPEC);
+
+ //past
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PAST));
+ lvi.mask=LVIF_TEXT;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=0;;i++) {
+ wsprintfA(idstr,"Past%d",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ wsprintfA(idstr,"Past%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PAST),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PAST),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+
+ for(i=0;;i++) {
+ wsprintfA(idstr,"Affiliation%d",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ wsprintfA(idstr,"Affiliation%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PAST),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PAST),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+
+ ResizeColumns(GetDlgItem(hwndDlg,IDC_PAST));
+
+ //interests
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_INTERESTS));
+ lvi.mask=LVIF_TEXT;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=0;;i++) {
+ wsprintfA(idstr,"Interest%dCat",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ wsprintfA(idstr,"Interest%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_INTERESTS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_INTERESTS),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ ResizeColumns(GetDlgItem(hwndDlg,IDC_INTERESTS));
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_WEBPAGE:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_WEBPAGE))) {
+ char szPage[256];
+ GetDlgItemTextA(hwndDlg,IDC_WEBPAGE,szPage,SIZEOF(szPage));
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szPage);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK NotesDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { DBVARIANT dbv;
+ if(!DBGetContactSetting((HANDLE)lParam,"UserInfo","MyNotes",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_MYNOTES,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ SendDlgItemMessage(hwndDlg,IDC_MYNOTES,EM_LIMITTEXT,2048,0);
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_INFOCHANGED:
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_ABOUT,hContact,szProto,"About",0);
+ }
+ break;
+ }
+ case PSN_APPLY:
+ { HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if(GetWindowTextLength(GetDlgItem(hwndDlg,IDC_MYNOTES))) {
+ char text[2048];
+ GetDlgItemTextA(hwndDlg,IDC_MYNOTES,text,SIZEOF(text));
+ DBWriteContactSettingString(hContact,"UserInfo","MyNotes",text);
+ }
+ else DBDeleteContactSetting(hContact,"UserInfo","MyNotes");
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ if(wParam==MAKEWPARAM(IDC_MYNOTES,EN_CHANGE))
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ else if(LOWORD(wParam)==IDCANCEL)
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ return FALSE;
+}
+
+int DetailsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ if ((HANDLE)lParam == NULL)
+ return 0;
+
+ if ( CallService(MS_PROTO_GETCONTACTBASEPROTO, lParam, 0) == 0 )
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.flags = 0;
+
+ odp.pfnDlgProc = SummaryDlgProc;
+ odp.position = -2100000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_SUMMARY);
+ odp.pszTitle = "Summary";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = ContactDlgProc;
+ odp.position = -1800000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_CONTACT);
+ odp.pszTitle = "Contact";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = LocationDlgProc;
+ odp.position = -1500000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_LOCATION);
+ odp.pszTitle = "Location";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = WorkDlgProc;
+ odp.position = -1200000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_WORK);
+ odp.pszTitle = "Work";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = BackgroundDlgProc;
+ odp.position = -900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_BACKGROUND);
+ odp.pszTitle = "Background";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = NotesDlgProc;
+ odp.position = 0;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_NOTES);
+ odp.pszTitle = "Notes";
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/userinfo/userinfo.c b/miranda-wine/src/modules/userinfo/userinfo.c new file mode 100644 index 0000000..1456c95 --- /dev/null +++ b/miranda-wine/src/modules/userinfo/userinfo.c @@ -0,0 +1,500 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#define UPDATEANIMFRAMES 20
+
+int DetailsInit(WPARAM wParam,LPARAM lParam);
+static BOOL CALLBACK DlgProcDetails(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HANDLE hWindowList=NULL;
+static HANDLE hDetailsInitEvent;
+
+struct DetailsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DetailsPageData {
+ DLGTEMPLATE *pTemplate;
+ HINSTANCE hInst;
+ DLGPROC dlgProc;
+ HWND hwnd;
+ HTREEITEM hItem;
+ int changed;
+};
+
+struct DetailsData {
+ HANDLE hContact;
+ HANDLE hProtoAckEvent;
+ HINSTANCE hInstIcmp;
+ HFONT hBoldFont;
+ int pageCount;
+ int currentPage;
+ struct DetailsPageData *opd;
+ RECT rcDisplay;
+ int updateAnimFrame;
+ TCHAR szUpdating[64];
+ int *infosUpdated;
+};
+
+static int PageSortProc(OPTIONSDIALOGPAGE *item1,OPTIONSDIALOGPAGE *item2)
+{
+ if(item2->position>item1->position) return -1;
+ if(item2->position<item1->position) return 1;
+ return 0;
+}
+
+static int ShowDetailsDialogCommand(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ PROPSHEETHEADER psh;
+ struct DetailsPageInit opi;
+ int i;
+
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ return 0;
+ }
+
+ opi.pageCount=0;
+ opi.odp=NULL;
+ NotifyEventHooks(hDetailsInitEvent,(WPARAM)&opi,wParam);
+ if(opi.pageCount==0) return 0;
+ qsort(opi.odp,opi.pageCount,sizeof(OPTIONSDIALOGPAGE),(int (*)(const void*,const void*))PageSortProc);
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = 0;
+ psh.pszCaption = (TCHAR*)wParam; //more abuses of structure: this is hContact
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+ CreateDialogParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DETAILS),NULL,DlgProcDetails,(LPARAM)&psh);
+ for(i=0;i<opi.pageCount;i++) {
+ mir_free((char*)opi.odp[i].pszTitle);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ mir_free(opi.odp);
+ return 0;
+}
+
+static int AddDetailsPage(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct DetailsPageInit *opi=(struct DetailsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)) return 1;
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ dst->cbSize = sizeof(OPTIONSDIALOGPAGE);
+ dst->hInstance = odp->hInstance;
+ dst->pfnDlgProc = odp->pfnDlgProc;
+ dst->position = odp->position;
+ if((DWORD)odp->pszTemplate&0xFFFF0000) dst->pszTemplate = mir_strdup(odp->pszTemplate);
+ else dst->pszTemplate = odp->pszTemplate;
+
+ #if defined(_UNICODE)
+ if ( odp->flags == ODPF_UNICODE )
+ dst->ptszTitle = (odp->ptszTitle==0) ? NULL : mir_wstrdup(odp->ptszTitle);
+ else
+ #endif
+ dst->ptszTitle = (odp->pszTitle==0) ? NULL : LangPackPcharToTchar(odp->pszTitle);
+
+ dst->pszGroup = NULL;
+ dst->groupPosition = odp->groupPosition;
+ dst->hGroupIcon = odp->hGroupIcon;
+ dst->hIcon = odp->hIcon;
+ opi->pageCount++;
+ return 0;
+}
+
+static int UserInfoContactDelete(WPARAM wParam,LPARAM lParam)
+{
+ HWND hwnd;
+ hwnd=WindowList_Find(hWindowList,(HANDLE)wParam);
+ if(hwnd!=NULL) DestroyWindow(hwnd);
+ return 0;
+}
+
+static void ThemeDialogBackground(HWND hwnd) {
+ if (IsWinVerXPPlus()) {
+ static HMODULE hThemeAPI = NULL;
+ if (!hThemeAPI) hThemeAPI = GetModuleHandleA("uxtheme");
+ if (hThemeAPI) {
+ HRESULT (STDAPICALLTYPE *MyEnableThemeDialogTexture)(HWND,DWORD) = (HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(hThemeAPI,"EnableThemeDialogTexture");
+ if (MyEnableThemeDialogTexture)
+ MyEnableThemeDialogTexture(hwnd,0x00000002|0x00000004); //0x00000002|0x00000004=ETDT_ENABLETAB
+ }
+ }
+}
+
+#define HM_PROTOACK (WM_USER+10)
+#define M_CHECKONLINE (WM_USER+11)
+static BOOL CALLBACK DlgProcDetails(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DetailsData *dat =(struct DetailsData*)GetWindowLong(hwndDlg,GWL_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { PROPSHEETHEADER *psh=(PROPSHEETHEADER*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_USERDETAILS)));
+ dat=(struct DetailsData*)mir_alloc(sizeof(struct DetailsData));
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)dat);
+ dat->hContact=(HANDLE)psh->pszCaption;
+ dat->hProtoAckEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_PROTOACK);
+ dat->infosUpdated=NULL;
+ WindowList_Add(hWindowList,hwndDlg,dat->hContact);
+ {
+ TCHAR *name, oldTitle[256], newTitle[256];
+ if (dat->hContact == NULL)
+ name = TranslateT("Owner");
+ else
+ name = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)dat->hContact, GCDNF_TCHAR);
+
+ GetWindowText( hwndDlg, oldTitle, SIZEOF( oldTitle ));
+ mir_sntprintf( newTitle, SIZEOF(newTitle), oldTitle, name );
+ SetWindowText( hwndDlg, newTitle );
+ SetDlgItemText( hwndDlg, IDC_NAME, name );
+ }
+ { LOGFONT lf;
+ HFONT hNormalFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_NAME,WM_GETFONT,0,0);
+ GetObject(hNormalFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,(WPARAM)dat->hBoldFont,0);
+ }
+ { OPTIONSDIALOGPAGE *odp;
+ int i;
+ TVINSERTSTRUCT tvis;
+ DBVARIANT dbv;
+
+ dat->currentPage=0;
+ if(DBGetContactSettingTString(NULL,"UserInfo","LastTab",&dbv))
+ dbv.type=DBVT_DELETED;
+ dat->pageCount=psh->nPages;
+ dat->opd=(struct DetailsPageData*)mir_alloc(sizeof(struct DetailsPageData)*dat->pageCount);
+ odp=(OPTIONSDIALOGPAGE*)psh->ppsp;
+
+ for(i=0;i<dat->pageCount;i++) {
+ dat->opd[i].pTemplate=(DLGTEMPLATE *)LockResource(LoadResource(odp[i].hInstance,FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5))));
+ dat->opd[i].dlgProc=odp[i].pfnDlgProc;
+ dat->opd[i].hInst=odp[i].hInstance;
+ dat->opd[i].hwnd=NULL;
+ dat->opd[i].changed=0;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
+ tvis.item.lParam = (LPARAM) i;
+ tvis.item.pszText = odp[i].ptszTitle;
+ if(dbv.type!=DBVT_DELETED && !lstrcmp(tvis.item.pszText,dbv.ptszVal))
+ dat->currentPage=i;
+ dat->opd[i].hItem = TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_PAGETREE), &tvis);
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_TABS),&dat->rcDisplay);
+ TabCtrl_AdjustRect(GetDlgItem(hwndDlg,IDC_TABS),FALSE,&dat->rcDisplay);
+ { POINT pt={0,0};
+ ClientToScreen(hwndDlg,&pt);
+ OffsetRect(&dat->rcDisplay,-pt.x,-pt.y);
+ }
+ TreeView_Select(GetDlgItem(hwndDlg,IDC_PAGETREE), dat->opd[dat->currentPage].hItem, TVGN_CARET);
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->hContact);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd, HWND_TOP, dat->rcDisplay.left, dat->rcDisplay.top, dat->rcDisplay.right - dat->rcDisplay.left, dat->rcDisplay.bottom - dat->rcDisplay.top, 0);
+ { PSHNOTIFY pshn;
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ dat->updateAnimFrame=0;
+ GetDlgItemText(hwndDlg,IDC_UPDATING,dat->szUpdating,SIZEOF(dat->szUpdating));
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ if(!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_UPDATE)))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ else {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ SetTimer(hwndDlg,1,100,NULL);
+ }
+ CallContactService(dat->hContact,PSS_GETINFO,SGIF_ONOPEN,0);
+ return TRUE;
+ }
+ case WM_TIMER:
+ { TCHAR str[128];
+ mir_sntprintf(str,SIZEOF(str), _T("%.*s%s%.*s"),dat->updateAnimFrame%10,_T("........."),dat->szUpdating,dat->updateAnimFrame%10,_T("........."));
+ SetDlgItemText(hwndDlg,IDC_UPDATING,str);
+ if(++dat->updateAnimFrame==UPDATEANIMFRAMES) dat->updateAnimFrame=0;
+ break;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_WHITERECT:
+ case IDC_LOGO:
+ SetBkColor((HDC)wParam,RGB(255,255,255));
+ return (BOOL)GetStockObject(WHITE_BRUSH);
+
+ case IDC_UPDATING:
+ {
+ COLORREF textCol,bgCol,newCol;
+ int ratio;
+ textCol=GetSysColor(COLOR_BTNTEXT);
+ bgCol=GetSysColor(COLOR_3DFACE);
+ ratio=abs(UPDATEANIMFRAMES/2-dat->updateAnimFrame)*510/UPDATEANIMFRAMES;
+ newCol=RGB(GetRValue(bgCol)+(GetRValue(textCol)-GetRValue(bgCol))*ratio/256,
+ GetGValue(bgCol)+(GetGValue(textCol)-GetGValue(bgCol))*ratio/256,
+ GetBValue(bgCol)+(GetBValue(textCol)-GetBValue(bgCol))*ratio/256);
+ SetTextColor((HDC)wParam,newCol);
+ SetBkColor((HDC)wParam,GetSysColor(COLOR_3DFACE));
+ return (BOOL)GetSysColorBrush(COLOR_3DFACE);
+ }
+ default:
+ SetBkMode((HDC)wParam,TRANSPARENT);
+ return (BOOL)GetStockObject(NULL_BRUSH);
+ }
+ break;
+ case PSM_CHANGED:
+ dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+ case PSM_FORCECHANGED:
+ { PSHNOTIFY pshn;
+ int i;
+
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ for(i=0;i<dat->pageCount;i++) {
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(dat->opd[i].hwnd!=NULL)
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ break;
+ }
+ case M_CHECKONLINE:
+ {
+ char *szProto;
+ if (dat->hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if(szProto==NULL) {EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE); break;}
+ if(CallProtoService(szProto,PS_GETSTATUS,0,0)<ID_STATUS_ONLINE) EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ else EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),!IsWindowVisible(GetDlgItem(hwndDlg,IDC_UPDATING)));
+ }
+ break;
+ }
+ case HM_PROTOACK:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ int i;
+
+ if(ack->hContact==NULL && ack->type==ACKTYPE_STATUS) {
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ break;
+ }
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_GETINFO) break;
+ SendMessage(hwndDlg,PSM_FORCECHANGED,0,0);
+ /* if they're not gonna send any more ACK's don't let that mean we should crash */
+ if (!ack->hProcess && !ack->lParam) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ KillTimer(hwndDlg,1);
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ break;
+ } //if
+ if(dat->infosUpdated==NULL) dat->infosUpdated=(int*)mir_calloc(sizeof(int)*(int)ack->hProcess);
+ if(ack->result==ACKRESULT_SUCCESS || ack->result==ACKRESULT_FAILED) dat->infosUpdated[ack->lParam]=1;
+ for(i=0;i<(int)ack->hProcess;i++)
+ if(dat->infosUpdated[i]==0) break;
+ if(i==(int)ack->hProcess) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ KillTimer(hwndDlg,1);
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TVN_SELCHANGED:
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) {
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
+ TVITEM tvi = pnmtv->itemNew;
+ dat->currentPage=tvi.lParam;
+ }
+ if(dat->currentPage!=-1) {
+ if(dat->opd[dat->currentPage].hwnd==NULL) {
+ PSHNOTIFY pshn;
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->hContact);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd, HWND_TOP, dat->rcDisplay.left, dat->rcDisplay.top, dat->rcDisplay.right - dat->rcDisplay.left, dat->rcDisplay.bottom - dat->rcDisplay.top, 0);
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ SetFocus(GetDlgItem(hwndDlg,IDC_PAGETREE));
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDOK:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ if(dat->currentPage!=-1) {
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ TreeView_Select(GetDlgItem(hwndDlg,IDC_PAGETREE), dat->opd[i].hItem, TVGN_CARET);
+ if(dat->currentPage!=-1) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ }
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDC_UPDATE:
+ if(dat->infosUpdated!=NULL) {mir_free(dat->infosUpdated); dat->infosUpdated=NULL;}
+ if(dat->hContact != NULL) {
+ CallContactService(dat->hContact,PSS_GETINFO,0,0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_SHOW);
+ SetTimer(hwndDlg,1,100,NULL);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK));
+ break;
+ case WM_DESTROY:
+ {
+ TCHAR name[128];
+ TVITEM tvi;
+ tvi.mask = TVIF_TEXT;
+ tvi.hItem = dat->opd[dat->currentPage].hItem;
+ tvi.pszText=name;
+ tvi.cchTextMax=SIZEOF(name);
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_PAGETREE), &tvi);
+ DBWriteContactSettingTString(NULL,"UserInfo","LastTab", name);
+ }
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDC_WHITERECT,WM_GETFONT,0,0),0);
+ DeleteObject(dat->hBoldFont);
+ WindowList_Remove(hWindowList,hwndDlg);
+ UnhookEvent(dat->hProtoAckEvent);
+ { int i;
+ for(i=0;i<dat->pageCount;i++)
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ }
+ if(dat->infosUpdated!=NULL) mir_free(dat->infosUpdated);
+ mir_free(dat->opd);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+int ShutdownUserInfo(WPARAM wParam,LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0);
+ return 0;
+}
+
+int LoadUserInfoModule(void)
+{
+ CLISTMENUITEM mi;
+
+ CreateServiceFunction(MS_USERINFO_SHOWDIALOG,ShowDetailsDialogCommand);
+ hDetailsInitEvent=CreateHookableEvent(ME_USERINFO_INITIALISE);
+ HookEvent(ME_USERINFO_INITIALISE,DetailsInit);
+ HookEvent(ME_DB_CONTACT_DELETED,UserInfoContactDelete);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownUserInfo);
+ CreateServiceFunction(MS_USERINFO_ADDPAGE,AddDetailsPage);
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=1000050000;
+ mi.flags=0;
+ mi.hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_USERDETAILS));
+ mi.pszContactOwner=NULL;
+ mi.pszName=Translate("User &Details");
+ mi.pszService=MS_USERINFO_SHOWDIALOG;
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ mi.position=500050000;
+ mi.pszName=Translate("View/Change My &Details...");
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/useronline/useronline.c b/miranda-wine/src/modules/useronline/useronline.c new file mode 100644 index 0000000..08652f6 --- /dev/null +++ b/miranda-wine/src/modules/useronline/useronline.c @@ -0,0 +1,96 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static int uniqueEventId=0;
+
+static int UserOnlineSettingChanged(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam;
+ int newStatus,oldStatus;
+
+ if((HANDLE)wParam==NULL || strcmp(cws->szSetting,"Status")) return 0;
+ newStatus=cws->value.wVal;
+ oldStatus=DBGetContactSettingWord((HANDLE)wParam,"UserOnline","OldStatus",ID_STATUS_OFFLINE);
+ DBWriteContactSettingWord((HANDLE)wParam,"UserOnline","OldStatus",(WORD)newStatus);
+ if(CallService(MS_IGNORE_ISIGNORED,wParam,IGNOREEVENT_USERONLINE)) return 0;
+ if(DBGetContactSettingByte((HANDLE)wParam,"CList","Hidden",0)) return 0;
+ if((newStatus==ID_STATUS_ONLINE || newStatus==ID_STATUS_FREECHAT) &&
+ oldStatus!=ID_STATUS_ONLINE && oldStatus!=ID_STATUS_FREECHAT) {
+ {
+ DWORD ticked = db_dword_get(NULL, "UserOnline", cws->szModule, GetTickCount());
+ // only play the sound (or show event) if this event happens at least 10 secs after the proto went from offline
+ if ( GetTickCount() - ticked > (1000*10) ) {
+ CLISTEVENT cle;
+ char tooltip[256];
+
+ ZeroMemory(&cle,sizeof(cle));
+ cle.cbSize=sizeof(cle);
+ cle.flags=CLEF_ONLYAFEW;
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)(uniqueEventId++);
+ cle.hIcon=LoadSkinnedIcon(SKINICON_OTHER_USERONLINE);
+ cle.pszService="UserOnline/Description";
+ mir_snprintf(tooltip,SIZEOF(tooltip),Translate("%s is Online"),(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,wParam,0));
+ cle.pszTooltip=tooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+
+ SkinPlaySound("UserOnline");
+ }
+ }
+ }
+ return 0;
+}
+
+static int UserOnlineAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA * ack = (ACKDATA*) lParam;
+ if ( ack != 0 && ack->szModule && ack->type == ACKTYPE_STATUS && ack->result == ACKRESULT_SUCCESS && ack->hProcess == (HANDLE)ID_STATUS_OFFLINE) {
+ // if going from offline to any other mode, remember when it happened.
+ db_dword_set(NULL, "UserOnline", ack->szModule, GetTickCount());
+ }
+ return 0;
+}
+
+static int UserOnlineModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int protoCount=0, j;
+ PROTOCOLDESCRIPTOR **protos = 0;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&protoCount, (LPARAM)&protos);
+ // reset the counter
+ for (j=0 ; j < protoCount; j++)
+ if (protos[j]->type == PROTOTYPE_PROTOCOL) {
+ db_dword_set(NULL, "UserOnline", protos[j]->szName, GetTickCount());
+ }
+ return 0;
+}
+
+int LoadUserOnlineModule(void)
+{
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED,UserOnlineSettingChanged);
+ HookEvent(ME_PROTO_ACK, UserOnlineAck);
+ HookEvent(ME_SYSTEM_MODULESLOADED, UserOnlineModulesLoaded);
+ SkinAddNewSoundEx("UserOnline",Translate("Alerts"),Translate("Online"));
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/bmpfilter.c b/miranda-wine/src/modules/utils/bmpfilter.c new file mode 100644 index 0000000..eb20d33 --- /dev/null +++ b/miranda-wine/src/modules/utils/bmpfilter.c @@ -0,0 +1,180 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <ocidl.h>
+#include <olectl.h>
+
+#include "m_png.h"
+
+static int BmpFilterLoadBitmap(WPARAM wParam,LPARAM lParam)
+{
+ IPicture *pic;
+ HBITMAP hBmp,hBmpCopy;
+ HBITMAP hOldBitmap, hOldBitmap2;
+ BITMAP bmpInfo;
+ WCHAR pszwFilename[MAX_PATH];
+ HDC hdc,hdcMem1,hdcMem2;
+ short picType;
+ const char *szFile=(const char *)lParam;
+ char szFilename[MAX_PATH];
+ int filenameLen;
+
+ if (!CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)szFile, (LPARAM)szFilename))
+ mir_snprintf(szFilename, SIZEOF(szFilename), "%s", szFile);
+ filenameLen=lstrlenA(szFilename);
+ if(filenameLen>4) {
+ char* pszExt = szFilename+filenameLen-4;
+ if ( !lstrcmpiA( pszExt,".bmp" ) || !lstrcmpiA( pszExt, ".rle" )) {
+ //LoadImage can do this much faster
+ return (int)LoadImageA( GetModuleHandle(NULL), szFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+ }
+
+ if ( !lstrcmpiA( pszExt, ".png" )) {
+ HANDLE hFile, hMap = NULL;
+ BYTE* ppMap = NULL;
+ long cbFileSize = 0;
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+
+ if ( !ServiceExists( MS_PNG2DIB )) {
+ MessageBox( NULL, TranslateT( "You need the png2dib plugin v. 0.1.3.x or later to process PNG images" ), TranslateT( "Error" ), MB_OK );
+ return (int)(HBITMAP)NULL;
+ }
+
+ if (( hFile = CreateFileA( szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE )
+ if (( hMap = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL )
+ if (( ppMap = ( BYTE* )MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL )
+ cbFileSize = GetFileSize( hFile, NULL );
+
+ if ( cbFileSize != 0 ) {
+ PNG2DIB param;
+ param.pSource = ppMap;
+ param.cbSourceSize = cbFileSize;
+ param.pResult = &pDib;
+ if ( CallService( MS_PNG2DIB, 0, ( LPARAM )¶m ))
+ pDibBits = ( BYTE* )( pDib+1 );
+ else
+ cbFileSize = 0;
+ }
+
+ if ( ppMap != NULL ) UnmapViewOfFile( ppMap );
+ if ( hMap != NULL ) CloseHandle( hMap );
+ if ( hFile != NULL ) CloseHandle( hFile );
+
+ if ( cbFileSize == 0 )
+ return (int)(HBITMAP)NULL;
+
+ { HDC sDC = GetDC( NULL );
+ HBITMAP hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, ( BITMAPINFO* )pDib, DIB_PAL_COLORS );
+ SelectObject( sDC, hBitmap );
+ ReleaseDC( NULL, sDC );
+ GlobalFree( pDib );
+ return (int)hBitmap;
+ } } }
+
+ OleInitialize(NULL);
+ MultiByteToWideChar(CP_ACP,0,szFilename,-1,pszwFilename,MAX_PATH);
+ if(S_OK!=OleLoadPicturePath(pszwFilename,NULL,0,0,&IID_IPicture,(PVOID*)&pic)) {
+ OleUninitialize();
+ return (int)(HBITMAP)NULL;
+ }
+ pic->lpVtbl->get_Type(pic,&picType);
+ if(picType!=PICTYPE_BITMAP) {
+ pic->lpVtbl->Release(pic);
+ OleUninitialize();
+ return (int)(HBITMAP)NULL;
+ }
+ pic->lpVtbl->get_Handle(pic,(OLE_HANDLE*)&hBmp);
+ GetObject(hBmp,sizeof(bmpInfo),&bmpInfo);
+
+ //need to copy bitmap so we can free the IPicture
+ hdc=GetDC(NULL);
+ hdcMem1=CreateCompatibleDC(hdc);
+ hdcMem2=CreateCompatibleDC(hdc);
+ hOldBitmap=SelectObject(hdcMem1,hBmp);
+ hBmpCopy=CreateCompatibleBitmap(hdcMem1,bmpInfo.bmWidth,bmpInfo.bmHeight);
+ hOldBitmap2=SelectObject(hdcMem2,hBmpCopy);
+ BitBlt(hdcMem2,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,hdcMem1,0,0,SRCCOPY);
+ SelectObject(hdcMem1,hOldBitmap);
+ SelectObject(hdcMem2,hOldBitmap2);
+ DeleteDC(hdcMem2);
+ DeleteDC(hdcMem1);
+ ReleaseDC(NULL,hdc);
+
+ DeleteObject(hBmp);
+ pic->lpVtbl->Release(pic);
+ OleUninitialize();
+ return (int)hBmpCopy;
+}
+
+static int BmpFilterGetStrings(WPARAM wParam,LPARAM lParam)
+{
+ int bytesLeft=wParam;
+ char *filter=(char*)lParam,*pfilter;
+
+ lstrcpynA(filter,Translate("All Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(filter);
+ strncat(filter," (*.bmp;*.jpg;*.gif;*.png)",bytesLeft);
+ pfilter=filter+lstrlenA(filter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("Windows Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.bmp;*.rle)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.jpg;*.jpeg)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.JPG;*.JPEG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.gif)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.GIF",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("PNG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.png)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("All Files"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ if(bytesLeft) *pfilter='\0';
+ return 0;
+}
+
+int InitBitmapFilter(void)
+{
+ CreateServiceFunction(MS_UTILS_LOADBITMAP,BmpFilterLoadBitmap);
+ CreateServiceFunction(MS_UTILS_GETBITMAPFILTERSTRINGS,BmpFilterGetStrings);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/colourpicker.c b/miranda-wine/src/modules/utils/colourpicker.c new file mode 100644 index 0000000..4192e62 --- /dev/null +++ b/miranda-wine/src/modules/utils/colourpicker.c @@ -0,0 +1,107 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static LRESULT CALLBACK ColourPickerWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_CREATE:
+ SetWindowLong(hwnd,0,0);
+ SetWindowLong(hwnd,sizeof(COLORREF),0);
+ break;
+ case CPM_SETDEFAULTCOLOUR:
+ SetWindowLong(hwnd,sizeof(COLORREF),lParam);
+ break;
+ case CPM_GETDEFAULTCOLOUR:
+ return GetWindowLong(hwnd,sizeof(COLORREF));
+ case CPM_SETCOLOUR:
+ SetWindowLong(hwnd,0,lParam);
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case CPM_GETCOLOUR:
+ return GetWindowLong(hwnd,0);
+ case WM_LBUTTONUP:
+ {
+ CHOOSECOLOR cc={0};
+ COLORREF custColours[16]={0};
+ custColours[0]=GetWindowLong(hwnd,sizeof(COLORREF));
+ cc.lStructSize=sizeof(CHOOSECOLOR);
+ cc.hwndOwner=hwnd;
+ cc.hInstance=(HWND)GetModuleHandle(NULL);
+ cc.rgbResult=GetWindowLong(hwnd,0);
+ cc.lpCustColors=custColours;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(ChooseColor(&cc)) {
+ SetWindowLong(hwnd,0,cc.rgbResult);
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),CPN_COLOURCHANGED),(LPARAM)hwnd);
+ InvalidateRect(hwnd,NULL,FALSE);
+ }
+ break;
+ }
+ case WM_ENABLE:
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case WM_NCPAINT:
+ case WM_PAINT:
+ { PAINTSTRUCT ps;
+ HDC hdc1;
+ RECT rc;
+ HBRUSH hBrush;
+
+ hdc1=BeginPaint(hwnd,&ps);
+ GetClientRect(hwnd,&rc);
+ DrawEdge(hdc1,&rc,EDGE_ETCHED,BF_RECT);
+ InflateRect(&rc,-2,-2);
+ if(IsWindowEnabled(hwnd))
+ hBrush=CreateSolidBrush(GetWindowLong(hwnd,0));
+ else
+ hBrush=CreateHatchBrush(HS_BDIAGONAL,GetSysColor(COLOR_GRAYTEXT));
+ SetBkColor(hdc1,GetSysColor(COLOR_BTNFACE));
+ FillRect(hdc1,&rc,hBrush);
+ DeleteObject(hBrush);
+ EndPaint(hwnd,&ps);
+ break;
+ }
+ case WM_DESTROY:
+ break;
+ }
+ return DefWindowProc(hwnd,message,wParam,lParam);
+}
+
+int InitColourPicker(void)
+{
+ WNDCLASS wcl;
+
+ wcl.lpfnWndProc=ColourPickerWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(COLORREF)*2;
+ wcl.hInstance=GetModuleHandle(NULL);
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_COLOURPICKER;
+ wcl.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
+ RegisterClass(&wcl);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/hyperlink.c b/miranda-wine/src/modules/utils/hyperlink.c new file mode 100644 index 0000000..affc1ff --- /dev/null +++ b/miranda-wine/src/modules/utils/hyperlink.c @@ -0,0 +1,183 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static HCURSOR hHandCursor;
+
+struct HyperlinkWndData {
+ HFONT hFont;
+ HFONT hSetFont;
+ RECT rcText;
+ DWORD enableColor;
+ DWORD disableColor;
+};
+#define IM_MEASURETEXT (WM_USER+1)
+#define HLK_INVALIDATE (WM_USER+2)
+static LRESULT CALLBACK HyperlinkWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct HyperlinkWndData *dat;
+ dat=(struct HyperlinkWndData*)GetWindowLong(hwnd,0);
+ switch(message) {
+ case WM_CREATE:
+ dat=(struct HyperlinkWndData*)mir_alloc(sizeof(struct HyperlinkWndData));
+ SetWindowLong(hwnd,0,(LONG)dat);
+ dat->hFont=NULL;
+ dat->hSetFont=NULL;
+ dat->enableColor=GetSysColor(COLOR_HOTLIGHT);
+ if(dat->enableColor==0 && GetLastError()!=ERROR_SUCCESS) dat->enableColor=RGB(0,0,255);
+ dat->disableColor=GetSysColor(COLOR_GRAYTEXT);
+ SendMessage(hwnd,IM_MEASURETEXT,0,0);
+ break;
+ case WM_LBUTTONDOWN:
+ { POINT pt;
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ if(PtInRect(&dat->rcText,pt))
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
+ break;
+ }
+ case WM_SETFONT:
+ { LOGFONT lf;
+ dat->hSetFont=(HFONT)wParam;
+ GetObject(dat->hSetFont,sizeof(lf),&lf);
+ lf.lfUnderline=1;
+ dat->hFont=CreateFontIndirect(&lf);
+ if(LOWORD(lParam)) SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ SendMessage(hwnd,IM_MEASURETEXT,0,0);
+ break;
+ }
+ case WM_ERASEBKGND: return(1); break;
+ case HLK_INVALIDATE: // invalidate
+ {
+ RECT rcWnd;
+ POINT pt;
+ GetWindowRect(hwnd,&rcWnd);
+ pt.x = rcWnd.left;
+ pt.y = rcWnd.top;
+ ScreenToClient(GetParent(hwnd),&pt);
+ rcWnd.right = pt.x + (rcWnd.right-rcWnd.left);
+ rcWnd.bottom = pt.y + (rcWnd.bottom-rcWnd.top);
+ rcWnd.left = pt.x;
+ rcWnd.top = pt.y;
+
+ InvalidateRect(GetParent(hwnd),&rcWnd,TRUE);
+ break;
+ }
+ case WM_GETFONT:
+ return (LRESULT)dat->hSetFont;
+ case IM_MEASURETEXT:
+ { char text[256];
+ GetWindowTextA(hwnd,text,SIZEOF(text));
+ lParam=(LPARAM)text;
+ //fall thru
+ case WM_SETTEXT:
+ { HFONT hoFont;
+ SIZE textSize;
+ RECT rc;
+
+ HDC hdc1=GetDC(hwnd);
+ if(dat->hFont!=NULL) hoFont=(HFONT)SelectObject(hdc1,dat->hFont);
+ GetTextExtentPoint32(hdc1,(const TCHAR*)lParam,lstrlen((const TCHAR*)lParam),&textSize);
+ dat->rcText.top=0; dat->rcText.bottom=dat->rcText.top+textSize.cy;
+ GetClientRect(hwnd,&rc);
+ if(GetWindowLong(hwnd,GWL_STYLE)&SS_CENTER) dat->rcText.left=(rc.right-textSize.cx)/2;
+ else if(GetWindowLong(hwnd,GWL_STYLE)&SS_RIGHT) dat->rcText.left=rc.right-textSize.cx;
+ else dat->rcText.left=0;
+ dat->rcText.right=dat->rcText.left+textSize.cx;
+ if(dat->hFont!=NULL) SelectObject(hdc1,hoFont);
+ ReleaseDC(hwnd,hdc1);
+ SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ break;
+ }}
+ case WM_SETCURSOR:
+ { POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hwnd,&pt);
+ if(PtInRect(&dat->rcText,pt)) SetCursor(hHandCursor);
+ else SetCursor(LoadCursor(NULL,IDC_ARROW));
+ return TRUE;
+ }
+ case HLK_SETENABLECOLOUR:
+ if ((DWORD)wParam) dat->enableColor = (DWORD)wParam;
+ break;
+ case HLK_SETDISABLECOLOUR:
+ if ((DWORD)wParam) dat->disableColor = (DWORD)wParam;
+ break;
+ case WM_NCPAINT:
+ case WM_PAINT:
+ {
+ HFONT hoFont;
+ RECT rc;
+ TCHAR text[256];
+ int alignFlag;
+ DWORD textColour;
+
+ PAINTSTRUCT ps;
+ HDC hdc1=BeginPaint(hwnd,&ps);
+ if(IsWindowEnabled(hwnd)) {
+ hoFont=(HFONT)SelectObject(hdc1,dat->hFont);
+ textColour=dat->enableColor;
+ }
+ else {
+ hoFont=(HFONT)SelectObject(hdc1,dat->hSetFont);
+ textColour=dat->disableColor;
+ }
+ SetTextColor(hdc1,textColour);
+ SetBkMode(hdc1,TRANSPARENT);
+ if(GetWindowLong(hwnd,GWL_STYLE)&SS_CENTER) alignFlag=DT_CENTER;
+ else if(GetWindowLong(hwnd,GWL_STYLE)&SS_RIGHT) alignFlag=DT_RIGHT;
+ else alignFlag=DT_LEFT;
+ GetClientRect(hwnd,&rc);
+ GetWindowText(hwnd,text,SIZEOF(text));
+ DrawText(hdc1,text,-1,&rc,alignFlag|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ SelectObject(hdc1,hoFont);
+ EndPaint(hwnd,&ps);
+ break;
+ }
+ case WM_DESTROY:
+ if(dat->hFont!=NULL) DeleteObject(dat->hFont);
+ mir_free(dat); dat=NULL;
+ SetWindowLong(hwnd,0,(LONG)dat);
+ break;
+ }
+ return DefWindowProc(hwnd,message,wParam,lParam);
+}
+
+int InitHyperlink(void)
+{
+ WNDCLASS wcl;
+
+ if(IsWinVer2000Plus()) hHandCursor=LoadCursor(NULL,IDC_HAND);
+ else hHandCursor=LoadCursor(GetModuleHandle(NULL),MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ wcl.lpfnWndProc=HyperlinkWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(void*);
+ wcl.hInstance=GetModuleHandle(NULL);
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_HYPERLINK;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS|CS_PARENTDC;
+ RegisterClass(&wcl);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/openurl.c b/miranda-wine/src/modules/utils/openurl.c new file mode 100644 index 0000000..02c415c --- /dev/null +++ b/miranda-wine/src/modules/utils/openurl.c @@ -0,0 +1,228 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+#include <ctype.h>
+
+#define DDEMESSAGETIMEOUT 1000
+#define WNDCLASS_DDEMSGWINDOW _T("MirandaDdeMsgWindow")
+
+struct DdeMsgWindowData {
+ int fAcked,fData;
+ HWND hwndDde;
+};
+
+static LRESULT CALLBACK DdeMessageWindow(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ struct DdeMsgWindowData *dat;
+ ATOM hSzItem;
+ HGLOBAL hDdeData;
+
+ dat=(struct DdeMsgWindowData*)GetWindowLong(hwnd,0);
+ switch(msg) {
+ case WM_DDE_ACK:
+ dat->fAcked=1;
+ dat->hwndDde=(HWND)wParam;
+ return 0;
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT)&hDdeData,(PUINT)&hSzItem);
+ dat->fData=1;
+ if(hDdeData) {
+ DDEDATA *data;
+ int release;
+ data=(DDEDATA*)GlobalLock(hDdeData);
+ if(data->fAckReq) {
+ DDEACK ack={0};
+ PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,PackDDElParam(WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem));
+ }
+ else GlobalDeleteAtom(hSzItem);
+ release=data->fRelease;
+ GlobalUnlock(hDdeData);
+ if(release) GlobalFree(hDdeData);
+ }
+ else GlobalDeleteAtom(hSzItem);
+ return 0;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+static int DoDdeRequest(const char *szItemName,HWND hwndDdeMsg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLong(hwndDdeMsg,0);
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(dat->hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDdeMsg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ timeoutTick=GetTickCount()+5000;
+ dat->fData=0; dat->fAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(dat->fData || dat->fAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ } while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!dat->fData) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ return 0;
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static int DdeOpenUrl(const char *szBrowser,char *szUrl,int newWindow,HWND hwndDdeMsg)
+{
+ ATOM hSzBrowser,hSzTopic;
+ DWORD dwResult;
+ char *szItemName;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLong(hwndDdeMsg,0);
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+ hSzTopic=GlobalAddAtomA("WWW_OpenURL");
+ dat->fAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDdeMsg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !dat->fAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ szItemName=(char*)mir_alloc(lstrlenA(szUrl)+7);
+ wsprintfA(szItemName,"\"%s\",,%d",szUrl,newWindow?0:-1);
+ if(DoDdeRequest(szItemName,hwndDdeMsg)) {
+ mir_free(szItemName);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ PostMessage(dat->hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDdeMsg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(szItemName);
+ return 0;
+}
+
+typedef struct {
+ char *szUrl;
+ int newWindow;
+} TOpenUrlInfo;
+
+static void OpenURLThread(void *arg)
+{
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)arg;
+ char *szResult;
+ HWND hwndDdeMsg;
+ struct DdeMsgWindowData msgWndData={0};
+ char *pszProtocol;
+ HKEY hKey;
+ char szSubkey[80];
+ char szCommandName[MAX_PATH];
+ DWORD dataLength;
+ int success=0;
+
+ if (!hUrlInfo->szUrl) return;
+ hwndDdeMsg=CreateWindow(WNDCLASS_DDEMSGWINDOW,_T(""),0,0,0,0,0,NULL,NULL,GetModuleHandle(NULL),NULL);
+ SetWindowLong(hwndDdeMsg,0,(LONG)&msgWndData);
+
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp:",4) || !_strnicmp(hUrlInfo->szUrl,"ftp.",4)) pszProtocol="ftp";
+ if(!_strnicmp(hUrlInfo->szUrl,"mailto:",7)) pszProtocol="mailto";
+ if(!_strnicmp(hUrlInfo->szUrl,"news:",5)) pszProtocol="news";
+ else pszProtocol="http";
+ wsprintfA(szSubkey,"%s\\shell\\open\\command",pszProtocol);
+ if(RegOpenKeyExA(HKEY_CURRENT_USER,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS
+ || RegOpenKeyExA(HKEY_CLASSES_ROOT,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS) {
+ dataLength=SIZEOF(szCommandName);
+ if(RegQueryValueEx(hKey,NULL,NULL,NULL,(PBYTE)szCommandName,&dataLength)==ERROR_SUCCESS) {
+ _strlwr(szCommandName);
+ if(strstr(szCommandName,"mozilla") || strstr(szCommandName,"netscape"))
+ success=(DdeOpenUrl("mozilla",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0 || DdeOpenUrl("netscape",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0);
+ else if(strstr(szCommandName,"iexplore") || strstr(szCommandName,"msimn"))
+ success=0==DdeOpenUrl("iexplore",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ else if(strstr(szCommandName,"opera"))
+ success=0==DdeOpenUrl("opera",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ //opera's the default anyway
+ }
+ RegCloseKey(hKey);
+ }
+
+ DestroyWindow(hwndDdeMsg);
+ if(success) return;
+
+ //wack a protocol on it
+ if((isalpha(hUrlInfo->szUrl[0]) && hUrlInfo->szUrl[1]==':') || hUrlInfo->szUrl[0]=='\\') {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+9);
+ wsprintfA(szResult,"file:///%s",hUrlInfo->szUrl);
+ }
+ else {
+ int i;
+ for(i=0;isalpha(hUrlInfo->szUrl[i]);i++);
+ if(hUrlInfo->szUrl[i]==':') szResult=mir_strdup(hUrlInfo->szUrl);
+ else {
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp.",4)) {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+7);
+ wsprintfA(szResult,"ftp://%s",hUrlInfo->szUrl);
+ }
+ else {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+8);
+ wsprintfA(szResult,"http://%s",hUrlInfo->szUrl);
+ }
+ }
+ }
+ ShellExecuteA(NULL, "open", szResult, NULL, NULL, SW_SHOW);
+ mir_free(szResult);
+ mir_free(hUrlInfo->szUrl);
+ mir_free(hUrlInfo);
+ return;
+}
+
+static int OpenURL(WPARAM wParam,LPARAM lParam) {
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)mir_alloc(sizeof(TOpenUrlInfo));
+ hUrlInfo->szUrl = (char*)lParam?mir_strdup((char*)lParam):NULL;
+ hUrlInfo->newWindow = (int)wParam;
+ forkthread(OpenURLThread, 0, (void*)hUrlInfo);
+ return 0;
+}
+
+int InitOpenUrl(void)
+{
+ WNDCLASS wcl;
+ wcl.lpfnWndProc=DdeMessageWindow;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(void*);
+ wcl.hInstance=GetModuleHandle(NULL);
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_DDEMSGWINDOW;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=0;
+ RegisterClass(&wcl);
+ CreateServiceFunction(MS_UTILS_OPENURL,OpenURL);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/path.c b/miranda-wine/src/modules/utils/path.c new file mode 100644 index 0000000..ba7caee --- /dev/null +++ b/miranda-wine/src/modules/utils/path.c @@ -0,0 +1,83 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static char szMirandaPath[MAX_PATH];
+
+static int pathIsAbsolute(char *path)
+{
+ if (!path||!strlen(path)>2) return 0;
+ if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\')) return 1;
+ return 0;
+}
+
+static int pathToRelative(WPARAM wParam, LPARAM lParam)
+{
+ char *pSrc = (char*)wParam;
+ char *pOut = (char*)lParam;
+ if (!pSrc||!strlen(pSrc)||strlen(pSrc)>MAX_PATH) return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ else {
+ char szTmp[MAX_PATH];
+
+ mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc);
+ _strlwr(szTmp);
+ if (strstr(szTmp, szMirandaPath)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPath));
+ return strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ }
+}
+
+static int pathToAbsolute(WPARAM wParam, LPARAM lParam) {
+ char *pSrc = (char*)wParam;
+ char *pOut = (char*)lParam;
+ if (!pSrc||!strlen(pSrc)||strlen(pSrc)>MAX_PATH) return 0;
+ if (pathIsAbsolute(pSrc)||!isalnum(pSrc[0])) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s%s", szMirandaPath, pSrc);
+ return strlen(pOut);
+ }
+}
+
+int InitPathUtils(void)
+{
+ char *p = 0;
+ GetModuleFileNameA(GetModuleHandle(NULL), szMirandaPath, SIZEOF(szMirandaPath));
+ p=strrchr(szMirandaPath,'\\');
+ if (p&&p+1) *(p+1)=0;
+ _strlwr(szMirandaPath);
+ CreateServiceFunction(MS_UTILS_PATHTORELATIVE, pathToRelative);
+ CreateServiceFunction(MS_UTILS_PATHTOABSOLUTE, pathToAbsolute);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/resizer.c b/miranda-wine/src/modules/utils/resizer.c new file mode 100644 index 0000000..06e79d3 --- /dev/null +++ b/miranda-wine/src/modules/utils/resizer.c @@ -0,0 +1,152 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+typedef struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ WORD id;
+} START_OF_DLGITEMTEMPLATEEX;
+
+typedef struct {
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+} START_OF_DLGTEMPLATEEX;
+
+int ResizeDialog(WPARAM wParam,LPARAM lParam)
+{
+ UTILRESIZEDIALOG *urd=(UTILRESIZEDIALOG*)lParam;
+ HDWP hDwp;
+ int i;
+ DLGITEMTEMPLATE *pItem;
+ START_OF_DLGITEMTEMPLATEEX *pItemEx;
+ RECT rc;
+ PWORD pWord;
+ DLGTEMPLATE *pTemplate;
+ START_OF_DLGTEMPLATEEX *pTemplateEx;
+ UTILRESIZECONTROL urc;
+ int procResult;
+ int extendedDlg,itemCount;
+
+ if(urd==NULL||urd->cbSize!=sizeof(UTILRESIZEDIALOG)) return 1;
+ pTemplate=(DLGTEMPLATE*)LockResource(LoadResource(urd->hInstance,FindResourceA(urd->hInstance,urd->lpTemplate,MAKEINTRESOURCEA(5))));
+ pTemplateEx=(START_OF_DLGTEMPLATEEX*)pTemplate;
+ extendedDlg=pTemplateEx->signature==0xFFFF;
+ if(extendedDlg && pTemplateEx->dlgVer!=1)
+ return 1;
+
+ if(extendedDlg) pWord=(PWORD)(pTemplateEx+1);
+ else pWord=(PWORD)(pTemplate+1);
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ while(*pWord++); //title
+ if(extendedDlg) {
+ if(pTemplateEx->style&DS_SETFONT) {
+ pWord+=3; //font size,weight,italic
+ while(*pWord++); //font name
+ }
+ }
+ else {
+ if(pTemplate->style&DS_SETFONT) {
+ pWord++; //font size
+ while(*pWord++); //font name
+ }
+ }
+
+ urc.cbSize=sizeof(UTILRESIZECONTROL);
+ rc.left=0; rc.top=0;
+ if(extendedDlg) {rc.right=pTemplateEx->cx; rc.bottom=pTemplateEx->cy;}
+ else {rc.right=pTemplate->cx; rc.bottom=pTemplate->cy;}
+ MapDialogRect(urd->hwndDlg,&rc);
+ urc.dlgOriginalSize.cx=rc.right; urc.dlgOriginalSize.cy=rc.bottom;
+ GetClientRect(urd->hwndDlg,&rc);
+ urc.dlgNewSize.cx=rc.right; urc.dlgNewSize.cy=rc.bottom;
+
+ if(extendedDlg) itemCount=pTemplateEx->cDlgItems;
+ else itemCount=pTemplate->cdit;
+ hDwp=BeginDeferWindowPos(itemCount);
+ for(i=0;i<itemCount;i++) {
+ if((unsigned)pWord&2) pWord++; //dword align
+
+ if(extendedDlg) {
+ pItemEx=(START_OF_DLGITEMTEMPLATEEX*)pWord;
+ pWord=(PWORD)(pItemEx+1);
+
+ urc.wId=pItemEx->id;
+ urc.rcItem.left=pItemEx->x; urc.rcItem.top=pItemEx->y;
+ urc.rcItem.right=urc.rcItem.left+pItemEx->cx; urc.rcItem.bottom=urc.rcItem.top+pItemEx->cy;
+ }
+ else {
+ pItem=(DLGITEMTEMPLATE*)pWord;
+ pWord=(PWORD)(pItem+1);
+
+ urc.wId=pItem->id;
+ urc.rcItem.left=pItem->x; urc.rcItem.top=pItem->y;
+ urc.rcItem.right=urc.rcItem.left+pItem->cx; urc.rcItem.bottom=urc.rcItem.top+pItem->cy;
+ }
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ pWord+=1+(1+*pWord)/2; //creation data
+
+ if(urc.wId==65535) continue; //using this breaks the dwp, so just ignore it
+
+ MapDialogRect(urd->hwndDlg,&urc.rcItem);
+ procResult=(urd->pfnResizer)(urd->hwndDlg,urd->lParam,&urc);
+ if(procResult&RD_ANCHORX_RIGHT) {
+ urc.rcItem.left+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ }
+ else if(procResult&RD_ANCHORX_WIDTH)
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ else if(procResult&RD_ANCHORX_CENTRE) {
+ urc.rcItem.left+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ urc.rcItem.right+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ }
+ if(procResult&RD_ANCHORY_BOTTOM) {
+ urc.rcItem.top+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ }
+ else if(procResult&RD_ANCHORY_HEIGHT)
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ else if(procResult&RD_ANCHORY_CENTRE) {
+ urc.rcItem.top+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ urc.rcItem.bottom+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ }
+ hDwp=DeferWindowPos(hDwp,GetDlgItem(urd->hwndDlg,extendedDlg?pItemEx->id:pItem->id),0,urc.rcItem.left,urc.rcItem.top,urc.rcItem.right-urc.rcItem.left,urc.rcItem.bottom-urc.rcItem.top,SWP_NOZORDER);
+ }
+ EndDeferWindowPos(hDwp);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/utf.c b/miranda-wine/src/modules/utils/utf.c new file mode 100644 index 0000000..57f72c8 --- /dev/null +++ b/miranda-wine/src/modules/utils/utf.c @@ -0,0 +1,165 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+void Utf8Decode( char* str, wchar_t** ucs2 )
+{
+ int len;
+ wchar_t* tempBuf;
+
+ if ( str == NULL )
+ return;
+
+ len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )mir_alloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return;
+ }
+
+ tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ {
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+ }
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )mir_alloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, len, NULL, NULL );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+char* Utf8Encode( const char* src )
+{
+ int len;
+ char* result;
+ wchar_t* tempBuf;
+
+ if ( src == NULL )
+ return NULL;
+
+ len = strlen( src );
+ result = ( char* )mir_alloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, src, -1, tempBuf, len );
+ tempBuf[ len ] = 0;
+ {
+ wchar_t* s = tempBuf;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+char* Utf8EncodeUcs2( const wchar_t* src )
+{
+ int len = wcslen( src );
+ char* result = ( char* )mir_alloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ { const wchar_t* s = src;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
diff --git a/miranda-wine/src/modules/utils/utils.c b/miranda-wine/src/modules/utils/utils.c new file mode 100644 index 0000000..5f72a56 --- /dev/null +++ b/miranda-wine/src/modules/utils/utils.c @@ -0,0 +1,364 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+int ResizeDialog(WPARAM wParam,LPARAM lParam);
+int InitOpenUrl(void);
+int InitWindowList(void);
+int InitHyperlink(void);
+int InitColourPicker(void);
+int InitBitmapFilter(void);
+int InitPathUtils(void);
+
+static struct CountryListEntry countries[]={
+ {0 ,"Unspecified"},
+ {9999,"Other"},
+ {0xFFFF,"Unknown"},
+ {93 ,"Afghanistan"},
+ {355 ,"Albania"},
+ {213 ,"Algeria"},
+ {684 ,"American Samoa"},
+ {376 ,"Andorra"},
+ {244 ,"Angola"},
+ {101 ,"Anguilla"},
+ {102 ,"Antigua and Barbuda"},
+ {5902,"Antilles"},
+ {54 ,"Argentina"},
+ {374 ,"Armenia"},
+ {297 ,"Aruba"},
+ {247 ,"Ascension Island"},
+ {61 ,"Australia"},
+ {43 ,"Austria"},
+ {994 ,"Azerbaijan"},
+ {103 ,"Bahamas"},
+ {973 ,"Bahrain"},
+ {880 ,"Bangladesh"},
+ {104 ,"Barbados"},
+ {120 ,"Barbuda"},
+ {375 ,"Belarus"},
+ {32 ,"Belgium"},
+ {501 ,"Belize"},
+ {229 ,"Benin"},
+ {105 ,"Bermuda"},
+ {975 ,"Bhutan"},
+ {591 ,"Bolivia"},
+ {387 ,"Bosnia and Herzegovina"},
+ {267 ,"Botswana"},
+ {55 ,"Brazil"},
+ {106 ,"British Virgin Islands"},
+ {673 ,"Brunei"},
+ {359 ,"Bulgaria"},
+ {226 ,"Burkina Faso"},
+ {257 ,"Burundi"},
+ {855 ,"Cambodia"},
+ {237 ,"Cameroon"},
+ {107 ,"Canada"},
+ {178 ,"Canary Islands"},
+ {238 ,"Cape Verde Islands"},
+ {108 ,"Cayman Islands"},
+ {236 ,"Central African Republic"},
+ {235 ,"Chad"},
+ {56 ,"Chile, Republic of"},
+ {86 ,"China"},
+ {672 ,"Christmas Island"},
+ {6101,"Cocos-Keeling Islands"},
+ {6102,"Cocos (Keeling) Islands"},
+ {57 ,"Colombia"},
+ {2691,"Comoros"},
+ {243 ,"Congo, Democratic Republic of (Zaire)"},
+ {242 ,"Congo, Republic of the"},
+ {682 ,"Cook Islands"},
+ {506 ,"Costa Rica"},
+ {225 ,"Cote d'Ivoire (Ivory Coast)"},
+ {385 ,"Croatia"},
+ {53 ,"Cuba"},
+ {357 ,"Cyprus"},
+ {420 ,"Czech Republic"},
+ {45 ,"Denmark"},
+ {246 ,"Diego Garcia"},
+ {253 ,"Djibouti"},
+ {109 ,"Dominica"},
+ {110 ,"Dominican Republic"},
+ {593 ,"Ecuador"},
+ {20 ,"Egypt"},
+ {503 ,"El Salvador"},
+ {240 ,"Equatorial Guinea"},
+ {291 ,"Eritrea"},
+ {372 ,"Estonia"},
+ {251 ,"Ethiopia"},
+ {298 ,"Faeroe Islands"},
+ {500 ,"Falkland Islands"},
+ {679 ,"Fiji"},
+ {358 ,"Finland"},
+ {33 ,"France"},
+ {5901,"French Antilles"},
+ {594 ,"French Guiana"},
+ {689 ,"French Polynesia"},
+ {241 ,"Gabon"},
+ {220 ,"Gambia"},
+ {995 ,"Georgia"},
+ {49 ,"Germany"},
+ {233 ,"Ghana"},
+ {350 ,"Gibraltar"},
+ {30 ,"Greece"},
+ {299 ,"Greenland"},
+ {111 ,"Grenada"},
+ {590 ,"Guadeloupe"},
+ {671 ,"Guam, US Territory of"},
+ {502 ,"Guatemala"},
+ {224 ,"Guinea"},
+ {245 ,"Guinea-Bissau"},
+ {592 ,"Guyana"},
+ {509 ,"Haiti"},
+ {504 ,"Honduras"},
+ {852 ,"Hong Kong"},
+ {36 ,"Hungary"},
+ {354 ,"Iceland"},
+ {91 ,"India"},
+ {62 ,"Indonesia"},
+ {98 ,"Iran (Islamic Republic of)"},
+ {964 ,"Iraq"},
+ {353 ,"Ireland"},
+ {972 ,"Israel"},
+ {39 ,"Italy"},
+ {112 ,"Jamaica"},
+ {81 ,"Japan"},
+ {962 ,"Jordan"},
+ {705 ,"Kazakhstan"},
+ {254 ,"Kenya"},
+ {686 ,"Kiribati"},
+ {850 ,"Korea, North"},
+ {82 ,"Korea, South"},
+ {965 ,"Kuwait"},
+ {706 ,"Kyrgyzstan"},
+ {856 ,"Laos"},
+ {371 ,"Latvia"},
+ {961 ,"Lebanon"},
+ {266 ,"Lesotho"},
+ {231 ,"Liberia"},
+ {218 ,"Libyan Arab Jamahiriya"},
+ {4101,"Liechtenstein"},
+ {370 ,"Lithuania"},
+ {352 ,"Luxembourg"},
+ {853 ,"Macau"},
+ {389 ,"Macedonia (F.Y.R.O.M.)"},
+ {261 ,"Madagascar"},
+ {265 ,"Malawi"},
+ {60 ,"Malaysia"},
+ {960 ,"Maldives"},
+ {223 ,"Mali"},
+ {356 ,"Malta"},
+ {692 ,"Marshall Islands"},
+ {596 ,"Martinique"},
+ {222 ,"Mauritania"},
+ {230 ,"Mauritius"},
+ {269 ,"Mayotte Island"},
+ {52 ,"Mexico"},
+ {691 ,"Micronesia, Federated States of"},
+ {373 ,"Moldova, Republic of"},
+ {377 ,"Monaco"},
+ {976 ,"Mongolia"},
+ {113 ,"Montserrat"},
+ {212 ,"Morocco"},
+ {258 ,"Mozambique"},
+ {95 ,"Myanmar"},
+ {264 ,"Namibia"},
+ {674 ,"Nauru"},
+ {977 ,"Nepal"},
+ {31 ,"Netherlands"},
+ {599 ,"Netherlands Antilles"},
+ {114 ,"Nevis"},
+ {687 ,"New Caledonia"},
+ {64 ,"New Zealand"},
+ {505 ,"Nicaragua"},
+ {227 ,"Niger"},
+ {234 ,"Nigeria"},
+ {683 ,"Niue"},
+ {6722,"Norfolk Island"},
+ {47 ,"Norway"},
+ {968 ,"Oman"},
+ {92 ,"Pakistan"},
+ {680 ,"Palau"},
+ {507 ,"Panama"},
+ {675 ,"Papua New Guinea"},
+ {595 ,"Paraguay"},
+ {51 ,"Peru"},
+ {63 ,"Philippines"},
+ {48 ,"Poland"},
+ {351 ,"Portugal"},
+ {121 ,"Puerto Rico"},
+ {974 ,"Qatar"},
+ {262 ,"Reunion Island"},
+ {40 ,"Romania"},
+ {6701,"Rota Island"},
+ {7 ,"Russia"},
+ {250 ,"Rwanda"},
+ {290 ,"Saint Helena"},
+ {115 ,"Saint Kitts"},
+ {1141,"Saint Kitts and Nevis"},
+ {122 ,"Saint Lucia"},
+ {508 ,"Saint Pierre and Miquelon"},
+ {116 ,"Saint Vincent and the Grenadines"},
+ {670 ,"Saipan Island"},
+ {378 ,"San Marino"},
+ {239 ,"Sao Tome and Principe"},
+ {966 ,"Saudi Arabia"},
+ {442 ,"Scotland"},
+ {221 ,"Senegal"},
+ {248 ,"Seychelles"},
+ {232 ,"Sierra Leone"},
+ {65 ,"Singapore"},
+ {421 ,"Slovakia"},
+ {386 ,"Slovenia"},
+ {677 ,"Solomon Islands"},
+ {252 ,"Somalia"},
+ {27 ,"South Africa"},
+ {34 ,"Spain"},
+ {94 ,"Sri Lanka"},
+ {249 ,"Sudan"},
+ {597 ,"Suriname"},
+ {268 ,"Swaziland"},
+ {46 ,"Sweden"},
+ {41 ,"Switzerland"},
+ {963 ,"Syrian Arab Republic"},
+ {886 ,"Taiwan"},
+ {708 ,"Tajikistan"},
+ {255 ,"Tanzania"},
+ {66 ,"Thailand"},
+ {6702,"Tinian Island"},
+ {228 ,"Togo"},
+ {690 ,"Tokelau"},
+ {676 ,"Tonga"},
+ {117 ,"Trinidad and Tobago"},
+ {216 ,"Tunisia"},
+ {90 ,"Turkey"},
+ {709 ,"Turkmenistan"},
+ {118 ,"Turks and Caicos Islands"},
+ {688 ,"Tuvalu"},
+ {256 ,"Uganda"},
+ {380 ,"Ukraine"},
+ {971 ,"United Arab Emirates"},
+ {44 ,"United Kingdom"},
+ {598 ,"Uruguay"},
+ {1 ,"USA"},
+ {711 ,"Uzbekistan"},
+ {678 ,"Vanuatu"},
+ {379 ,"Vatican City"},
+ {58 ,"Venezuela"},
+ {84 ,"Vietnam"},
+ {123 ,"Virgin Islands (USA)"},
+ {441 ,"Wales"},
+ {681 ,"Wallis and Futuna Islands"},
+ {685 ,"Western Samoa"},
+ {967 ,"Yemen"},
+ {381 ,"Yugoslavia"},
+ {3811,"Yugoslavia - Serbia"},
+ {382 ,"Yugoslavia - Montenegro"},
+ {260 ,"Zambia"},
+ {263 ,"Zimbabwe"},
+};
+
+
+static int SaveWindowPosition(WPARAM wParam,LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ wsprintfA(szSettingName,"%sx",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.left);
+ wsprintfA(szSettingName,"%sy",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.top);
+ wsprintfA(szSettingName,"%swidth",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.right-wp.rcNormalPosition.left);
+ wsprintfA(szSettingName,"%sheight",swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.bottom-wp.rcNormalPosition.top);
+ return 0;
+}
+
+static int RestoreWindowPosition(WPARAM wParam,LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+ int x,y;
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ wsprintfA(szSettingName,"%sx",swp->szNamePrefix);
+ x=DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ wsprintfA(szSettingName,"%sy",swp->szNamePrefix);
+ y=(int)DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ if(x==-1) return 1;
+ if(wParam&RWPF_NOSIZE) {
+ OffsetRect(&wp.rcNormalPosition,x-wp.rcNormalPosition.left,y-wp.rcNormalPosition.top);
+ }
+ else {
+ wp.rcNormalPosition.left=x;
+ wp.rcNormalPosition.top=y;
+ wsprintfA(szSettingName,"%swidth",swp->szNamePrefix);
+ wp.rcNormalPosition.right=wp.rcNormalPosition.left+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ wsprintfA(szSettingName,"%sheight",swp->szNamePrefix);
+ wp.rcNormalPosition.bottom=wp.rcNormalPosition.top+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ }
+ wp.flags=0;
+ if(wParam&RWPF_NOACTIVATE)
+ wp.showCmd = SW_SHOWNOACTIVATE;
+
+ SetWindowPlacement(swp->hwnd,&wp);
+ return 0;
+}
+
+static int GetCountryByNumber(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ for(i=0; i < SIZEOF(countries); i++ )
+ if((int)wParam==countries[i].id) return (int)countries[i].szName;
+ return (int)(char*)NULL;
+}
+
+static int GetCountryList(WPARAM wParam,LPARAM lParam)
+{
+ *(int*)wParam = SIZEOF(countries);
+ *(struct CountryListEntry**)lParam=countries;
+ return 0;
+}
+
+int LoadUtilsModule(void)
+{
+ CreateServiceFunction(MS_UTILS_RESIZEDIALOG,ResizeDialog);
+ CreateServiceFunction(MS_UTILS_SAVEWINDOWPOSITION,SaveWindowPosition);
+ CreateServiceFunction(MS_UTILS_RESTOREWINDOWPOSITION,RestoreWindowPosition);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYBYNUMBER,GetCountryByNumber);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYLIST,GetCountryList);
+ InitOpenUrl();
+ InitWindowList();
+ InitHyperlink();
+ InitColourPicker();
+ InitBitmapFilter();
+ InitPathUtils();
+ return 0;
+}
diff --git a/miranda-wine/src/modules/utils/windowlist.c b/miranda-wine/src/modules/utils/windowlist.c new file mode 100644 index 0000000..d8f53b4 --- /dev/null +++ b/miranda-wine/src/modules/utils/windowlist.c @@ -0,0 +1,107 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static WINDOWLISTENTRY *windowList=NULL;
+static int windowListCount=0;
+static int nextWindowListId=1;
+
+static int AllocWindowList(WPARAM wParam,LPARAM lParam)
+{
+ return nextWindowListId++;
+}
+
+static int AddToWindowList(WPARAM wParam,LPARAM lParam)
+{
+ windowList=(WINDOWLISTENTRY*)mir_realloc(windowList,sizeof(WINDOWLISTENTRY)*(windowListCount+1));
+ windowList[windowListCount++]=*(WINDOWLISTENTRY*)lParam;
+ return 0;
+}
+
+static int RemoveFromWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hwnd==(HWND)lParam && windowList[i].hList==(HANDLE)wParam) {
+ MoveMemory(&windowList[i],&windowList[i+1],sizeof(WINDOWLISTENTRY)*(windowListCount-i-1));
+ windowListCount--;
+ return 0;
+ }
+ return 1;
+}
+
+static int FindInWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hContact==(HANDLE)lParam && windowList[i].hList==(HANDLE)wParam)
+ return (int)windowList[i].hwnd;
+ return (int)(HWND)NULL;
+}
+
+static int BroadcastToWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ SendMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+static int BroadcastToWindowListAsync(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ PostMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+static int FreeWindowList(WPARAM wParam,LPARAM lParam)
+{
+ if (windowList) mir_free(windowList);
+ windowList=NULL;
+ windowListCount=0;
+ nextWindowListId=1;
+ return 0;
+}
+
+static int HookShutdown(WPARAM wParam, LPARAM lParam)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN,FreeWindowList);
+ return 0;
+}
+
+int InitWindowList(void)
+{
+ CreateServiceFunction(MS_UTILS_ALLOCWINDOWLIST,AllocWindowList);
+ CreateServiceFunction(MS_UTILS_ADDTOWINDOWLIST,AddToWindowList);
+ CreateServiceFunction(MS_UTILS_REMOVEFROMWINDOWLIST,RemoveFromWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST,BroadcastToWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST_ASYNC,BroadcastToWindowListAsync);
+ CreateServiceFunction(MS_UTILS_FINDWINDOWINLIST,FindInWindowList);
+ HookEvent(ME_SYSTEM_MODULESLOADED,HookShutdown);
+ return 0;
+}
diff --git a/miranda-wine/src/modules/visibility/visibility.c b/miranda-wine/src/modules/visibility/visibility.c new file mode 100644 index 0000000..2b8c870 --- /dev/null +++ b/miranda-wine/src/modules/visibility/visibility.c @@ -0,0 +1,297 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2006 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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 "commonheaders.h"
+
+static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
+{
+ int typeOfFirst;
+ int iconOn[2]={1,1};
+ int childCount[2]={0,0},i;
+ int iImage;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
+ for( i=0; i < SIZEOF(iconOn); i++)
+ if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ for ( i=0; i < SIZEOF(iconOn); i++) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
+ if(iconOn[i] && iImage==0) iconOn[i]=0;
+ if(iImage!=0xFF) childCount[i]++;
+ }
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+ //set icons
+ for( i=0; i < SIZEOF(iconOn); i++) {
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+1:0):0xFF));
+ if(groupChildCount) groupChildCount[i]+=childCount[i];
+ }
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+static void ResetListOptions(HWND hwndList)
+{
+ int i;
+
+ SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL);
+ SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0);
+ SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
+ SendMessage(hwndList,CLM_SETLEFTMARGIN,2,0);
+ SendMessage(hwndList,CLM_SETINDENT,10,0);
+ for(i=0;i<=FONTID_MAX;i++)
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+ SetWindowLong(hwndList,GWL_STYLE,GetWindowLong(hwndList,GWL_STYLE)|CLS_SHOWHIDDEN);
+}
+
+static void SetAllContactIcons(HWND hwndList)
+{
+ HANDLE hContact,hItem;
+ char *szProto;
+ DWORD flags;
+ WORD status;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if(szProto==NULL) {flags=0; status=0;}
+ else {
+ flags=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ status=DBGetContactSettingWord(hContact,szProto,"ApparentMode",0);
+ }
+ if(flags&PF1_INVISLIST) {
+ if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,0))==0xFF)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,status==ID_STATUS_ONLINE?1:0));
+ }
+ if(flags&PF1_VISLIST) {
+ if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,0))==0xFF)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,status==ID_STATUS_OFFLINE?2:0));
+ }
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+}
+
+static BOOL CALLBACK DlgProcVisibilityOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HICON hVisibleIcon,hInvisibleIcon;
+ static HANDLE hItemAll;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { HIMAGELIST hIml;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3,3);
+ ImageList_AddIcon(hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_SMALLDOT)));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_STATUS_INVISIBLE));
+ ImageList_AddIcon(hIml,LoadSkinnedIcon(SKINICON_STATUS_OFFLINE));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hIml);
+ hVisibleIcon=ImageList_GetIcon(hIml,1,ILD_NORMAL);
+ SendDlgItemMessage(hwndDlg,IDC_VISIBLEICON,STM_SETICON,(WPARAM)hVisibleIcon,0);
+ hInvisibleIcon=ImageList_GetIcon(hIml,2,ILD_NORMAL);
+ SendDlgItemMessage(hwndDlg,IDC_INVISIBLEICON,STM_SETICON,(WPARAM)hInvisibleIcon,0);
+ }
+
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,2,0);
+
+ { CLCINFOITEM cii={0};
+ cii.cbSize=sizeof(cii);
+ cii.flags=CLCIIF_GROUPFONT;
+ cii.pszText=TranslateT("** All contacts **");
+ hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+ }
+
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ return TRUE;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case NM_CLICK:
+ { HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+ int itemType;
+
+ // Make sure we have an extra column
+ if (nm->iColumn == -1)
+ break;
+
+ // Find clicked item
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x,nm->pt.y));
+ // Nothing was clicked
+ if (hItem == NULL) break;
+ // It was not a visbility icon
+ if (!(hitFlags & CLCHT_ONITEMEXTRA)) break;
+
+ // Get image in clicked column (0=none, 1=visible, 2=invisible)
+ iImage = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0));
+ if (iImage == 0)
+ iImage=nm->iColumn + 1;
+ else
+ if (iImage == 1 || iImage == 2)
+ iImage = 0;
+
+ // Get item type (contact, group, etc...)
+ itemType = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+
+ // Update list, making sure that the options are mutually exclusive
+ if (itemType == CLCIT_CONTACT) { // A contact
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, iImage));
+ if (iImage && SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn?0:1,0))!=0xFF)
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn?0:1, 0));
+ }
+ else if (itemType == CLCIT_INFO) { // All Contacts
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn, iImage);
+ if (iImage)
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn?0:1, 0);
+ }
+ else if (itemType == CLCIT_GROUP) { // A group
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hItem) {
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn, iImage);
+ if (iImage)
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn?0:1, 0);
+ }
+ }
+ // Update the all/none icons
+ SetListGroupIcons(GetDlgItem(hwndDlg, IDC_LIST), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL);
+
+ // Activate Apply button
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { HANDLE hContact,hItem;
+ int set,i,iImage;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) {
+ set=0;
+ for(i=0;i<2;i++) {
+ iImage=SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,0));
+ if(iImage==i+1) {
+ CallContactService(hContact,PSS_SETAPPARENTMODE,iImage==1?ID_STATUS_ONLINE:ID_STATUS_OFFLINE,0);
+ set=1;
+ break;
+ }
+ }
+ if(!set) CallContactService(hContact,PSS_SETAPPARENTMODE,0,0);
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ DestroyIcon(hVisibleIcon);
+ DestroyIcon(hInvisibleIcon);
+ { HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int VisibilityOptInitialise(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 850000000;
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_VISIBILITY);
+ odp.pszTitle = "Visibility";
+ odp.pszGroup = "Status";
+ odp.pfnDlgProc = DlgProcVisibilityOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+int LoadVisibilityModule(void)
+{
+ HookEvent(ME_OPT_INITIALISE,VisibilityOptInitialise);
+ return 0;
+}
diff --git a/miranda-wine/src/res/addcontact.ico b/miranda-wine/src/res/addcontact.ico Binary files differnew file mode 100644 index 0000000..2efc4dc --- /dev/null +++ b/miranda-wine/src/res/addcontact.ico diff --git a/miranda-wine/src/res/away.ico b/miranda-wine/src/res/away.ico Binary files differnew file mode 100644 index 0000000..1e22d9b --- /dev/null +++ b/miranda-wine/src/res/away.ico diff --git a/miranda-wine/src/res/blank.ico b/miranda-wine/src/res/blank.ico Binary files differnew file mode 100644 index 0000000..7845f62 --- /dev/null +++ b/miranda-wine/src/res/blank.ico diff --git a/miranda-wine/src/res/changefont.ico b/miranda-wine/src/res/changefont.ico Binary files differnew file mode 100644 index 0000000..2c152dc --- /dev/null +++ b/miranda-wine/src/res/changefont.ico diff --git a/miranda-wine/src/res/delete.ico b/miranda-wine/src/res/delete.ico Binary files differnew file mode 100644 index 0000000..c541793 --- /dev/null +++ b/miranda-wine/src/res/delete.ico diff --git a/miranda-wine/src/res/detailsl.ico b/miranda-wine/src/res/detailsl.ico Binary files differnew file mode 100644 index 0000000..a37e05d --- /dev/null +++ b/miranda-wine/src/res/detailsl.ico diff --git a/miranda-wine/src/res/dnd.ico b/miranda-wine/src/res/dnd.ico Binary files differnew file mode 100644 index 0000000..6ccd9d2 --- /dev/null +++ b/miranda-wine/src/res/dnd.ico diff --git a/miranda-wine/src/res/downarrow.ico b/miranda-wine/src/res/downarrow.ico Binary files differnew file mode 100644 index 0000000..76a473c --- /dev/null +++ b/miranda-wine/src/res/downarrow.ico diff --git a/miranda-wine/src/res/dragcopy.cur b/miranda-wine/src/res/dragcopy.cur Binary files differnew file mode 100644 index 0000000..89c7c96 --- /dev/null +++ b/miranda-wine/src/res/dragcopy.cur diff --git a/miranda-wine/src/res/dropuser.cur b/miranda-wine/src/res/dropuser.cur Binary files differnew file mode 100644 index 0000000..a84b19e --- /dev/null +++ b/miranda-wine/src/res/dropuser.cur diff --git a/miranda-wine/src/res/emptyblo.ico b/miranda-wine/src/res/emptyblo.ico Binary files differnew file mode 100644 index 0000000..05469b9 --- /dev/null +++ b/miranda-wine/src/res/emptyblo.ico diff --git a/miranda-wine/src/res/file.ico b/miranda-wine/src/res/file.ico Binary files differnew file mode 100644 index 0000000..7d24e6d --- /dev/null +++ b/miranda-wine/src/res/file.ico diff --git a/miranda-wine/src/res/filledbl.ico b/miranda-wine/src/res/filledbl.ico Binary files differnew file mode 100644 index 0000000..35752d2 --- /dev/null +++ b/miranda-wine/src/res/filledbl.ico diff --git a/miranda-wine/src/res/finduser.ico b/miranda-wine/src/res/finduser.ico Binary files differnew file mode 100644 index 0000000..a105678 --- /dev/null +++ b/miranda-wine/src/res/finduser.ico diff --git a/miranda-wine/src/res/freechat.ico b/miranda-wine/src/res/freechat.ico Binary files differnew file mode 100644 index 0000000..56d6661 --- /dev/null +++ b/miranda-wine/src/res/freechat.ico diff --git a/miranda-wine/src/res/groupope.ico b/miranda-wine/src/res/groupope.ico Binary files differnew file mode 100644 index 0000000..64b8dc2 --- /dev/null +++ b/miranda-wine/src/res/groupope.ico diff --git a/miranda-wine/src/res/groupshu.ico b/miranda-wine/src/res/groupshu.ico Binary files differnew file mode 100644 index 0000000..8b6f797 --- /dev/null +++ b/miranda-wine/src/res/groupshu.ico diff --git a/miranda-wine/src/res/help.ico b/miranda-wine/src/res/help.ico Binary files differnew file mode 100644 index 0000000..7fd7196 --- /dev/null +++ b/miranda-wine/src/res/help.ico diff --git a/miranda-wine/src/res/history.ico b/miranda-wine/src/res/history.ico Binary files differnew file mode 100644 index 0000000..2749b50 --- /dev/null +++ b/miranda-wine/src/res/history.ico diff --git a/miranda-wine/src/res/hyperlin.cur b/miranda-wine/src/res/hyperlin.cur Binary files differnew file mode 100644 index 0000000..f0f548c --- /dev/null +++ b/miranda-wine/src/res/hyperlin.cur diff --git a/miranda-wine/src/res/invisible.ico b/miranda-wine/src/res/invisible.ico Binary files differnew file mode 100644 index 0000000..a2cd800 --- /dev/null +++ b/miranda-wine/src/res/invisible.ico diff --git a/miranda-wine/src/res/message.ico b/miranda-wine/src/res/message.ico Binary files differnew file mode 100644 index 0000000..34bc390 --- /dev/null +++ b/miranda-wine/src/res/message.ico diff --git a/miranda-wine/src/res/miranda.ico b/miranda-wine/src/res/miranda.ico Binary files differnew file mode 100644 index 0000000..f7791c3 --- /dev/null +++ b/miranda-wine/src/res/miranda.ico diff --git a/miranda-wine/src/res/mirandaw.ico b/miranda-wine/src/res/mirandaw.ico Binary files differnew file mode 100644 index 0000000..bc62b68 --- /dev/null +++ b/miranda-wine/src/res/mirandaw.ico diff --git a/miranda-wine/src/res/multisend.ico b/miranda-wine/src/res/multisend.ico Binary files differnew file mode 100644 index 0000000..3303179 --- /dev/null +++ b/miranda-wine/src/res/multisend.ico diff --git a/miranda-wine/src/res/na2.ico b/miranda-wine/src/res/na2.ico Binary files differnew file mode 100644 index 0000000..cab81c4 --- /dev/null +++ b/miranda-wine/src/res/na2.ico diff --git a/miranda-wine/src/res/notick.ico b/miranda-wine/src/res/notick.ico Binary files differnew file mode 100644 index 0000000..b96b9ec --- /dev/null +++ b/miranda-wine/src/res/notick.ico diff --git a/miranda-wine/src/res/notick1.ico b/miranda-wine/src/res/notick1.ico Binary files differnew file mode 100644 index 0000000..9fe70c4 --- /dev/null +++ b/miranda-wine/src/res/notick1.ico diff --git a/miranda-wine/src/res/occupied.ico b/miranda-wine/src/res/occupied.ico Binary files differnew file mode 100644 index 0000000..d60bcd7 --- /dev/null +++ b/miranda-wine/src/res/occupied.ico diff --git a/miranda-wine/src/res/offline2.ico b/miranda-wine/src/res/offline2.ico Binary files differnew file mode 100644 index 0000000..7058c74 --- /dev/null +++ b/miranda-wine/src/res/offline2.ico diff --git a/miranda-wine/src/res/online2.ico b/miranda-wine/src/res/online2.ico Binary files differnew file mode 100644 index 0000000..d559fb9 --- /dev/null +++ b/miranda-wine/src/res/online2.ico diff --git a/miranda-wine/src/res/onthepho.ico b/miranda-wine/src/res/onthepho.ico Binary files differnew file mode 100644 index 0000000..09d6dfa --- /dev/null +++ b/miranda-wine/src/res/onthepho.ico diff --git a/miranda-wine/src/res/options.ico b/miranda-wine/src/res/options.ico Binary files differnew file mode 100644 index 0000000..af93fd2 --- /dev/null +++ b/miranda-wine/src/res/options.ico diff --git a/miranda-wine/src/res/outtolun.ico b/miranda-wine/src/res/outtolun.ico Binary files differnew file mode 100644 index 0000000..6e5d40e --- /dev/null +++ b/miranda-wine/src/res/outtolun.ico diff --git a/miranda-wine/src/res/rename.ico b/miranda-wine/src/res/rename.ico Binary files differnew file mode 100644 index 0000000..6dd597e --- /dev/null +++ b/miranda-wine/src/res/rename.ico diff --git a/miranda-wine/src/res/reply.ico b/miranda-wine/src/res/reply.ico Binary files differnew file mode 100644 index 0000000..ddaf242 --- /dev/null +++ b/miranda-wine/src/res/reply.ico diff --git a/miranda-wine/src/res/searchal.ico b/miranda-wine/src/res/searchal.ico Binary files differnew file mode 100644 index 0000000..8146dfb --- /dev/null +++ b/miranda-wine/src/res/searchal.ico diff --git a/miranda-wine/src/res/sendmail.ico b/miranda-wine/src/res/sendmail.ico Binary files differnew file mode 100644 index 0000000..55097a1 --- /dev/null +++ b/miranda-wine/src/res/sendmail.ico diff --git a/miranda-wine/src/res/smalldot.ico b/miranda-wine/src/res/smalldot.ico Binary files differnew file mode 100644 index 0000000..47f0556 --- /dev/null +++ b/miranda-wine/src/res/smalldot.ico diff --git a/miranda-wine/src/res/sms.ico b/miranda-wine/src/res/sms.ico Binary files differnew file mode 100644 index 0000000..4beb6e7 --- /dev/null +++ b/miranda-wine/src/res/sms.ico diff --git a/miranda-wine/src/res/sortcold.bmp b/miranda-wine/src/res/sortcold.bmp Binary files differnew file mode 100644 index 0000000..1fc197f --- /dev/null +++ b/miranda-wine/src/res/sortcold.bmp diff --git a/miranda-wine/src/res/sortcolu.bmp b/miranda-wine/src/res/sortcolu.bmp Binary files differnew file mode 100644 index 0000000..271acc9 --- /dev/null +++ b/miranda-wine/src/res/sortcolu.bmp diff --git a/miranda-wine/src/res/timestamp.ico b/miranda-wine/src/res/timestamp.ico Binary files differnew file mode 100644 index 0000000..83b8abf --- /dev/null +++ b/miranda-wine/src/res/timestamp.ico diff --git a/miranda-wine/src/res/url.ico b/miranda-wine/src/res/url.ico Binary files differnew file mode 100644 index 0000000..34a5643 --- /dev/null +++ b/miranda-wine/src/res/url.ico diff --git a/miranda-wine/src/res/useronli.ico b/miranda-wine/src/res/useronli.ico Binary files differnew file mode 100644 index 0000000..b6e4190 --- /dev/null +++ b/miranda-wine/src/res/useronli.ico diff --git a/miranda-wine/src/res/viewdetails.ico b/miranda-wine/src/res/viewdetails.ico Binary files differnew file mode 100644 index 0000000..c9fb124 --- /dev/null +++ b/miranda-wine/src/res/viewdetails.ico diff --git a/miranda-wine/src/resource.h b/miranda-wine/src/resource.h new file mode 100644 index 0000000..eaec7a7 --- /dev/null +++ b/miranda-wine/src/resource.h @@ -0,0 +1,392 @@ +//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDC_AUTHICON 1
+#define IDC_NOTOALL 3
+#define IDC_APPLY 3
+#define IDI_MIRANDA 102
+#define IDD_ABOUT 103
+#define IDI_SMS 103
+#define IDI_ONLINE 104
+#define IDI_OFFLINE 105
+#define IDD_ADDED 115
+#define IDD_URLSEND 119
+#define IDD_URLRECV 120
+#define IDD_AUTHREQ 121
+#define IDD_DETAILS 125
+#define IDD_HISTORY 127
+#define IDI_AWAY 128
+#define IDI_FREE4CHAT 129
+#define IDI_INVISIBLE 130
+#define IDI_NA 131
+#define IDD_OPT_SOUND 134
+#define IDI_RECVMSG 136
+#define IDI_SENDMSG 137
+#define IDI_URL 138
+#define IDI_DND 158
+#define IDI_OCCUPIED 159
+#define IDI_USERDETAILS 160
+#define IDI_FINDUSER 161
+#define IDI_HELP 162
+#define IDI_OPTIONS 163
+#define IDI_MIRANDAWEBSITE 172
+#define IDI_RENAME 173
+#define IDI_HISTORY 174
+#define IDI_DELETE 175
+#define IDR_CONTEXT 180
+#define IDC_DROP 183
+#define IDD_HISTORY_FIND 192
+#define IDI_SENDEMAIL 193
+#define IDD_FILERECV 194
+#define IDD_PROFILEMANAGER 197
+#define IDR_CLISTMENU 199
+#define IDI_BLANK 200
+#define IDD_FINDADD 201
+#define IDI_USERONLINE 201
+#define IDI_GROUPSHUT 202
+#define IDD_OPTIONS 203
+#define IDI_GROUPOPEN 203
+#define IDD_FILESEND 205
+#define IDI_NOTICK 205
+#define IDD_OPT_PLUGINS 206
+#define IDI_TICK 206
+#define IDD_OPT_ICONS 207
+#define IDI_FILE 207
+#define IDI_TIMESTAMP 208
+#define IDI_CHANGEFONT 209
+#define IDI_ADDCONTACT 210
+#define IDI_SMALLDOT 211
+#define IDI_FILLEDBLOB 212
+#define IDD_READAWAYMSG 213
+#define IDI_EMPTYBLOB 213
+#define IDD_OPT_IGNORE 214
+#define IDC_HYPERLINKHAND 214
+#define IDD_OPT_VISIBILITY 215
+#define IDC_DROPUSER 215
+#define IDD_SETAWAYMSG 216
+#define IDI_DETAILSLOGO 216
+#define IDD_OPT_AWAYMSG 217
+#define IDD_INFO_SUMMARY 220
+#define IDD_INFO_CONTACT 221
+#define IDR_CREDITS 221
+#define IDD_INFO_BACKGROUND 222
+#define IDD_INFO_NOTES 223
+#define IDD_ADDEMAIL 226
+#define IDD_ICONINDEX 227
+#define IDD_INFO_LOCATION 231
+#define IDD_INFO_WORK 232
+#define IDD_ADDPHONE 233
+#define IDD_INSTALLINI 235
+#define IDD_WARNINICHANGE 236
+#define IDD_INIIMPORTDONE 237
+#define IDB_SORTCOLUP 239
+#define IDB_SORTCOLDOWN 240
+#define IDD_OPT_NETLIB 246
+#define IDD_NETLIBLOGOPTS 247
+#define IDD_FILETRANSFERINFO 249
+#define IDD_OPT_FILETRANSFER 250
+#define IDD_FILEEXISTS 251
+#define IDD_DELETECONTACT 254
+#define IDD_DENYREASON 256
+#define IDD_ADDCONTACT 257
+#define IDD_OPT_CONTACT 261
+#define IDI_MULTISEND 263
+#define IDI_DOWNARROW 264
+#define IDD_OPT_IDLE 268
+#define IDD_PROFILE_SELECTION 269
+#define IDD_PROFILE_NEW 270
+#define IDC_SAVE 1001
+#define IDI_ONTHEPHONE 1002
+#define IDC_MESSAGE 1002
+#define IDI_OUTTOLUNCH 1003
+#define IDC_AUTOCLOSE 1004
+#define IDC_FROM 1005
+#define IDC_AUTOMIN 1005
+#define IDC_DATE 1006
+#define IDC_DUMPRECV 1006
+#define IDC_MSG 1008
+#define IDC_PROXYDNS 1008
+#define IDC_NAME 1009
+#define IDC_PROXYTYPE 1009
+#define IDC_STATIC23 1010
+#define IDC_NAMEVAL 1010
+#define IDC_SPECIFYPORTS 1013
+#define IDC_ST_ENTERMSG 1013
+#define IDC_ST_ENTERURL 1014
+#define IDC_SPECIFYPORTSO 1014
+#define IDC_SHOWNAMES 1024
+#define IDC_ABOUT 1032
+#define IDC_MYNOTES 1033
+#define IDC_URLS 1037
+#define IDC_REPLY 1039
+#define IDC_URL 1041
+#define IDC_REASON 1046
+#define IDC_EMAIL 1048
+#define IDC_NAMENICK 1049
+#define IDC_NAMEFIRST 1050
+#define IDC_NAMELAST 1051
+#define IDC_NICK 1053
+#define IDC_GENDER 1060
+#define IDC_CITY 1061
+#define IDC_STATE 1062
+#define IDC_COUNTRY 1063
+#define IDC_AGE 1064
+#define IDC_ZIP 1064
+#define IDC_PHONE 1065
+#define IDC_STREET 1065
+#define IDC_COMPANY 1066
+#define IDC_LANGUAGE1 1066
+#define IDC_TIMEZONE 1067
+#define IDC_DEPARTMENT 1067
+#define IDC_LOCALTIME 1068
+#define IDC_DETAILS 1069
+#define IDC_POSITION 1069
+#define IDC_LANGUAGE2 1069
+#define IDC_ADD 1070
+#define IDC_LANGUAGE3 1070
+#define IDC_MOREOPTIONS 1071
+#define IDC_USERMENU 1071
+#define IDC_EDIT 1078
+#define IDC_LIST 1079
+#define IDC_HISTORY 1080
+#define IDC_BUILDTIME 1108
+#define IDC_CREDITSFILE 1109
+#define IDC_NUMBER 1113
+#define IDC_UIN 1123
+#define IDC_FINDWHAT 1131
+#define IDC_FIND 1132
+#define IDC_FILE 1133
+#define IDC_PROFILELIST 1134
+#define IDC_TABS 1141
+#define IDC_RESULTS 1142
+#define IDC_STATUS 1144
+#define IDC_USEPROXY 1148
+#define IDC_PROXYAUTH 1149
+#define IDC_PROXYHOST 1150
+#define IDC_PROXYPORT 1151
+#define IDC_PROXYUSER 1152
+#define IDC_PROXYPASS 1153
+#define IDC_STATIC12 1155
+#define IDC_STATIC21 1156
+#define IDC_STATIC22 1157
+#define IDC_STATIC31 1158
+#define IDC_STATIC32 1159
+#define IDC_PROXYAUTHNTLM 1160
+#define IDC_CHANGE 1164
+#define IDC_PREVIEW 1165
+#define IDC_CHOOSE 1169
+#define IDC_TO 1170
+#define IDC_VERSION 1179
+#define IDC_ICONSET 1183
+#define IDC_BROWSE 1184
+#define IDC_RUNATSTARTBROWSE 1185
+#define IDC_PAGETREE 1186
+#define IDC_RUNNOW 1186
+#define IDC_RETRIEVING 1193
+#define IDC_GETMORE 1200
+#define IDC_VISIBLEICON 1204
+#define IDC_INVISIBLEICON 1205
+#define IDC_FILEICON 1206
+#define IDC_ONLINEICON 1207
+#define IDC_FILENAMES 1208
+#define IDC_ALLICON 1208
+#define IDC_DONTREPLY 1209
+#define IDC_NONEICON 1209
+#define IDC_USEPREVIOUS 1210
+#define IDC_NODIALOG 1211
+#define IDC_USESPECIFIC 1212
+#define IDC_FILEDIR 1213
+#define IDC_ALLFILESPROGRESS 1217
+#define IDC_CURRENTSPEED 1219
+#define IDC_WHITERECT 1221
+#define IDC_ALLSPEED 1221
+#define IDC_CURRENTFILEPROGRESS 1222
+#define IDC_CURRENTFILEGROUP 1223
+#define IDC_FIRSTNAME 1224
+#define IDC_LASTNAME 1225
+#define IDC_CURRENTTRANSFERRED 1225
+#define IDC_DOBDAY 1226
+#define IDC_DOBMONTH 1227
+#define IDC_WEBPAGE 1228
+#define IDC_DOBYEAR 1228
+#define IDC_UPDATING 1231
+#define IDC_NAMEORDER 1234
+#define IDC_RECONNECTREQD 1239
+#define IDC_IMPORT 1241
+#define IDC_TOMAIN 1243
+#define IDC_TOPROTO 1244
+#define IDC_PROTOLIST 1245
+#define IDC_TODEFICON 1246
+#define IDC_IMPORTMULTI 1247
+#define IDC_FILENAME 1271
+#define IDC_INTERESTS 1305
+#define IDC_EMAILS 1306
+#define IDC_PAST 1307
+#define IDC_PHONES 1308
+#define IDC_SMS 1310
+#define IDC_AREA 1312
+#define IDC_UPDATE 1313
+#define IDC_ININAME 1333
+#define IDC_VIEWINI 1334
+#define IDC_SECURITYINFO 1335
+#define IDC_SETTINGNAME 1336
+#define IDC_NEWVALUE 1337
+#define IDC_WARNNOMORE 1338
+#define IDC_DELETE 1339
+#define IDC_RECYCLE 1340
+#define IDC_NEWNAME 1341
+#define IDC_MOVE 1342
+#define IDC_LEAVE 1343
+#define IDC_EXPERT 1346
+#define IDC_CATEGORYLIST 1366
+#define IDC_LOADICONS 1369
+#define IDC_STICONSGROUP 1371
+#define IDC_MSGICON 1375
+#define IDC_URLICON 1376
+#define IDC_STNOPAGE 1377
+#define IDC_STCHECKMARKS 1380
+#define IDC_MIRANDA 1388
+#define IDC_STATUSBAR 1389
+#define IDC_PROTOIDGROUP 1392
+#define IDC_BYPROTOID 1393
+#define IDC_PROTOID 1394
+#define IDC_EMAILGROUP 1395
+#define IDC_BYEMAIL 1396
+#define IDC_STNAMENICK 1397
+#define IDC_NAMEGROUP 1398
+#define IDC_BYNAME 1399
+#define IDC_STNAMEFIRST 1400
+#define IDC_STNAMELAST 1401
+#define IDC_ADVANCEDGROUP 1402
+#define IDC_BYADVANCED 1403
+#define IDC_ADVANCED 1404
+#define IDC_STSIMPLERIGHT 1440
+#define IDC_NETLIBUSERS 1443
+#define IDC_STOFTENPORT 1445
+#define IDC_STATIC51 1446
+#define IDC_STATIC52 1447
+#define IDC_STATIC43 1448
+#define IDC_LOGOPTIONS 1449
+#define IDC_PORTSRANGE 1450
+#define IDC_STATIC53 1451
+#define IDC_PORTSRANGEO 1452
+#define IDC_STATIC54 1453
+#define IDC_TOOUTPUTDEBUGSTRING 1455
+#define IDC_TOFILE 1456
+#define IDC_RUNATSTART 1458
+#define IDC_DUMPSENT 1464
+#define IDC_DUMPPROXY 1466
+#define IDC_TEXTDUMPS 1467
+#define IDC_AUTODETECTTEXT 1468
+#define IDC_TIMEFORMAT 1469
+#define IDC_FILENAMEBROWSE 1470
+#define IDC_SHOWTHISDLGATSTART 1471
+#define IDC_FILEDIRBROWSE 1475
+#define IDC_ALLFILESGROUP 1476
+#define IDC_SCANCMDLINEBROWSE 1476
+#define IDC_ALLTRANSFERRED 1477
+#define IDC_OPENFOLDER 1478
+#define IDC_OPENFILE 1479
+#define IDC_TOTALSIZE 1480
+#define IDC_AUTOACCEPT 1484
+#define IDC_SCANCMDLINE 1485
+#define IDC_WARNBEFOREOPENING 1488
+#define IDC_SCANDURINGDL 1489
+#define IDC_SCANAFTERDL 1490
+#define IDC_NOSCANNER 1491
+#define IDC_ST_CMDLINE 1492
+#define IDC_ST_CMDLINEHELP 1493
+#define IDC_PROPERTIES 1496
+#define IDC_RESUME 1497
+#define IDC_EXISTINGICON 1499
+#define IDC_RESUMEALL 1500
+#define IDC_OVERWRITE 1501
+#define IDC_OVERWRITEALL 1502
+#define IDC_SKIP 1503
+#define IDC_EXISTINGSIZE 1506
+#define IDC_EXISTINGDATE 1507
+#define IDC_EXISTINGTYPE 1508
+#define IDC_NEWICON 1509
+#define IDC_NEWSIZE 1510
+#define IDC_NEWDATE 1511
+#define IDC_NEWTYPE 1512
+#define IDC_SAVEAS 1513
+#define IDC_ASK 1516
+#define IDC_RENAME 1519
+#define IDC_VIRUSSCANNERGROUP 1520
+#define IDC_HIDE 1534
+#define IDC_TOPLINE 1535
+#define IDC_MAIL 1536
+#define IDC_DESCRIPTION 1538
+#define IDC_MYHANDLE 1540
+#define IDC_GROUP 1541
+#define IDC_ADDED 1542
+#define IDC_AUTH 1543
+#define IDC_DELETEHISTORY 1560
+#define IDC_AUTHREQ 1577
+#define IDC_AUTHGB 1578
+#define IDC_PROTOCOL 1580
+#define IDC_CONTRIBLINK 1586
+#define IDC_DEVS 1589
+#define IDC_LOGO 1591
+#define IDC_IDLEONWINDOWS 1637
+#define IDC_IDLEONMIRANDA 1638
+#define IDC_SCREENSAVER 1642
+#define IDC_LOCKED 1643
+#define IDC_IDLESHORT 1644
+#define IDC_IDLE1STTIME 1646
+#define IDC_IDLEPRIVATE 1649
+#define IDC_AASTATUS 1650
+#define IDC_AASHORTIDLE 1651
+#define IDC_SOUNDTREE 1657
+#define IDC_LOCATION 1659
+#define IDC_SGROUP 1660
+#define IDC_SLOC 1661
+#define IDC_PROFILENAME 1673
+#define IDC_PROFILEDRIVERS 1674
+#define IDC_PLUGLIST 1676
+#define IDC_PLUGINLONGINFO 1677
+#define IDC_PLUGINAUTHOR 1679
+#define IDC_PLUGININFOFRAME 1680
+#define IDC_PLUGINCPYR 1681
+#define IDC_PLUGINURL 1682
+#define IDC_PLUGINEMAIL 1684
+#define IDC_IDLESPIN 1687
+#define IDC_NODBDRIVERS 1690
+#define IDC_IDLESTATUSLOCK 1691
+#define IDC_RESTART 1692
+#define IDI_SEARCHALL 32548
+#define ID_ICQ_EXIT 40001
+#define IDM_COPY 40001
+#define ID_RESET 40002
+#define POPUP_HIDEEMPTYGROUPS 40003
+#define POPUP_NEWSUBGROUP 40004
+#define POPUP_HIDEOFFLINE 40005
+#define POPUP_GROUPHIDEOFFLINE 40006
+#define POPUP_HIDEOFFLINEROOT 40007
+#define POPUP_DISABLEGROUPS 40008
+#define IDC_SENDMESSAGE 40009
+#define IDM_COPYALL 40011
+#define IDM_SELECTALL 40012
+#define IDM_CLEAR 40013
+#define IDM_OPENNEW 40014
+#define IDM_OPENEXISTING 40015
+#define IDM_COPYLINK 40016
+#define POPUP_HIDEMIRANDA 40017
+#define ID_TRAY_HIDE 40038
+#define ID_TRAY_EXIT 40040
+#define POPUP_NEWGROUP 40050
+#define POPUP_RENAMEGROUP 40052
+#define POPUP_DELETEGROUP 40053
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 274
+#define _APS_NEXT_COMMAND_VALUE 40018
+#define _APS_NEXT_CONTROL_VALUE 1693
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/src/resource.rc b/miranda-wine/src/resource.rc new file mode 100644 index 0000000..688efbd --- /dev/null +++ b/miranda-wine/src/resource.rc @@ -0,0 +1,1765 @@ +//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include <winres.h>
+#include "../include/statusmodes.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_AUTHREQ DIALOGEX 0, 0, 242, 107
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Authorization Request"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Authorize",IDOK,66,88,50,14
+ PUSHBUTTON "&Deny",IDCANCEL,132,88,50,14
+ CONTROL "&U",IDC_ADD,"MButtonClass",WS_TABSTOP,201,4,16,14,
+ 0x18000000L
+ CONTROL "&I",IDC_DETAILS,"MButtonClass",WS_TABSTOP,219,4,16,14,
+ 0x18000000L
+ LTEXT "",IDC_NAME,53,24,134,10,SS_CENTERIMAGE
+ LTEXT "",IDC_MAIL,53,39,110,10,SS_CENTERIMAGE
+ LTEXT "",IDC_UIN,20,7,178,10,SS_CENTERIMAGE
+ EDITTEXT IDC_REASON,53,58,182,26,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | NOT WS_BORDER | WS_VSCROLL,
+ WS_EX_STATICEDGE
+ LTEXT "Nick:",IDC_STATIC,7,24,40,10,SS_CENTERIMAGE
+ LTEXT "E-mail:",IDC_STATIC,7,39,40,10,SS_CENTERIMAGE
+ LTEXT "Reason:",IDC_STATIC,7,55,40,10,SS_CENTERIMAGE
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,4,6,
+ 12,12
+END
+
+IDD_DENYREASON DIALOGEX 0, 0, 172, 70
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Enter a reason for denial"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_REASON,6,6,160,36,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN
+ DEFPUSHBUTTON "&Send",IDOK,61,50,50,14
+END
+
+IDD_ADDCONTACT DIALOGEX 0, 0, 230, 151
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Add",IDOK,20,130,72,14
+ PUSHBUTTON "&Cancel",IDCANCEL,139,130,71,14
+ EDITTEXT IDC_MYHANDLE,6,16,90,12,ES_AUTOHSCROLL
+ COMBOBOX IDC_GROUP,112,16,110,60,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Send ""You were added""",IDC_ADDED,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,11,46,204,10
+ CONTROL "Send authorization request",IDC_AUTH,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,11,60,204,10
+ LTEXT "Custom name:",IDC_STATIC,6,4,70,10
+ LTEXT "Group:",IDC_STATIC,112,4,70,10
+ GROUPBOX "Options",IDC_STATIC,7,33,216,43
+ GROUPBOX "Authorization Request",IDC_AUTHGB,7,79,216,45
+ EDITTEXT IDC_AUTHREQ,13,89,204,29,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_ADDED DIALOGEX 0, 0, 225, 57
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "You Were Added"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "&Close",IDCANCEL,83,38,60,14
+ CTEXT "You were added to this user's contact list.",IDC_STATIC,
+ 7,19,210,14,SS_CENTERIMAGE
+ EDITTEXT IDC_NAME,17,5,160,12,ES_READONLY | NOT WS_BORDER
+ CONTROL "&I",IDC_DETAILS,"MButtonClass",WS_TABSTOP,201,3,16,14,
+ 0x18000000L
+ CONTROL "&U",IDC_ADD,"MButtonClass",WS_TABSTOP,183,3,16,14,
+ 0x18000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,4,4,
+ 12,12
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 212, 131
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "About Miranda IM"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "",IDC_WHITERECT,0,0,213,105
+ DEFPUSHBUTTON "OK",IDOK,152,112,55,14
+ LTEXT "Miranda IM",IDC_MIRANDA,5,7,150,15
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,106,213,1
+ LTEXT "",IDC_DEVS,5,44,202,42
+ ICON IDI_MIRANDA,IDC_LOGO,187,2,20,20
+ EDITTEXT IDC_BUILDTIME,4,91,146,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ PUSHBUTTON "Credits >",IDC_CONTRIBLINK,5,112,55,14
+ LTEXT "Version",IDC_VERSION,5,25,150,15
+ EDITTEXT IDC_CREDITSFILE,4,44,202,56,ES_CENTER | ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER | WS_VSCROLL
+END
+
+IDD_DELETECONTACT DIALOGEX 0, 0, 284, 90
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Delete Contact"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "No",IDNO,162,38,65,14
+ PUSHBUTTON "Yes",IDYES,54,38,65,14
+ CONTROL "Hide from list only, in order to keep their history and ignore/visibility settings",
+ IDC_HIDE,"Button",BS_AUTOCHECKBOX | BS_MULTILINE |
+ WS_TABSTOP,7,65,270,9
+ LTEXT "Use Options->Ignore (expert mode) to unhide contacts.",
+ IDC_STATIC,20,78,257,8
+ CONTROL "Are you sure you want to delete %s?",IDC_TOPLINE,"Static",
+ SS_SIMPLE | SS_NOPREFIX | WS_GROUP,7,7,270,8
+ LTEXT "This will erase all history and settings for this contact!",
+ IDC_STATIC,7,18,239,14
+END
+
+IDD_OPT_CONTACT DIALOGEX 0, 0, 199, 144
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Contact Display Options",IDC_STATIC,13,7,176,127
+ LTEXT "Instead of displaying contacts by their nickname, drag to choose another order:",
+ IDC_STATIC,19,17,165,23
+ CONTROL "Tree1",IDC_NAMEORDER,"SysTreeView32",TVS_NOTOOLTIPS |
+ TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,19,43,164,86
+END
+
+IDD_PROFILEMANAGER DIALOGEX 0, 0, 400, 211
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Miranda IM Profile Manager"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK |
+ WS_TABSTOP,4,31,393,160
+ PUSHBUTTON "&Run",IDOK,298,194,48,14
+ PUSHBUTTON "&Exit",IDCANCEL,348,194,48,14
+ LTEXT "",IDC_WHITERECT,0,0,400,26
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,25,410,1
+ ICON IDI_DETAILSLOGO,IDC_LOGO,7,3,20,20
+ LTEXT "Miranda",IDC_NAME,35,4,360,8,0,WS_EX_TRANSPARENT
+ LTEXT "Select and/or create your Miranda IM user profile",
+ IDC_DESCRIPTION,45,14,349,8,0,WS_EX_TRANSPARENT
+END
+
+IDD_FINDADD DIALOGEX 0, 0, 427, 232
+STYLE DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find/Add Contacts"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Search:",IDC_STATIC,5,7,37,8
+ CONTROL "",IDC_PROTOLIST,"ComboBoxEx32",CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP,42,5,80,88
+ GROUPBOX "",IDC_PROTOIDGROUP,5,21,117,32
+ CONTROL "",IDC_BYPROTOID,"Button",BS_AUTORADIOBUTTON,11,21,85,10
+ EDITTEXT IDC_PROTOID,11,34,105,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_EMAILGROUP,5,58,117,32
+ CONTROL "E-mail address",IDC_BYEMAIL,"Button",BS_AUTORADIOBUTTON,
+ 11,58,80,10
+ EDITTEXT IDC_EMAIL,11,71,105,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_NAMEGROUP,5,95,117,59
+ CONTROL "Name",IDC_BYNAME,"Button",BS_AUTORADIOBUTTON,11,95,49,
+ 10
+ LTEXT "Nick:",IDC_STNAMENICK,11,110,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMENICK,42,108,74,12,ES_AUTOHSCROLL
+ LTEXT "First:",IDC_STNAMEFIRST,11,124,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMEFIRST,42,122,74,12,ES_AUTOHSCROLL
+ LTEXT "Last:",IDC_STNAMELAST,11,138,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMELAST,42,136,74,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_ADVANCEDGROUP,5,159,117,32
+ CONTROL "Advanced",IDC_BYADVANCED,"Button",BS_AUTORADIOBUTTON,11,
+ 159,62,10
+ CONTROL "Advanced >>",IDC_ADVANCED,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,11,171,105,14
+ DEFPUSHBUTTON "&Search",IDOK,5,197,117,17
+ CONTROL "List1",IDC_RESULTS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_AUTOARRANGE |
+ WS_BORDER | WS_TABSTOP,129,5,293,191
+ CONTROL "More options",IDC_MOREOPTIONS,"MButtonClass",
+ WS_DISABLED | WS_TABSTOP,272,200,77,14,0x18000000L
+ PUSHBUTTON "Add to list",IDC_ADD,354,200,68,14,WS_DISABLED
+ CONTROL "",IDC_STATUSBAR,"msctls_statusbar32",WS_TABSTOP | 0x100,
+ 0,220,427,10
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 428, 271
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX |
+ WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,266,253,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,320,253,50,14
+ PUSHBUTTON "Apply",IDC_APPLY,374,253,50,14
+ CONTROL "Tree1",IDC_PAGETREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_TABSTOP,4,4,102,
+ 247,WS_EX_STATICEDGE
+ CONTROL "Show expert options",IDC_EXPERT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,5,257,102,10
+ CTEXT "Please select a subentry from the list",IDC_STNOPAGE,
+ 111,4,313,240,SS_CENTERIMAGE
+END
+
+IDD_READAWAYMSG DIALOGEX 0, 0, 187, 72
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "%s Message for %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Cancel",IDOK,69,53,50,14
+ CTEXT "Retrieving %s message...",IDC_RETRIEVING,5,21,177,8,
+ SS_NOPREFIX
+ EDITTEXT IDC_MSG,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | NOT WS_VISIBLE | WS_VSCROLL
+END
+
+IDD_SETAWAYMSG DIALOGEX 0, 0, 187, 72
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Change %s Message"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Closing in %d",IDOK,61,53,65,14
+ EDITTEXT IDC_MSG,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_DETAILS DIALOGEX 0, 0, 318, 210
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "%s: User Details"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,263,191,50,14
+ LTEXT "",IDC_WHITERECT,0,0,318,26
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,26,320,1
+ ICON IDI_DETAILSLOGO,IDC_LOGO,7,4,20,20
+ LTEXT "",IDC_NAME,33,5,200,8,0,WS_EX_TRANSPARENT
+ CONTROL "",IDC_PAGETREE,"SysTreeView32",TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT |
+ TVS_FULLROWSELECT | TVS_NONEVENHEIGHT | WS_TABSTOP,3,30,76,176,
+ WS_EX_STATICEDGE
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK |
+ TCS_MULTILINE | WS_TABSTOP,85,29,228,158
+ LTEXT "View personal user details and more.",IDC_STATIC,44,13,
+ 189,8,0,WS_EX_TRANSPARENT
+ CTEXT "Updating",IDC_UPDATING,145,194,113,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ PUSHBUTTON "Update Now",IDC_UPDATE,85,191,55,14,WS_DISABLED
+END
+
+IDD_INFO_SUMMARY DIALOGEX 0, 0, 222, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Nickname:",IDC_STATIC,5,5,46,8
+ EDITTEXT IDC_NICK,51,5,166,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "First name:",IDC_STATIC,5,18,46,8
+ EDITTEXT IDC_FIRSTNAME,51,18,74,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Gender:",IDC_STATIC,126,18,44,8
+ EDITTEXT IDC_GENDER,170,18,47,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Last name:",IDC_STATIC,5,31,46,8
+ EDITTEXT IDC_LASTNAME,51,31,74,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Age:",IDC_STATIC,126,31,44,8
+ EDITTEXT IDC_AGE,170,31,47,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "E-mail:",IDC_STATIC,5,44,46,8
+ CONTROL "",IDC_EMAIL,"Hyperlink",WS_TABSTOP,51,44,166,8
+ LTEXT "Date of birth:",IDC_STATIC,5,58,46,8
+ EDITTEXT IDC_DOBDAY,51,58,17,8,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_DOBMONTH,68,58,19,8,ES_CENTER | ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_DOBYEAR,87,58,25,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+END
+
+IDD_INFO_CONTACT DIALOGEX 0, 0, 222, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "E-mail:",IDC_STATIC,5,5,212,8
+ CONTROL "List1",IDC_EMAILS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,5,14,212,50
+ LTEXT "Phone:",IDC_STATIC,5,68,212,8
+ CONTROL "List1",IDC_PHONES,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,5,77,212,50
+END
+
+IDD_INFO_BACKGROUND DIALOGEX 0, 0, 222, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Web page:",IDC_STATIC,5,5,44,8
+ CONTROL "",IDC_WEBPAGE,"Hyperlink",WS_TABSTOP,49,5,168,8
+ LTEXT "Past background:",IDC_STATIC,5,18,212,8
+ CONTROL "List1",IDC_PAST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,5,27,212,44
+ LTEXT "Interests:",IDC_STATIC,5,74,212,8
+ CONTROL "List1",IDC_INTERESTS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,5,83,212,44
+END
+
+IDD_INFO_NOTES DIALOGEX 0, 0, 222, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "About:",IDC_STATIC,5,5,212,8
+ EDITTEXT IDC_ABOUT,5,13,212,45,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+ LTEXT "My notes:",IDC_STATIC,5,61,212,8
+ EDITTEXT IDC_MYNOTES,5,69,212,58,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_INFO_LOCATION DIALOGEX 0, 0, 222, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Street:",IDC_STATIC,5,5,51,8
+ EDITTEXT IDC_STREET,56,5,161,16,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "City:",IDC_STATIC,5,22,51,8
+ EDITTEXT IDC_CITY,56,22,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "State:",IDC_STATIC,5,33,51,8
+ EDITTEXT IDC_STATE,56,33,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Postal code:",IDC_STATIC,5,44,51,8
+ EDITTEXT IDC_ZIP,56,44,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Country:",IDC_STATIC,5,55,51,8
+ EDITTEXT IDC_COUNTRY,56,55,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Spoken languages:",IDC_STATIC,5,70,51,16
+ EDITTEXT IDC_LANGUAGE1,56,70,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ EDITTEXT IDC_LANGUAGE2,56,78,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ EDITTEXT IDC_LANGUAGE3,56,86,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Timezone:",IDC_STATIC,5,97,51,8
+ EDITTEXT IDC_TIMEZONE,56,97,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Local time:",IDC_STATIC,5,108,51,8
+ EDITTEXT IDC_LOCALTIME,56,108,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+END
+
+IDD_INFO_WORK DIALOGEX 0, 0, 222, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Company:",IDC_STATIC,5,5,51,8
+ EDITTEXT IDC_COMPANY,56,5,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Department:",IDC_STATIC,5,17,51,8
+ EDITTEXT IDC_DEPARTMENT,56,17,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Position:",IDC_STATIC,5,28,51,8
+ EDITTEXT IDC_POSITION,56,28,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Street:",IDC_STATIC,5,48,51,8
+ EDITTEXT IDC_STREET,56,48,161,16,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "City:",IDC_STATIC,5,65,51,8
+ EDITTEXT IDC_CITY,56,65,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "State:",IDC_STATIC,5,76,51,8
+ EDITTEXT IDC_STATE,56,76,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Postal code:",IDC_STATIC,5,87,51,8
+ EDITTEXT IDC_ZIP,56,87,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Country:",IDC_STATIC,5,98,51,8
+ EDITTEXT IDC_COUNTRY,56,98,161,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Website:",IDC_STATIC,5,109,51,8
+ CONTROL "",IDC_WEBPAGE,"Hyperlink",WS_TABSTOP,57,109,160,8
+END
+
+IDD_ADDEMAIL DIALOGEX 0, 0, 187, 42
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add E-Mail Address"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_EMAIL,5,5,177,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,36,23,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,23,50,14
+END
+
+IDD_ADDPHONE DIALOGEX 0, 0, 210, 91
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add Phone Number"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Enter country, area code and phone number:",IDC_STATIC,
+ 5,5,200,8
+ COMBOBOX IDC_COUNTRY,21,15,66,120,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_AREA,91,15,36,12,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_NUMBER,131,15,74,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "Or enter a full international number:",IDC_STATIC,5,30,
+ 200,8
+ EDITTEXT IDC_PHONE,21,40,184,12,ES_AUTOHSCROLL
+ CONTROL "Phone can receive SMS text messages",IDC_SMS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,5,56,200,10
+ DEFPUSHBUTTON "OK",IDOK,47,72,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,113,72,50,14
+END
+
+IDD_INSTALLINI DIALOGEX 0, 0, 213, 103
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Install Database Settings"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,26,84,50,14
+ PUSHBUTTON "No",IDCANCEL,81,84,50,14
+ LTEXT "A file containing new database settings has been placed in the Miranda IM directory.",
+ IDC_STATIC,5,5,203,16
+ LTEXT "Do you want to import the settings now?",IDC_STATIC,5,
+ 69,203,8
+ PUSHBUTTON "No to all",IDC_NOTOALL,136,84,50,14
+ LTEXT "",IDC_ININAME,5,24,143,16,SS_NOPREFIX | SS_CENTERIMAGE
+ PUSHBUTTON "&View contents",IDC_VIEWINI,150,25,58,14
+ LTEXT "Security systems to prevent malicious changes are in place and you will be warned before changes that are not known to be safe.",
+ IDC_SECURITYINFO,5,43,203,24
+END
+
+IDD_WARNINICHANGE DIALOGEX 0, 0, 187, 113
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Setting Change"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Database settings are being imported from",IDC_STATIC,5,
+ 5,177,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,5,13,177,8
+ LTEXT "This file wishes to change the setting",IDC_STATIC,5,24,
+ 177,8
+ CONTROL "",IDC_SETTINGNAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,12,33,170,8
+ LTEXT "to the value",IDC_STATIC,5,42,177,8
+ CONTROL "",IDC_NEWVALUE,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,12,51,170,8
+ LTEXT "",IDC_SECURITYINFO,5,60,177,8
+ LTEXT "Do you want to allow this change?",IDC_STATIC,5,71,177,
+ 8
+ CONTROL "&Allow all further changes to this section",
+ IDC_WARNNOMORE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,
+ 80,169,10
+ DEFPUSHBUTTON "&Yes",IDYES,5,94,50,14
+ PUSHBUTTON "&No",IDNO,59,94,50,14
+ PUSHBUTTON "Cancel Import",IDCANCEL,123,94,59,14
+END
+
+IDD_INIIMPORTDONE DIALOGEX 0, 0, 186, 73
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Import Complete"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The import has completed from",IDC_STATIC,5,5,176,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,5,13,176,8
+ LTEXT "What do you want to do with the file now?",IDC_STATIC,5,
+ 24,176,8
+ PUSHBUTTON "&Recycle",IDC_RECYCLE,5,36,50,14
+ PUSHBUTTON "&Delete",IDC_DELETE,68,36,50,14
+ EDITTEXT IDC_NEWNAME,5,55,117,12,ES_AUTOHSCROLL
+ PUSHBUTTON "&Move/Rename",IDC_MOVE,124,54,57,14
+ PUSHBUTTON "&Leave",IDC_LEAVE,131,36,50,14
+END
+
+IDD_NETLIBLOGOPTS DIALOGEX 0, 0, 261, 201
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Netlib Log Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Show",IDC_STATIC,5,5,250,78
+ CONTROL "Sent bytes",IDC_DUMPSENT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,148,17,65,10
+ CONTROL "Received bytes",IDC_DUMPRECV,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,13,17,133,10
+ CONTROL "Additional data due to proxy communication",
+ IDC_DUMPPROXY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,
+ 28,234,10
+ CONTROL "Text dumps where available",IDC_TEXTDUMPS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,39,133,10
+ CONTROL "Auto-detect text",IDC_AUTODETECTTEXT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,148,39,99,10
+ COMBOBOX IDC_TIMEFORMAT,13,52,164,69,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Calling modules' names",IDC_SHOWNAMES,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,66,234,10
+ GROUPBOX "Log to",IDC_STATIC,5,87,250,43
+ CONTROL "OutputDebugString()",IDC_TOOUTPUTDEBUGSTRING,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,100,122,10
+ CONTROL "File",IDC_TOFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 13,113,42,10
+ EDITTEXT IDC_FILENAME,56,112,173,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FILENAMEBROWSE,232,112,15,12
+ CONTROL "Show this dialog box when Miranda IM starts",
+ IDC_SHOWTHISDLGATSTART,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,5,135,250,10
+ LTEXT "Run programme when Miranda IM starts (eg tail -f, dbgview, etc):",
+ IDC_STATIC,5,147,250,8
+ EDITTEXT IDC_RUNATSTART,13,158,170,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_RUNATSTARTBROWSE,186,158,15,12
+ PUSHBUTTON "Run now",IDC_RUNNOW,205,158,42,12
+ PUSHBUTTON "Save as default",IDC_SAVE,5,182,77,14
+ DEFPUSHBUTTON "Close",IDOK,205,182,50,14
+END
+
+IDD_HISTORY_FIND DIALOGEX 0, 0, 230, 46
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_FINDWHAT,48,11,115,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Find Next",IDOK,173,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,173,24,50,14
+ LTEXT "Find What:",IDC_STATIC,7,13,39,9
+END
+
+IDD_FILESEND DIALOGEX 0, 0, 256, 177
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Send File(s)"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_MSG,6,102,245,46,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+ DEFPUSHBUTTON "&Send",IDOK,67,157,50,15
+ PUSHBUTTON "Cancel",IDCANCEL,140,157,50,15
+ LTEXT "To:",IDC_STATIC,6,23,24,9,SS_CENTERIMAGE
+ CONTROL "",IDC_TO,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,43,
+ 24,159,9
+ LTEXT "File(s):",IDC_STATIC,7,39,30,8
+ EDITTEXT IDC_FILE,38,38,213,31,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY
+ PUSHBUTTON "&Choose Again...",IDC_CHOOSE,39,74,77,14
+ RTEXT "Total size:",IDC_STATIC,119,76,68,8
+ CONTROL "",IDC_TOTALSIZE,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,191,76,58,8
+ LTEXT "Description:",IDC_STATIC,6,93,96,8
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,195,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,213,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,231,5,16,14,
+ 0x18000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,151,9,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_FILERECV DIALOGEX 0, 0, 256, 174
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Incoming File Transfer"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "A&ccept",IDOK,68,155,50,14
+ PUSHBUTTON "&Decline",IDCANCEL,138,155,50,14
+ LTEXT "From:",IDC_STATIC,6,20,24,9,SS_CENTERIMAGE
+ CONTROL "",IDC_FROM,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,
+ 39,21,159,9
+ LTEXT "Date:",IDC_STATIC,6,35,28,9,SS_CENTERIMAGE
+ CONTROL "",IDC_DATE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,
+ 39,34,159,9
+ LTEXT "Files:",IDC_STATIC,6,50,28,8
+ EDITTEXT IDC_FILENAMES,39,50,210,16,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LTEXT "Description:",IDC_STATIC,6,69,64,8
+ EDITTEXT IDC_MSG,6,79,243,45,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY
+ LTEXT "Save to:",IDC_STATIC,6,131,34,8
+ PUSHBUTTON "...",IDC_FILEDIRBROWSE,235,130,14,10
+ COMBOBOX IDC_FILEDIR,45,129,187,108,CBS_DROPDOWN |
+ CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,177,5,16,14,
+ 0x18000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,195,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,213,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,231,5,16,14,
+ 0x18000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,151,9,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_FILETRANSFERINFO DIALOGEX 0, 0, 256, 155
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Cancel",IDCANCEL,162,136,89,14
+ LTEXT "Status:",IDC_STATIC,9,0,31,9,SS_CENTERIMAGE
+ CONTROL "",IDC_STATUS,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,41,0,210,9
+ GROUPBOX "Current file",IDC_CURRENTFILEGROUP,5,13,246,62
+ CONTROL "",IDC_FILENAME,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX |
+ WS_GROUP,11,25,234,8
+ CONTROL "Transferred:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,36,58,8
+ CONTROL "",IDC_CURRENTTRANSFERRED,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,69,36,176,8
+ CONTROL "Speed:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,47,58,8
+ CONTROL "",IDC_CURRENTSPEED,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,69,47,176,8
+ CONTROL "Progress1",IDC_CURRENTFILEPROGRESS,"msctls_progress32",
+ PBS_SMOOTH | WS_DISABLED,11,59,234,8
+ GROUPBOX "All files",IDC_ALLFILESGROUP,5,79,246,51
+ CONTROL "Transferred:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,91,58,8
+ CONTROL "",IDC_ALLTRANSFERRED,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,69,91,176,8
+ CONTROL "Speed:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,11,102,58,8
+ CONTROL "",IDC_ALLSPEED,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX |
+ WS_GROUP,69,102,176,8
+ CONTROL "Progress1",IDC_ALLFILESPROGRESS,"msctls_progress32",
+ PBS_SMOOTH | WS_DISABLED,11,114,234,8
+ PUSHBUTTON "Open folder",IDC_OPENFOLDER,5,136,64,14
+ CONTROL "Open file",IDC_OPENFILE,"MButtonClass",WS_DISABLED |
+ WS_TABSTOP,75,136,66,14,0x18000000L
+END
+
+IDD_FILEEXISTS DIALOGEX 0, 0, 288, 181
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "File Already Exists"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "Resume",IDC_RESUME,5,144,65,14
+ PUSHBUTTON "Resume all",IDC_RESUMEALL,5,162,65,14
+ PUSHBUTTON "Overwrite",IDC_OVERWRITE,76,144,65,14
+ PUSHBUTTON "Overwrite all",IDC_OVERWRITEALL,76,162,65,14
+ PUSHBUTTON "Save as...",IDC_SAVEAS,147,144,65,14
+ PUSHBUTTON "Skip",IDC_SKIP,218,144,65,14
+ PUSHBUTTON "Cancel transfer",IDCANCEL,218,162,65,14
+ LTEXT "You are about to receive the file",IDC_STATIC,5,5,278,8
+ EDITTEXT IDC_FILENAME,15,16,268,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ GROUPBOX "Existing file",IDC_STATIC,5,29,278,61
+ ICON "",IDC_EXISTINGICON,14,45,20,20,SS_NOTIFY
+ LTEXT "Size:",IDC_STATIC,40,42,27,8
+ LTEXT "",IDC_EXISTINGSIZE,67,42,35,8
+ RTEXT "Last modified:",IDC_STATIC,103,42,58,8
+ LTEXT "",IDC_EXISTINGDATE,166,42,115,8
+ LTEXT "Type:",IDC_STATIC,40,55,27,8
+ LTEXT "",IDC_EXISTINGTYPE,67,55,214,8
+ PUSHBUTTON "Open file",IDC_OPENFILE,12,70,62,13
+ PUSHBUTTON "Open folder",IDC_OPENFOLDER,82,70,62,13
+ PUSHBUTTON "File properties",IDC_PROPERTIES,201,70,74,13
+ GROUPBOX "File being received",IDC_STATIC,5,95,278,42
+ ICON "",IDC_NEWICON,14,110,20,20,SS_NOTIFY
+ LTEXT "Size:",IDC_STATIC,40,108,27,8
+ LTEXT "",IDC_NEWSIZE,67,108,35,8
+ RTEXT "Last modified:",IDC_STATIC,103,108,58,8
+ LTEXT "",IDC_NEWDATE,166,108,115,8
+ LTEXT "Type:",IDC_STATIC,40,121,27,8
+ LTEXT "",IDC_NEWTYPE,67,121,214,8
+END
+
+IDD_URLSEND DIALOGEX 0, 0, 215, 126
+STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_URLS,5,30,205,92,CBS_DROPDOWN | CBS_AUTOHSCROLL |
+ WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_MESSAGE,5,57,205,44,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+ DEFPUSHBUTTON "&Send",IDOK,54,107,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,113,107,50,14
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,118,9,SS_NOPREFIX | SS_CENTERIMAGE
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,140,5,16,14,
+ 0x18000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,158,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,176,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,194,5,16,14,
+ 0x18000000L
+ LTEXT "Enter URL:",IDC_ST_ENTERURL,5,20,205,8
+ LTEXT "Enter description:",IDC_ST_ENTERMSG,5,47,205,8
+END
+
+IDD_URLRECV DIALOGEX 0, 0, 215, 140
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "URL Recieved"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "&Open URL",IDOK,"MButtonClass",WS_TABSTOP,11,120,57,14,
+ 0x18000000L
+ PUSHBUTTON "&Reply",IDC_REPLY,82,120,50,14
+ PUSHBUTTON "&Close",IDCANCEL,148,120,50,14
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,
+ 12,12
+ LTEXT "",IDC_NAME,19,7,118,9,SS_NOPREFIX | SS_CENTERIMAGE
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,140,5,16,14,
+ 0x18000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,158,5,16,14,
+ 0x18000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,176,5,16,14,
+ 0x18000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,194,5,16,14,
+ 0x18000000L
+ LTEXT "Date:",IDC_STATIC,5,21,29,8
+ EDITTEXT IDC_DATE,34,21,176,12,ES_AUTOHSCROLL | ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "URL:",IDC_STATIC,5,33,205,8
+ EDITTEXT IDC_URL,5,43,205,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Description:",IDC_ST_ENTERMSG,5,60,205,8
+ EDITTEXT IDC_MSG,5,70,205,44,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+END
+
+IDD_HISTORY DIALOGEX 0, 0, 296, 166
+STYLE DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Message History"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,239,144,50,14
+ EDITTEXT IDC_EDIT,7,83,282,52,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+ LISTBOX IDC_LIST,7,7,282,72,LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Find...",IDC_FIND,7,144,50,14
+ PUSHBUTTON "Delete",IDC_DELETEHISTORY,66,144,50,14
+END
+
+IDD_OPT_SOUND DIALOGEX 0, 0, 285, 240
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Sounds",IDC_STATIC,4,4,277,154
+ PUSHBUTTON "&Change...",IDC_CHANGE,16,213,50,14
+ PUSHBUTTON "&Preview",IDC_PREVIEW,70,213,50,14
+ CONTROL "Download more sounds",IDC_GETMORE,"Hyperlink",
+ WS_TABSTOP | 0x2,127,216,137,8
+ CONTROL "Tree1",IDC_SOUNDTREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER |
+ WS_TABSTOP,12,15,261,137
+ GROUPBOX "Sound Information",IDC_SGROUP,4,162,277,71
+ LTEXT "Location:",IDC_SLOC,17,190,40,9
+ LTEXT "",IDC_LOCATION,65,190,208,18
+ LTEXT "Name:",IDC_NAME,17,174,39,9
+ LTEXT "",IDC_NAMEVAL,64,174,209,9
+END
+
+IDD_OPT_ICONS DIALOGEX 0, 0, 257, 193
+STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Icons",IDC_STICONSGROUP,4,4,248,185
+ LTEXT "Show category:",IDC_STATIC,12,18,66,16
+ LISTBOX IDC_CATEGORYLIST,114,17,129,41,LBS_NOINTEGRALHEIGHT |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL |
+ LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,12,66,231,83
+ PUSHBUTTON "&Load icon set...",IDC_LOADICONS,12,158,94,13
+ PUSHBUTTON "&Import icons >>",IDC_IMPORT,154,158,89,13
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP |
+ 0x1,12,178,232,8
+ LTEXT "",IDC_STSIMPLERIGHT,200,104,8,32,NOT WS_VISIBLE
+END
+
+IDD_OPT_IGNORE DIALOGEX 0, 0, 313, 240
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The following events are being ignored:",IDC_STATIC,8,
+ 14,297,8
+ ICON IDI_RECVMSG,IDC_MSGICON,8,172,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore messages",IDC_STATIC,26,178,70,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_URL,IDC_URLICON,8,187,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore URLs",IDC_STATIC,26,193,70,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_FILE,IDC_FILEICON,8,202,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore files",IDC_STATIC,26,208,70,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_MIRANDA,IDC_AUTHICON,96,172,20,20,SS_CENTERIMAGE
+ LTEXT "Suppress auth requests",IDC_STATIC,114,178,107,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_USERONLINE,IDC_ONLINEICON,96,187,20,20,
+ SS_CENTERIMAGE
+ LTEXT "Suppress online notification",IDC_STATIC,114,193,107,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_FILLEDBLOB,IDC_ALLICON,221,172,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore all",IDC_STATIC,239,178,66,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_EMPTYBLOB,IDC_NONEICON,221,187,20,20,SS_CENTERIMAGE
+ LTEXT "Ignore none",IDC_STATIC,239,193,66,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ CTEXT "Only the ticked contacts will be shown on the main contact list",
+ IDC_STCHECKMARKS,8,227,297,8
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x3da,8,26,297,
+ 146,WS_EX_CLIENTEDGE
+ GROUPBOX "Ignore",IDC_STATIC,0,0,313,240
+ ICON IDI_ADDCONTACT,IDC_ADDED,96,202,20,20,SS_CENTERIMAGE
+ LTEXT "Suppress added notification",IDC_STATIC,114,208,107,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_OPT_VISIBILITY DIALOGEX 0, 0, 313, 240
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ ICON IDI_ONLINE,IDC_VISIBLEICON,8,203,12,12,SS_CENTERIMAGE
+ LTEXT "You are visible to this person even when in invisible mode",
+ IDC_STATIC,26,205,279,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_INVISIBLE,IDC_INVISIBLEICON,8,218,12,12,
+ SS_CENTERIMAGE
+ LTEXT "You are never visible to this person",IDC_STATIC,26,220,
+ 279,8,SS_NOPREFIX | SS_CENTERIMAGE
+ GROUPBOX "Visibility",IDC_STATIC,0,0,313,240
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x1d0,8,14,297,
+ 183,WS_EX_CLIENTEDGE
+END
+
+IDD_OPT_AWAYMSG DIALOGEX 0, 0, 263, 151
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Status Messages",IDC_STATIC,4,5,255,142
+ COMBOBOX IDC_STATUS,12,19,240,97,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Do not reply to requests for this message",
+ IDC_DONTREPLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,
+ 37,227,10
+ CONTROL "Do not pop up dialog asking for new message",
+ IDC_NODIALOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,50,
+ 227,10
+ CONTROL "By default, use the same message as last time",
+ IDC_USEPREVIOUS,"Button",BS_AUTORADIOBUTTON,23,65,227,10
+ CONTROL "By default, use this message:",IDC_USESPECIFIC,"Button",
+ BS_AUTORADIOBUTTON,23,78,227,10
+ EDITTEXT IDC_MSG,33,91,219,38,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_WANTRETURN | WS_VSCROLL
+ LTEXT "Use %time% for the current time, %date% for the current date",
+ IDC_STATIC,33,131,219,8
+END
+
+IDD_ICONINDEX DIALOGEX 0, 0, 219, 197
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Icon Index"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ RTEXT "Icon library:",IDC_STATIC,4,6,54,8
+ EDITTEXT IDC_ICONSET,60,4,139,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSE,201,5,14,10
+ LTEXT "Drag icons to main list to assign them:",IDC_STATIC,4,
+ 18,211,8
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL |
+ LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,4,27,211,82
+ GROUPBOX "Import multiple",IDC_IMPORTMULTI,4,122,211,61
+ CONTROL "To main icons",IDC_TOMAIN,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,8,132,74,12
+ CONTROL "To",IDC_TOPROTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,
+ 165,25,12
+ COMBOBOX IDC_PROTOLIST,34,164,79,58,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "<< &Import",IDC_IMPORT,164,164,48,14,WS_DISABLED
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP |
+ 0x1,4,185,211,8
+ CONTROL "To default status icons",IDC_TODEFICON,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8,148,123,12
+END
+
+IDD_OPT_NETLIB DIALOGEX 0, 0, 313, 238
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Incoming connections",IDC_STATIC43,0,173,313,51
+ COMBOBOX IDC_NETLIBUSERS,0,1,231,110,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Log Options...",IDC_LOGOPTIONS,258,1,55,13
+ CONTROL "Use proxy server",IDC_USEPROXY,"Button",BS_3STATE |
+ WS_TABSTOP,7,29,90,9
+ LTEXT "Proxy type:",IDC_STATIC21,19,43,57,8,WS_DISABLED
+ COMBOBOX IDC_PROXYTYPE,80,40,86,62,CBS_DROPDOWNLIST | WS_DISABLED |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Proxy server:",IDC_STATIC22,19,58,57,8,WS_DISABLED
+ EDITTEXT IDC_PROXYHOST,80,56,86,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Port:",IDC_STATIC23,177,58,35,8,WS_DISABLED
+ EDITTEXT IDC_PROXYPORT,213,56,35,12,ES_AUTOHSCROLL | ES_NUMBER |
+ WS_DISABLED
+ LTEXT "(often %d)",IDC_STOFTENPORT,258,57,48,8,WS_DISABLED
+ CONTROL "Proxy requires authorization",IDC_PROXYAUTH,"Button",
+ BS_3STATE | WS_DISABLED | WS_TABSTOP,20,73,154,10
+ LTEXT "Username:",IDC_STATIC31,32,87,47,8,WS_DISABLED
+ EDITTEXT IDC_PROXYUSER,80,85,86,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Password:",IDC_STATIC32,177,87,49,8,WS_DISABLED
+ EDITTEXT IDC_PROXYPASS,232,83,74,12,ES_PASSWORD | ES_AUTOHSCROLL |
+ WS_DISABLED
+ CONTROL "Resolve hostnames through proxy",IDC_PROXYDNS,"Button",
+ BS_3STATE | WS_DISABLED | WS_TABSTOP,20,115,154,10
+ CONTROL "Specify ports to be used for incoming connections",
+ IDC_SPECIFYPORTS,"Button",BS_3STATE | BS_TOP |
+ BS_MULTILINE | WS_TABSTOP,7,185,186,9
+ LTEXT "Range:",IDC_STATIC51,19,199,58,8,WS_DISABLED
+ EDITTEXT IDC_PORTSRANGE,80,197,142,12,ES_AUTOHSCROLL |
+ WS_DISABLED
+ LTEXT "Example: 1050-1070, 2000-2010, 2500",IDC_STATIC52,80,
+ 212,196,8,WS_DISABLED
+ CTEXT "You will need to reconnect for the changes you have made on this page to take effect.",
+ IDC_RECONNECTREQD,7,227,307,8,NOT WS_VISIBLE
+ CONTROL "Use NTLM authentication",IDC_PROXYAUTHNTLM,"Button",
+ BS_3STATE | WS_DISABLED | WS_TABSTOP,32,101,154,10
+ GROUPBOX "Outgoing connections",IDC_STATIC12,0,18,313,151
+ CONTROL "Specify ports to be used for outgoing connections",
+ IDC_SPECIFYPORTSO,"Button",BS_3STATE | BS_TOP |
+ BS_MULTILINE | WS_TABSTOP,7,130,186,9
+ LTEXT "Range:",IDC_STATIC53,19,144,58,8,WS_DISABLED
+ EDITTEXT IDC_PORTSRANGEO,80,142,142,12,ES_AUTOHSCROLL |
+ WS_DISABLED
+ LTEXT "Example: 1050-1070, 2000-2010, 2500",IDC_STATIC54,80,
+ 157,196,8,WS_DISABLED
+END
+
+IDD_OPT_FILETRANSFER DIALOGEX 0, 0, 313, 228
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Receiving files",IDC_STATIC,0,0,313,80
+ LTEXT "Received files folder:",IDC_STATIC,8,15,82,8
+ EDITTEXT IDC_FILEDIR,92,13,190,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FILEDIRBROWSE,287,14,15,11
+ CONTROL "Auto-accept incoming files from people on my contact list",
+ IDC_AUTOACCEPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,
+ 39,294,10
+ CONTROL "Minimize the file transfer window",IDC_AUTOMIN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,17,52,285,10
+ CONTROL "Close window when transfer completes",IDC_AUTOCLOSE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,65,294,10
+ GROUPBOX "Virus scanner",IDC_VIRUSSCANNERGROUP,0,85,313,93
+ LTEXT "Scan files:",IDC_STATIC,8,97,43,9,SS_CENTERIMAGE
+ CONTROL "Never, do not use virus scanning",IDC_NOSCANNER,"Button",
+ BS_AUTORADIOBUTTON,52,97,250,10
+ CONTROL "When all files have been downloaded",IDC_SCANAFTERDL,
+ "Button",BS_AUTORADIOBUTTON,52,109,250,10
+ CONTROL "As each file finishes downloading",IDC_SCANDURINGDL,
+ "Button",BS_AUTORADIOBUTTON,52,121,250,10
+ LTEXT "Command line:",IDC_ST_CMDLINE,7,137,62,8
+ COMBOBOX IDC_SCANCMDLINE,70,136,213,71,CBS_DROPDOWN |
+ CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_SCANCMDLINEBROWSE,287,137,15,11
+ LTEXT "%f will be replaced by the file or folder name to be scanned",
+ IDC_ST_CMDLINEHELP,70,150,232,8
+ CONTROL "Warn me before opening a file that has not been scanned",
+ IDC_WARNBEFOREOPENING,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,8,163,294,10
+ GROUPBOX "If incoming files already exist",IDC_STATIC,0,183,313,
+ 43
+ CONTROL "Ask me",IDC_ASK,"Button",BS_AUTORADIOBUTTON,8,197,73,10
+ CONTROL "Resume",IDC_RESUME,"Button",BS_AUTORADIOBUTTON,82,197,
+ 125,10
+ CONTROL "Overwrite",IDC_OVERWRITE,"Button",BS_AUTORADIOBUTTON,8,
+ 209,73,10
+ CONTROL "Rename (append "" (1)"", etc.)",IDC_RENAME,"Button",
+ BS_AUTORADIOBUTTON,82,209,125,10
+ LTEXT "You will always be asked about files from people not on your contact list",
+ IDC_STATIC,212,195,90,24
+ LTEXT "Variables Allowed: %userid%, %nick%, %proto%",
+ IDC_STATIC,93,27,167,11,WS_DISABLED
+END
+
+IDD_OPT_IDLE DIALOGEX 0, 0, 312, 172
+STYLE DS_FIXEDSYS | WS_CHILD | WS_BORDER
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Become idle if the following is left unattended:",
+ IDC_IDLESHORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,
+ 18,259,9
+ CONTROL "Windows",IDC_IDLEONWINDOWS,"Button",BS_AUTORADIOBUTTON,
+ 45,31,104,9
+ CONTROL "Miranda",IDC_IDLEONMIRANDA,"Button",BS_AUTORADIOBUTTON,
+ 45,43,103,9
+ EDITTEXT IDC_IDLE1STTIME,59,59,27,14,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin2",IDC_IDLESPIN,"msctls_updown32",UDS_WRAP |
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS |
+ UDS_NOTHOUSANDS | UDS_HOTTRACK,71,55,12,23
+ CONTROL "Become idle if the screen saver is active",
+ IDC_SCREENSAVER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,
+ 83,268,9
+ CONTROL "Become idle if the computer is locked (2000/XP+ only)",
+ IDC_LOCKED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,99,
+ 249,9
+ CONTROL "Do not let protocols report any idle information",
+ IDC_IDLEPRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,
+ 115,251,9
+ LTEXT "minute(s)",IDC_STATIC,91,61,76,9
+ RTEXT "for",IDC_STATIC,12,59,41,9
+ COMBOBOX IDC_AASTATUS,128,130,64,50,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Change my status mode to:",IDC_AASHORTIDLE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,25,131,101,11
+ CONTROL "Do not set status back to online when returning from idle",
+ IDC_IDLESTATUSLOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 35,148,246,10
+ GROUPBOX "Idle Options",IDC_STATIC,3,3,304,165
+END
+
+IDD_PROFILE_SELECTION DIALOGEX 0, 0, 386, 142
+STYLE DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_PROFILELIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER |
+ WS_TABSTOP,3,2,382,137
+END
+
+IDD_PROFILE_NEW DIALOGEX 0, 0, 386, 142
+STYLE DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Please complete the following form to create a new user profile",
+ IDC_STATIC,7,7,372,10
+ EDITTEXT IDC_PROFILENAME,49,27,75,12,ES_AUTOHSCROLL
+ COMBOBOX IDC_PROFILEDRIVERS,49,72,75,56,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Profile",IDC_STATIC,20,28,26,9
+ LTEXT "e.g. Workplace",IDC_STATIC,131,28,77,11
+ LTEXT "You can select a different profile driver from the default, it may offer more features or abilities, if in doubt use the default.",
+ IDC_STATIC,7,49,372,17
+ LTEXT "e.g. Miranda Database",IDC_STATIC,131,73,84,11
+ LTEXT "Driver",IDC_STATIC,20,74,23,9
+ LTEXT "Problem: Unable to find any database drivers, this means you can not create a new profile, you need to get dbx_3x.dll",
+ IDC_NODBDRIVERS,7,113,372,22,NOT WS_VISIBLE
+END
+
+IDD_OPT_PLUGINS DIALOGEX 0, 0, 315, 247
+STYLE DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_PLUGLIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING |
+ LVS_AUTOARRANGE | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,4,0,306,145
+ EDITTEXT IDC_PLUGINLONGINFO,50,159,253,19,ES_MULTILINE |
+ ES_READONLY | ES_WANTRETURN | NOT WS_BORDER | WS_VSCROLL
+ GROUPBOX "",IDC_PLUGININFOFRAME,4,148,307,80,BS_RIGHT
+ EDITTEXT IDC_PLUGINAUTHOR,50,178,253,12,ES_READONLY |
+ ES_WANTRETURN | NOT WS_BORDER
+ EDITTEXT IDC_PLUGINCPYR,50,190,249,12,ES_AUTOHSCROLL |
+ ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ CONTROL "",IDC_PLUGINURL,"Hyperlink",WS_TABSTOP,50,213,254,10
+ CONTROL "",IDC_PLUGINEMAIL,"Hyperlink",WS_TABSTOP,50,201,208,10
+ RTEXT "Description:",IDC_STATIC,8,158,38,10
+ RTEXT "Author(s):",IDC_STATIC,8,177,38,9
+ RTEXT "Copyright:",IDC_STATIC,8,190,38,9
+ RTEXT "E-mail:",IDC_STATIC,8,202,38,8
+ RTEXT "Homepage:",IDC_STATIC,7,213,38,8
+ CTEXT "Please restart Miranda IM for your changes to take effect.",
+ IDC_RESTART,5,233,305,11,NOT WS_VISIBLE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO MOVEABLE PURE
+BEGIN
+ IDD_AUTHREQ, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 235
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 102
+ END
+
+ IDD_DENYREASON, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 165
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 63
+ END
+
+ IDD_ADDCONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 144
+ END
+
+ IDD_ADDED, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 217
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 52
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 207
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 126
+ END
+
+ IDD_DELETECONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 277
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ END
+
+ IDD_OPT_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 192
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 137
+ END
+
+ IDD_FINDADD, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 422
+ VERTGUIDE, 11
+ VERTGUIDE, 42
+ VERTGUIDE, 53
+ VERTGUIDE, 116
+ VERTGUIDE, 122
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 227
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 424
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 267
+ END
+
+ IDD_READAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_SETAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_DETAILS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 233
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 205
+ END
+
+ IDD_INFO_SUMMARY, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 51
+ VERTGUIDE, 126
+ VERTGUIDE, 170
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 22
+ HORZGUIDE, 35
+ HORZGUIDE, 48
+ HORZGUIDE, 62
+ END
+
+ IDD_INFO_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_BACKGROUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 49
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_NOTES, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_LOCATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 56
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 22
+ HORZGUIDE, 33
+ HORZGUIDE, 45
+ HORZGUIDE, 56
+ HORZGUIDE, 70
+ HORZGUIDE, 95
+ HORZGUIDE, 106
+ END
+
+ IDD_INFO_WORK, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 56
+ VERTGUIDE, 126
+ VERTGUIDE, 170
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 16
+ HORZGUIDE, 27
+ HORZGUIDE, 44
+ HORZGUIDE, 61
+ HORZGUIDE, 72
+ HORZGUIDE, 83
+ HORZGUIDE, 94
+ HORZGUIDE, 105
+ END
+
+ IDD_ADDEMAIL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 37
+ END
+
+ IDD_ADDPHONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 205
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 86
+ END
+
+ IDD_INSTALLINI, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 208
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 98
+ END
+
+ IDD_WARNINICHANGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 108
+ END
+
+ IDD_INIIMPORTDONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 181
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 68
+ END
+
+ IDD_NETLIBLOGOPTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 255
+ VERTGUIDE, 13
+ VERTGUIDE, 148
+ VERTGUIDE, 247
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 196
+ END
+
+ IDD_HISTORY_FIND, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 39
+ HORZGUIDE, 17
+ END
+
+ IDD_FILESEND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 251
+ VERTGUIDE, 7
+ VERTGUIDE, 249
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 172
+ END
+
+ IDD_FILERECV, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 249
+ VERTGUIDE, 7
+ VERTGUIDE, 249
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 169
+ END
+
+ IDD_FILETRANSFERINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 251
+ VERTGUIDE, 11
+ VERTGUIDE, 69
+ VERTGUIDE, 245
+ BOTTOMMARGIN, 150
+ END
+
+ IDD_FILEEXISTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 283
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_URLSEND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 210
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 121
+ END
+
+ IDD_URLRECV, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 210
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_HISTORY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 289
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 158
+ END
+
+ IDD_OPT_SOUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 281
+ VERTGUIDE, 12
+ VERTGUIDE, 273
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 236
+ END
+
+ IDD_OPT_ICONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 253
+ VERTGUIDE, 12
+ VERTGUIDE, 200
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 189
+ END
+
+ IDD_OPT_IGNORE, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 96
+ VERTGUIDE, 221
+ VERTGUIDE, 305
+ END
+
+ IDD_OPT_VISIBILITY, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 305
+ END
+
+ IDD_OPT_AWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 259
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_ICONINDEX, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 215
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 193
+ END
+
+ IDD_OPT_NETLIB, DIALOG
+ BEGIN
+ VERTGUIDE, 7
+ VERTGUIDE, 20
+ VERTGUIDE, 80
+ VERTGUIDE, 166
+ VERTGUIDE, 177
+ VERTGUIDE, 306
+ BOTTOMMARGIN, 235
+ HORZGUIDE, 80
+ HORZGUIDE, 113
+ END
+
+ IDD_OPT_FILETRANSFER, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 302
+ END
+
+ IDD_PROFILE_SELECTION, DIALOG
+ BEGIN
+ RIGHTMARGIN, 225
+ BOTTOMMARGIN, 141
+ END
+
+ IDD_PROFILE_NEW, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 219
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_OPT_PLUGINS, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 235
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "#include <windows.h>\r\n"
+ "#include <winres.h>\r\n"
+ "#include ""../include/statusmodes.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MIRANDA ICON DISCARDABLE "res\\miranda.ico"
+IDI_SEARCHALL ICON DISCARDABLE "res\\searchal.ico"
+IDI_SMS ICON DISCARDABLE "res\\sms.ico"
+IDI_BLANK ICON DISCARDABLE "res\\blank.ico"
+IDI_NOTICK ICON DISCARDABLE "res\\notick.ico"
+IDI_TICK ICON DISCARDABLE "res\\notick1.ico"
+IDI_FILE ICON DISCARDABLE "res\\file.ico"
+IDI_TIMESTAMP ICON DISCARDABLE "res\\timestamp.ico"
+IDI_CHANGEFONT ICON DISCARDABLE "res\\changefont.ico"
+IDI_ADDCONTACT ICON DISCARDABLE "res\\addcontact.ico"
+IDI_USERDETAILS ICON DISCARDABLE "res\\viewdetails.ico"
+IDI_SMALLDOT ICON DISCARDABLE "res\\smalldot.ico"
+IDI_FILLEDBLOB ICON DISCARDABLE "res\\filledbl.ico"
+IDI_EMPTYBLOB ICON DISCARDABLE "res\\emptyblo.ico"
+IDI_DETAILSLOGO ICON DISCARDABLE "res\\detailsl.ico"
+IDI_RECVMSG ICON DISCARDABLE "res\\message.ico"
+IDI_SENDMSG ICON DISCARDABLE "res\\reply.ico"
+IDI_URL ICON DISCARDABLE "res\\url.ico"
+IDI_NA ICON DISCARDABLE "res\\na2.ico"
+IDI_AWAY ICON DISCARDABLE "res\\away.ico"
+IDI_FREE4CHAT ICON DISCARDABLE "res\\freechat.ico"
+IDI_ONLINE ICON DISCARDABLE "res\\online2.ico"
+IDI_OFFLINE ICON DISCARDABLE "res\\offline2.ico"
+IDI_DND ICON DISCARDABLE "res\\dnd.ico"
+IDI_OCCUPIED ICON DISCARDABLE "res\\occupied.ico"
+IDI_FINDUSER ICON DISCARDABLE "res\\finduser.ico"
+IDI_HELP ICON DISCARDABLE "res\\help.ico"
+IDI_OPTIONS ICON DISCARDABLE "res\\options.ico"
+IDI_MIRANDAWEBSITE ICON DISCARDABLE "res\\mirandaw.ico"
+IDI_RENAME ICON DISCARDABLE "res\\rename.ico"
+IDI_HISTORY ICON DISCARDABLE "res\\history.ico"
+IDI_DELETE ICON DISCARDABLE "res\\delete.ico"
+IDI_SENDEMAIL ICON DISCARDABLE "res\\sendmail.ico"
+IDI_USERONLINE ICON DISCARDABLE "res\\useronli.ico"
+IDI_GROUPSHUT ICON DISCARDABLE "res\\groupshu.ico"
+IDI_GROUPOPEN ICON DISCARDABLE "res\\groupope.ico"
+IDI_ONTHEPHONE ICON DISCARDABLE "res\\onthepho.ico"
+IDI_OUTTOLUNCH ICON DISCARDABLE "res\\outtolun.ico"
+IDI_INVISIBLE ICON DISCARDABLE "res\\invisible.ico"
+IDI_MULTISEND ICON DISCARDABLE "res\\multisend.ico"
+IDI_DOWNARROW ICON DISCARDABLE "res\\downarrow.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_HYPERLINKHAND CURSOR DISCARDABLE "res\\hyperlin.cur"
+IDC_DROP CURSOR DISCARDABLE "res\\dragcopy.cur"
+IDC_DROPUSER CURSOR DISCARDABLE "res\\dropuser.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CLISTMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&¤"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_ICQ_EXIT
+ END
+ POPUP "&Status"
+ BEGIN
+ MENUITEM "&Offline\tCtrl+0", ID_STATUS_OFFLINE, CHECKED
+ MENUITEM "On&line\tCtrl+1", ID_STATUS_ONLINE
+ MENUITEM "&Away\tCtrl+2", ID_STATUS_AWAY
+ MENUITEM "&NA\tCtrl+3", ID_STATUS_NA
+ MENUITEM "Occ&upied\tCtrl+4", ID_STATUS_OCCUPIED
+ MENUITEM "&DND\tCtrl+5", ID_STATUS_DND
+ MENUITEM "&Free for chat\tCtrl+6", ID_STATUS_FREECHAT
+ MENUITEM "&Invisible\tCtrl+7", ID_STATUS_INVISIBLE
+ MENUITEM "On the &Phone\tCtrl+8", ID_STATUS_ONTHEPHONE
+ MENUITEM "Out to &Lunch\tCtrl+9", ID_STATUS_OUTTOLUNCH
+ END
+END
+
+IDR_CONTEXT MENU DISCARDABLE
+BEGIN
+ POPUP "Tray"
+ BEGIN
+ MENUITEM "&Hide/Show", ID_TRAY_HIDE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_TRAY_EXIT
+ END
+ POPUP "Nowhere"
+ BEGIN
+ MENUITEM "&New Group", POPUP_NEWGROUP
+ MENUITEM SEPARATOR
+ MENUITEM "&Hide Offline Users", POPUP_HIDEOFFLINE
+ MENUITEM "Hide &Offline Users out here", POPUP_HIDEOFFLINEROOT
+ MENUITEM "Hide &Empty Groups", POPUP_HIDEEMPTYGROUPS
+ MENUITEM "Disable &Groups", POPUP_DISABLEGROUPS
+ MENUITEM SEPARATOR
+ MENUITEM "Hide Miranda", POPUP_HIDEMIRANDA
+ END
+ POPUP "Group"
+ BEGIN
+ MENUITEM "&New Subgroup", POPUP_NEWSUBGROUP
+ MENUITEM "&Hide Offline Users in here", POPUP_GROUPHIDEOFFLINE
+ MENUITEM SEPARATOR
+ MENUITEM "&Rename Group", POPUP_RENAMEGROUP
+ MENUITEM "&Delete Group", POPUP_DELETEGROUP
+ END
+ POPUP "IconOptions"
+ BEGIN
+ MENUITEM "&Reset to default", ID_RESET
+ END
+ POPUP "find/add"
+ BEGIN
+ MENUITEM "&Add to List", IDC_ADD
+ MENUITEM SEPARATOR
+ MENUITEM "User &Details", IDC_DETAILS
+ MENUITEM "Send &Message", IDC_SENDMESSAGE
+ END
+ POPUP "Log"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "Co&py All", IDM_COPYALL
+ MENUITEM "Select &All", IDM_SELECTALL
+ MENUITEM SEPARATOR
+ MENUITEM "C&lear Log", IDM_CLEAR
+ END
+ POPUP "LogLink"
+ BEGIN
+ MENUITEM "Open in &new window", IDM_OPENNEW
+ MENUITEM "&Open in existing window", IDM_OPENEXISTING
+ MENUITEM "&Copy link", IDM_COPYLINK
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXT
+//
+
+IDR_CREDITS TEXT MOVEABLE PURE "..\\docs\\credits.txt"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_SORTCOLUP BITMAP MOVEABLE PURE "res\\sortcolu.bmp"
+IDB_SORTCOLDOWN BITMAP MOVEABLE PURE "res\\sortcold.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+1 RT_MANIFEST MOVEABLE PURE "miranda32.exe.manifest"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc"
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/src/version.rc b/miranda-wine/src/version.rc new file mode 100644 index 0000000..78083f2 --- /dev/null +++ b/miranda-wine/src/version.rc @@ -0,0 +1,45 @@ +#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,6,0,6
+ PRODUCTVERSION 0,6,0,6
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "Licensed under the terms of the GNU General Public License\0"
+ VALUE "CompanyName", " \0"
+ VALUE "FileDescription", "Miranda IM\0"
+ VALUE "FileVersion", "0.6 alpha build #6\0"
+ VALUE "InternalName", "miranda32\0"
+ VALUE "LegalCopyright", "Copyright © 2000-2006 Miranda IM Project. This software is released under the terms of the GNU General Public License.\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "miranda32.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Miranda IM\0"
+ VALUE "ProductVersion", "0.6 alpha build #6\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#endif // !_MAC
+
|