From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- miranda-wine/src/core/commonheaders.c | 2 + miranda-wine/src/core/commonheaders.h | 84 + miranda-wine/src/core/forkthread.h | 64 + miranda-wine/src/core/memory.c | 167 ++ miranda-wine/src/core/miranda.c | 565 +++++++ miranda-wine/src/core/miranda.h | 48 + miranda-wine/src/core/modules.c | 656 ++++++++ miranda-wine/src/core/modules.h | 184 ++ miranda-wine/src/modules/addcontact/addcontact.c | 235 +++ miranda-wine/src/modules/autoaway/autoaway.c | 82 + miranda-wine/src/modules/button/button.c | 540 ++++++ miranda-wine/src/modules/clist/Docking.c | 293 ++++ miranda-wine/src/modules/clist/clc.c | 1321 +++++++++++++++ miranda-wine/src/modules/clist/clc.h | 154 ++ miranda-wine/src/modules/clist/clcfiledrop.c | 295 ++++ miranda-wine/src/modules/clist/clcidents.c | 201 +++ miranda-wine/src/modules/clist/clcitems.c | 721 ++++++++ miranda-wine/src/modules/clist/clcmsgs.c | 462 +++++ miranda-wine/src/modules/clist/clcutils.c | 865 ++++++++++ miranda-wine/src/modules/clist/clistcore.c | 315 ++++ miranda-wine/src/modules/clist/clistevents.c | 308 ++++ miranda-wine/src/modules/clist/clistmod.c | 526 ++++++ miranda-wine/src/modules/clist/clistsettings.c | 380 +++++ miranda-wine/src/modules/clist/clisttray.c | 632 +++++++ miranda-wine/src/modules/clist/clui.c | 1042 ++++++++++++ miranda-wine/src/modules/clist/cluiservices.c | 239 +++ miranda-wine/src/modules/clist/contact.c | 185 ++ miranda-wine/src/modules/clist/groups.c | 514 ++++++ miranda-wine/src/modules/clist/keyboard.c | 135 ++ miranda-wine/src/modules/contacts/contacts.c | 478 ++++++ miranda-wine/src/modules/database/database.c | 377 +++++ miranda-wine/src/modules/database/dbini.c | 495 ++++++ miranda-wine/src/modules/database/dblists.c | 149 ++ miranda-wine/src/modules/database/dblists.h | 36 + miranda-wine/src/modules/database/dbtime.c | 239 +++ miranda-wine/src/modules/database/profilemanager.c | 696 ++++++++ miranda-wine/src/modules/database/profilemanager.h | 37 + miranda-wine/src/modules/findadd/findadd.c | 902 ++++++++++ miranda-wine/src/modules/findadd/findadd.h | 57 + miranda-wine/src/modules/findadd/searchresults.c | 424 +++++ miranda-wine/src/modules/help/about.c | 143 ++ miranda-wine/src/modules/help/help.c | 104 ++ miranda-wine/src/modules/history/history.c | 434 +++++ miranda-wine/src/modules/idle/idle.c | 415 +++++ miranda-wine/src/modules/ignore/ignore.c | 449 +++++ miranda-wine/src/modules/langpack/langpack.c | 362 ++++ miranda-wine/src/modules/langpack/lpservices.c | 128 ++ miranda-wine/src/modules/netlib/netlib.c | 503 ++++++ miranda-wine/src/modules/netlib/netlib.h | 157 ++ miranda-wine/src/modules/netlib/netlibbind.c | 247 +++ miranda-wine/src/modules/netlib/netlibhttp.c | 729 ++++++++ miranda-wine/src/modules/netlib/netlibhttpproxy.c | 610 +++++++ miranda-wine/src/modules/netlib/netliblog.c | 440 +++++ miranda-wine/src/modules/netlib/netlibopenconn.c | 569 +++++++ miranda-wine/src/modules/netlib/netlibopts.c | 516 ++++++ miranda-wine/src/modules/netlib/netlibpktrecver.c | 85 + miranda-wine/src/modules/netlib/netlibsock.c | 166 ++ miranda-wine/src/modules/netlib/netlibupnp.c | 495 ++++++ miranda-wine/src/modules/options/options.c | 664 ++++++++ miranda-wine/src/modules/plugins/newplugins.c | 815 +++++++++ miranda-wine/src/modules/protocols/protochains.c | 225 +++ miranda-wine/src/modules/protocols/protocols.c | 134 ++ miranda-wine/src/modules/protocols/protodir.c | 248 +++ miranda-wine/src/modules/skin/skin.c | 77 + miranda-wine/src/modules/skin/skinicons.c | 1044 ++++++++++++ miranda-wine/src/modules/skin/sounds.c | 403 +++++ miranda-wine/src/modules/srauth/auth.c | 97 ++ miranda-wine/src/modules/srauth/authdialogs.c | 269 +++ miranda-wine/src/modules/srawaymsg/awaymsg.c | 161 ++ miranda-wine/src/modules/srawaymsg/sendmsg.c | 414 +++++ miranda-wine/src/modules/sremail/email.c | 92 + miranda-wine/src/modules/srfile/file.c | 287 ++++ miranda-wine/src/modules/srfile/file.h | 88 + miranda-wine/src/modules/srfile/fileexistsdlg.c | 331 ++++ miranda-wine/src/modules/srfile/fileopts.c | 227 +++ miranda-wine/src/modules/srfile/filerecvdlg.c | 431 +++++ miranda-wine/src/modules/srfile/filesenddlg.c | 380 +++++ miranda-wine/src/modules/srfile/filexferdlg.c | 562 +++++++ miranda-wine/src/modules/srurl/url.c | 203 +++ miranda-wine/src/modules/srurl/url.h | 43 + miranda-wine/src/modules/srurl/urldialogs.c | 737 ++++++++ miranda-wine/src/modules/userinfo/contactinfo.c | 503 ++++++ miranda-wine/src/modules/userinfo/stdinfo.c | 541 ++++++ miranda-wine/src/modules/userinfo/userinfo.c | 500 ++++++ miranda-wine/src/modules/useronline/useronline.c | 96 ++ miranda-wine/src/modules/utils/bmpfilter.c | 180 ++ miranda-wine/src/modules/utils/colourpicker.c | 107 ++ miranda-wine/src/modules/utils/hyperlink.c | 183 ++ miranda-wine/src/modules/utils/openurl.c | 228 +++ miranda-wine/src/modules/utils/path.c | 83 + miranda-wine/src/modules/utils/resizer.c | 152 ++ miranda-wine/src/modules/utils/utf.c | 165 ++ miranda-wine/src/modules/utils/utils.c | 364 ++++ miranda-wine/src/modules/utils/windowlist.c | 107 ++ miranda-wine/src/modules/visibility/visibility.c | 297 ++++ miranda-wine/src/res/addcontact.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/away.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/blank.ico | Bin 0 -> 318 bytes miranda-wine/src/res/changefont.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/delete.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/detailsl.ico | Bin 0 -> 6518 bytes miranda-wine/src/res/dnd.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/downarrow.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/dragcopy.cur | Bin 0 -> 326 bytes miranda-wine/src/res/dropuser.cur | Bin 0 -> 1086 bytes miranda-wine/src/res/emptyblo.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/file.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/filledbl.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/finduser.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/freechat.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/groupope.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/groupshu.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/help.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/history.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/hyperlin.cur | Bin 0 -> 326 bytes miranda-wine/src/res/invisible.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/message.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/miranda.ico | Bin 0 -> 22486 bytes miranda-wine/src/res/mirandaw.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/multisend.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/na2.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/notick.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/notick1.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/occupied.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/offline2.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/online2.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/onthepho.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/options.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/outtolun.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/rename.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/reply.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/searchal.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/sendmail.ico | Bin 0 -> 1406 bytes miranda-wine/src/res/smalldot.ico | Bin 0 -> 318 bytes miranda-wine/src/res/sms.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/sortcold.bmp | Bin 0 -> 150 bytes miranda-wine/src/res/sortcolu.bmp | Bin 0 -> 150 bytes miranda-wine/src/res/timestamp.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/url.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/useronli.ico | Bin 0 -> 2550 bytes miranda-wine/src/res/viewdetails.ico | Bin 0 -> 2550 bytes miranda-wine/src/resource.h | 392 +++++ miranda-wine/src/resource.rc | 1765 ++++++++++++++++++++ miranda-wine/src/version.rc | 45 + 144 files changed, 35297 insertions(+) create mode 100644 miranda-wine/src/core/commonheaders.c create mode 100644 miranda-wine/src/core/commonheaders.h create mode 100644 miranda-wine/src/core/forkthread.h create mode 100644 miranda-wine/src/core/memory.c create mode 100644 miranda-wine/src/core/miranda.c create mode 100644 miranda-wine/src/core/miranda.h create mode 100644 miranda-wine/src/core/modules.c create mode 100644 miranda-wine/src/core/modules.h create mode 100644 miranda-wine/src/modules/addcontact/addcontact.c create mode 100644 miranda-wine/src/modules/autoaway/autoaway.c create mode 100644 miranda-wine/src/modules/button/button.c create mode 100644 miranda-wine/src/modules/clist/Docking.c create mode 100644 miranda-wine/src/modules/clist/clc.c create mode 100644 miranda-wine/src/modules/clist/clc.h create mode 100644 miranda-wine/src/modules/clist/clcfiledrop.c create mode 100644 miranda-wine/src/modules/clist/clcidents.c create mode 100644 miranda-wine/src/modules/clist/clcitems.c create mode 100644 miranda-wine/src/modules/clist/clcmsgs.c create mode 100644 miranda-wine/src/modules/clist/clcutils.c create mode 100644 miranda-wine/src/modules/clist/clistcore.c create mode 100644 miranda-wine/src/modules/clist/clistevents.c create mode 100644 miranda-wine/src/modules/clist/clistmod.c create mode 100644 miranda-wine/src/modules/clist/clistsettings.c create mode 100644 miranda-wine/src/modules/clist/clisttray.c create mode 100644 miranda-wine/src/modules/clist/clui.c create mode 100644 miranda-wine/src/modules/clist/cluiservices.c create mode 100644 miranda-wine/src/modules/clist/contact.c create mode 100644 miranda-wine/src/modules/clist/groups.c create mode 100644 miranda-wine/src/modules/clist/keyboard.c create mode 100644 miranda-wine/src/modules/contacts/contacts.c create mode 100644 miranda-wine/src/modules/database/database.c create mode 100644 miranda-wine/src/modules/database/dbini.c create mode 100644 miranda-wine/src/modules/database/dblists.c create mode 100644 miranda-wine/src/modules/database/dblists.h create mode 100644 miranda-wine/src/modules/database/dbtime.c create mode 100644 miranda-wine/src/modules/database/profilemanager.c create mode 100644 miranda-wine/src/modules/database/profilemanager.h create mode 100644 miranda-wine/src/modules/findadd/findadd.c create mode 100644 miranda-wine/src/modules/findadd/findadd.h create mode 100644 miranda-wine/src/modules/findadd/searchresults.c create mode 100644 miranda-wine/src/modules/help/about.c create mode 100644 miranda-wine/src/modules/help/help.c create mode 100644 miranda-wine/src/modules/history/history.c create mode 100644 miranda-wine/src/modules/idle/idle.c create mode 100644 miranda-wine/src/modules/ignore/ignore.c create mode 100644 miranda-wine/src/modules/langpack/langpack.c create mode 100644 miranda-wine/src/modules/langpack/lpservices.c create mode 100644 miranda-wine/src/modules/netlib/netlib.c create mode 100644 miranda-wine/src/modules/netlib/netlib.h create mode 100644 miranda-wine/src/modules/netlib/netlibbind.c create mode 100644 miranda-wine/src/modules/netlib/netlibhttp.c create mode 100644 miranda-wine/src/modules/netlib/netlibhttpproxy.c create mode 100644 miranda-wine/src/modules/netlib/netliblog.c create mode 100644 miranda-wine/src/modules/netlib/netlibopenconn.c create mode 100644 miranda-wine/src/modules/netlib/netlibopts.c create mode 100644 miranda-wine/src/modules/netlib/netlibpktrecver.c create mode 100644 miranda-wine/src/modules/netlib/netlibsock.c create mode 100644 miranda-wine/src/modules/netlib/netlibupnp.c create mode 100644 miranda-wine/src/modules/options/options.c create mode 100644 miranda-wine/src/modules/plugins/newplugins.c create mode 100644 miranda-wine/src/modules/protocols/protochains.c create mode 100644 miranda-wine/src/modules/protocols/protocols.c create mode 100644 miranda-wine/src/modules/protocols/protodir.c create mode 100644 miranda-wine/src/modules/skin/skin.c create mode 100644 miranda-wine/src/modules/skin/skinicons.c create mode 100644 miranda-wine/src/modules/skin/sounds.c create mode 100644 miranda-wine/src/modules/srauth/auth.c create mode 100644 miranda-wine/src/modules/srauth/authdialogs.c create mode 100644 miranda-wine/src/modules/srawaymsg/awaymsg.c create mode 100644 miranda-wine/src/modules/srawaymsg/sendmsg.c create mode 100644 miranda-wine/src/modules/sremail/email.c create mode 100644 miranda-wine/src/modules/srfile/file.c create mode 100644 miranda-wine/src/modules/srfile/file.h create mode 100644 miranda-wine/src/modules/srfile/fileexistsdlg.c create mode 100644 miranda-wine/src/modules/srfile/fileopts.c create mode 100644 miranda-wine/src/modules/srfile/filerecvdlg.c create mode 100644 miranda-wine/src/modules/srfile/filesenddlg.c create mode 100644 miranda-wine/src/modules/srfile/filexferdlg.c create mode 100644 miranda-wine/src/modules/srurl/url.c create mode 100644 miranda-wine/src/modules/srurl/url.h create mode 100644 miranda-wine/src/modules/srurl/urldialogs.c create mode 100644 miranda-wine/src/modules/userinfo/contactinfo.c create mode 100644 miranda-wine/src/modules/userinfo/stdinfo.c create mode 100644 miranda-wine/src/modules/userinfo/userinfo.c create mode 100644 miranda-wine/src/modules/useronline/useronline.c create mode 100644 miranda-wine/src/modules/utils/bmpfilter.c create mode 100644 miranda-wine/src/modules/utils/colourpicker.c create mode 100644 miranda-wine/src/modules/utils/hyperlink.c create mode 100644 miranda-wine/src/modules/utils/openurl.c create mode 100644 miranda-wine/src/modules/utils/path.c create mode 100644 miranda-wine/src/modules/utils/resizer.c create mode 100644 miranda-wine/src/modules/utils/utf.c create mode 100644 miranda-wine/src/modules/utils/utils.c create mode 100644 miranda-wine/src/modules/utils/windowlist.c create mode 100644 miranda-wine/src/modules/visibility/visibility.c create mode 100644 miranda-wine/src/res/addcontact.ico create mode 100644 miranda-wine/src/res/away.ico create mode 100644 miranda-wine/src/res/blank.ico create mode 100644 miranda-wine/src/res/changefont.ico create mode 100644 miranda-wine/src/res/delete.ico create mode 100644 miranda-wine/src/res/detailsl.ico create mode 100644 miranda-wine/src/res/dnd.ico create mode 100644 miranda-wine/src/res/downarrow.ico create mode 100644 miranda-wine/src/res/dragcopy.cur create mode 100644 miranda-wine/src/res/dropuser.cur create mode 100644 miranda-wine/src/res/emptyblo.ico create mode 100644 miranda-wine/src/res/file.ico create mode 100644 miranda-wine/src/res/filledbl.ico create mode 100644 miranda-wine/src/res/finduser.ico create mode 100644 miranda-wine/src/res/freechat.ico create mode 100644 miranda-wine/src/res/groupope.ico create mode 100644 miranda-wine/src/res/groupshu.ico create mode 100644 miranda-wine/src/res/help.ico create mode 100644 miranda-wine/src/res/history.ico create mode 100644 miranda-wine/src/res/hyperlin.cur create mode 100644 miranda-wine/src/res/invisible.ico create mode 100644 miranda-wine/src/res/message.ico create mode 100644 miranda-wine/src/res/miranda.ico create mode 100644 miranda-wine/src/res/mirandaw.ico create mode 100644 miranda-wine/src/res/multisend.ico create mode 100644 miranda-wine/src/res/na2.ico create mode 100644 miranda-wine/src/res/notick.ico create mode 100644 miranda-wine/src/res/notick1.ico create mode 100644 miranda-wine/src/res/occupied.ico create mode 100644 miranda-wine/src/res/offline2.ico create mode 100644 miranda-wine/src/res/online2.ico create mode 100644 miranda-wine/src/res/onthepho.ico create mode 100644 miranda-wine/src/res/options.ico create mode 100644 miranda-wine/src/res/outtolun.ico create mode 100644 miranda-wine/src/res/rename.ico create mode 100644 miranda-wine/src/res/reply.ico create mode 100644 miranda-wine/src/res/searchal.ico create mode 100644 miranda-wine/src/res/sendmail.ico create mode 100644 miranda-wine/src/res/smalldot.ico create mode 100644 miranda-wine/src/res/sms.ico create mode 100644 miranda-wine/src/res/sortcold.bmp create mode 100644 miranda-wine/src/res/sortcolu.bmp create mode 100644 miranda-wine/src/res/timestamp.ico create mode 100644 miranda-wine/src/res/url.ico create mode 100644 miranda-wine/src/res/useronli.ico create mode 100644 miranda-wine/src/res/viewdetails.ico create mode 100644 miranda-wine/src/resource.h create mode 100644 miranda-wine/src/resource.rc create mode 100644 miranda-wine/src/version.rc (limited to 'miranda-wine/src') 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 +#include + +#define _ALPHA_BASE_ 1 // defined for CVS builds +#define _ALPHA_FUSE_ 1 // defined for fuse powered core + +#ifdef _DEBUG +# define _CRTDBG_MAP_ALLOC +# include +# include +#endif + +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../resource.h" +#include +#include "modules.h" +#include "miranda.h" +#include "forkthread.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include 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;jmessage) { + 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;icbSize == 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 + +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;i24) 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 || 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;iresult=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 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; jtype == 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 + +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;idwFlag & 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; imakeDatabase(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->wMonthwMonth) 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.wMonth0) + { + 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(destCharsLeftszDest[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 + +#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(""); + } + 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;ipageCount;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;ipageCount;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;ipageCount;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;ipageCount;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;ipageCount;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 +#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("")); +} + +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;itype!=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;itype!=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)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;itype!=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.topthrobbing,&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;isearchCount;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;itype==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;itype==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 +#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) 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;iiLastColumnSortIndex=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;itype!=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 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;iszProto) { + 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 + +#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;iidFrom) { + 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;iImageiColumn==IGNOREEVENT_MAX+1) { //ignore none + for(iImage=0;iImageiColumn,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) && 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]<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]<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->englishHashenglishHash) 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->linePoslinePos) return -1; + if(arg1->linePos>arg2->linePos) return 1; + return 0; +} + + +static int SortLangPackHashesProc2(struct LangPackEntry *arg1,struct LangPackEntry *arg2) +{ + if(arg1->englishHashenglishHash) 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= 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;iuser.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;iuser.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 + 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->cchEncodedcbDecoded)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + return 0; + } + nlb64->cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded); + for(iIn=0,pbIn=nlb64->pbDecoded,pszOut=nlb64->pszEncoded;iIncbDecoded;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->cbDecodedcchEncoded)) { + SetLastError(ERROR_BUFFER_OVERFLOW); + return 0; + } + nlb64->cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded); + for(iIn=0,pszIn=nlb64->pszEncoded,pbOut=nlb64->pbDecoded;iIncchEncoded;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<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 +#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)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;iheadersCount;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;iheadersCount;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;iheadersCount;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;iheadersCount;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(bytesPeekedncsRecv); + 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)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;iheadersCount;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;iheadersCount;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;bytesRecveds); + 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=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<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(""),_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;iszIncomingPorts) 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;iuseProxy); + 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;iUseruser.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;iuser.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("")); + 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;iUseruser.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;iidFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { int iUser; + for(iUser=0;iUseruser.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 && ihandleType!=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; jhReadConns[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; jhWriteConns[j]; + if (conn==NULL || conn==INVALID_HANDLE_VALUE) break; + nls->hWriteStatus[j] = FD_ISSET(conn->s,&writefd); + } + for (j=0; jhExceptConns[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[] = + "%s"; + +static char soap_action[] = + "\r\n" + " \r\n" + " \r\n" + "%s" + " \r\n" + " \r\n" + "\r\n"; + +static char add_port_mapping[] = + " \r\n" + " %i\r\n" + " %s\r\n" + " %i\r\n" + " %s\r\n" + " 1\r\n" + " Miranda\r\n" + " 0\r\n"; + +static char delete_port_mapping[] = + " \r\n" + " %i\r\n" + " %s\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; jh_addr_list[j]; + } + + buf = mir_alloc(1500); + + for(i = 3; --i && szUrl[0] == 0;) + { + for (j=0; j 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, "", "", 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, "", "", 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, "", "<", 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;iopd[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;ipageCount;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;jopd[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;ipageCount;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;ipageCount;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;ipageCount;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;icbSize!=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 .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 + +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;icbSize!=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;iproto 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 + +/***********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;jtype!=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=SIZEOF(skinIconStatusToIdStatus)) return (int)(HICON)NULL; + return LoadSkinProtoIcon((WPARAM)(char*)NULL,skinIconStatusToIdStatus[wParam]); + } + if(wParam=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 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(nmainIconPath=(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;iprotoCount;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].idmainStatusPath[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;iprotoCount;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;iprotoCount;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;iprotoCount;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].idprotoCount>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;iprotoCount;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;iprotoCount;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;iprotoCount;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].ididFrom) { + 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; jidFrom) { + case 0: + if (((LPNMHDR)lParam)->code == PSN_APPLY) + { + int i; + for(i=0;i>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("")); + 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;ihDbEvent); + 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;iszName,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;iszName,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;itotalFiles;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;itotalFiles;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;itype!=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 +#include +#include +#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 +#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+1hContact=((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;ihContact,(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 +#include +#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;ifiles[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 +#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.cxcurrentFile,'\\')+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->currentFileNumbertotalFiles) 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;itransferStatus.totalFiles;i++) dat->fileVirusScanned[i]=1; + } + else { + dat->fileVirusScanned[wParam]=1; + for(i=0;itransferStatus.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 +#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;itype!=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; jhContact = ((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;iValue,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;i4) 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.x4 && !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("")); + 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("")); + } + 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->positionposition) 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;icbSize!=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;ipageCount;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;ipageCount;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)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;ipageCount;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;ipageCount;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;ipageCount;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 +#include + +#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 + +#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;iid; + 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;imessage,msg->wParam,msg->lParam); + return 0; +} + +static int BroadcastToWindowListAsync(WPARAM wParam,LPARAM lParam) +{ + int i; + MSG *msg=(MSG*)lParam; + for(i=0;imessage,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 new file mode 100644 index 0000000..2efc4dc Binary files /dev/null and b/miranda-wine/src/res/addcontact.ico differ diff --git a/miranda-wine/src/res/away.ico b/miranda-wine/src/res/away.ico new file mode 100644 index 0000000..1e22d9b Binary files /dev/null and b/miranda-wine/src/res/away.ico differ diff --git a/miranda-wine/src/res/blank.ico b/miranda-wine/src/res/blank.ico new file mode 100644 index 0000000..7845f62 Binary files /dev/null and b/miranda-wine/src/res/blank.ico differ diff --git a/miranda-wine/src/res/changefont.ico b/miranda-wine/src/res/changefont.ico new file mode 100644 index 0000000..2c152dc Binary files /dev/null and b/miranda-wine/src/res/changefont.ico differ diff --git a/miranda-wine/src/res/delete.ico b/miranda-wine/src/res/delete.ico new file mode 100644 index 0000000..c541793 Binary files /dev/null and b/miranda-wine/src/res/delete.ico differ diff --git a/miranda-wine/src/res/detailsl.ico b/miranda-wine/src/res/detailsl.ico new file mode 100644 index 0000000..a37e05d Binary files /dev/null and b/miranda-wine/src/res/detailsl.ico differ diff --git a/miranda-wine/src/res/dnd.ico b/miranda-wine/src/res/dnd.ico new file mode 100644 index 0000000..6ccd9d2 Binary files /dev/null and b/miranda-wine/src/res/dnd.ico differ diff --git a/miranda-wine/src/res/downarrow.ico b/miranda-wine/src/res/downarrow.ico new file mode 100644 index 0000000..76a473c Binary files /dev/null and b/miranda-wine/src/res/downarrow.ico differ diff --git a/miranda-wine/src/res/dragcopy.cur b/miranda-wine/src/res/dragcopy.cur new file mode 100644 index 0000000..89c7c96 Binary files /dev/null and b/miranda-wine/src/res/dragcopy.cur differ diff --git a/miranda-wine/src/res/dropuser.cur b/miranda-wine/src/res/dropuser.cur new file mode 100644 index 0000000..a84b19e Binary files /dev/null and b/miranda-wine/src/res/dropuser.cur differ diff --git a/miranda-wine/src/res/emptyblo.ico b/miranda-wine/src/res/emptyblo.ico new file mode 100644 index 0000000..05469b9 Binary files /dev/null and b/miranda-wine/src/res/emptyblo.ico differ diff --git a/miranda-wine/src/res/file.ico b/miranda-wine/src/res/file.ico new file mode 100644 index 0000000..7d24e6d Binary files /dev/null and b/miranda-wine/src/res/file.ico differ diff --git a/miranda-wine/src/res/filledbl.ico b/miranda-wine/src/res/filledbl.ico new file mode 100644 index 0000000..35752d2 Binary files /dev/null and b/miranda-wine/src/res/filledbl.ico differ diff --git a/miranda-wine/src/res/finduser.ico b/miranda-wine/src/res/finduser.ico new file mode 100644 index 0000000..a105678 Binary files /dev/null and b/miranda-wine/src/res/finduser.ico differ diff --git a/miranda-wine/src/res/freechat.ico b/miranda-wine/src/res/freechat.ico new file mode 100644 index 0000000..56d6661 Binary files /dev/null and b/miranda-wine/src/res/freechat.ico differ diff --git a/miranda-wine/src/res/groupope.ico b/miranda-wine/src/res/groupope.ico new file mode 100644 index 0000000..64b8dc2 Binary files /dev/null and b/miranda-wine/src/res/groupope.ico differ diff --git a/miranda-wine/src/res/groupshu.ico b/miranda-wine/src/res/groupshu.ico new file mode 100644 index 0000000..8b6f797 Binary files /dev/null and b/miranda-wine/src/res/groupshu.ico differ diff --git a/miranda-wine/src/res/help.ico b/miranda-wine/src/res/help.ico new file mode 100644 index 0000000..7fd7196 Binary files /dev/null and b/miranda-wine/src/res/help.ico differ diff --git a/miranda-wine/src/res/history.ico b/miranda-wine/src/res/history.ico new file mode 100644 index 0000000..2749b50 Binary files /dev/null and b/miranda-wine/src/res/history.ico differ diff --git a/miranda-wine/src/res/hyperlin.cur b/miranda-wine/src/res/hyperlin.cur new file mode 100644 index 0000000..f0f548c Binary files /dev/null and b/miranda-wine/src/res/hyperlin.cur differ diff --git a/miranda-wine/src/res/invisible.ico b/miranda-wine/src/res/invisible.ico new file mode 100644 index 0000000..a2cd800 Binary files /dev/null and b/miranda-wine/src/res/invisible.ico differ diff --git a/miranda-wine/src/res/message.ico b/miranda-wine/src/res/message.ico new file mode 100644 index 0000000..34bc390 Binary files /dev/null and b/miranda-wine/src/res/message.ico differ diff --git a/miranda-wine/src/res/miranda.ico b/miranda-wine/src/res/miranda.ico new file mode 100644 index 0000000..f7791c3 Binary files /dev/null and b/miranda-wine/src/res/miranda.ico differ diff --git a/miranda-wine/src/res/mirandaw.ico b/miranda-wine/src/res/mirandaw.ico new file mode 100644 index 0000000..bc62b68 Binary files /dev/null and b/miranda-wine/src/res/mirandaw.ico differ diff --git a/miranda-wine/src/res/multisend.ico b/miranda-wine/src/res/multisend.ico new file mode 100644 index 0000000..3303179 Binary files /dev/null and b/miranda-wine/src/res/multisend.ico differ diff --git a/miranda-wine/src/res/na2.ico b/miranda-wine/src/res/na2.ico new file mode 100644 index 0000000..cab81c4 Binary files /dev/null and b/miranda-wine/src/res/na2.ico differ diff --git a/miranda-wine/src/res/notick.ico b/miranda-wine/src/res/notick.ico new file mode 100644 index 0000000..b96b9ec Binary files /dev/null and b/miranda-wine/src/res/notick.ico differ diff --git a/miranda-wine/src/res/notick1.ico b/miranda-wine/src/res/notick1.ico new file mode 100644 index 0000000..9fe70c4 Binary files /dev/null and b/miranda-wine/src/res/notick1.ico differ diff --git a/miranda-wine/src/res/occupied.ico b/miranda-wine/src/res/occupied.ico new file mode 100644 index 0000000..d60bcd7 Binary files /dev/null and b/miranda-wine/src/res/occupied.ico differ diff --git a/miranda-wine/src/res/offline2.ico b/miranda-wine/src/res/offline2.ico new file mode 100644 index 0000000..7058c74 Binary files /dev/null and b/miranda-wine/src/res/offline2.ico differ diff --git a/miranda-wine/src/res/online2.ico b/miranda-wine/src/res/online2.ico new file mode 100644 index 0000000..d559fb9 Binary files /dev/null and b/miranda-wine/src/res/online2.ico differ diff --git a/miranda-wine/src/res/onthepho.ico b/miranda-wine/src/res/onthepho.ico new file mode 100644 index 0000000..09d6dfa Binary files /dev/null and b/miranda-wine/src/res/onthepho.ico differ diff --git a/miranda-wine/src/res/options.ico b/miranda-wine/src/res/options.ico new file mode 100644 index 0000000..af93fd2 Binary files /dev/null and b/miranda-wine/src/res/options.ico differ diff --git a/miranda-wine/src/res/outtolun.ico b/miranda-wine/src/res/outtolun.ico new file mode 100644 index 0000000..6e5d40e Binary files /dev/null and b/miranda-wine/src/res/outtolun.ico differ diff --git a/miranda-wine/src/res/rename.ico b/miranda-wine/src/res/rename.ico new file mode 100644 index 0000000..6dd597e Binary files /dev/null and b/miranda-wine/src/res/rename.ico differ diff --git a/miranda-wine/src/res/reply.ico b/miranda-wine/src/res/reply.ico new file mode 100644 index 0000000..ddaf242 Binary files /dev/null and b/miranda-wine/src/res/reply.ico differ diff --git a/miranda-wine/src/res/searchal.ico b/miranda-wine/src/res/searchal.ico new file mode 100644 index 0000000..8146dfb Binary files /dev/null and b/miranda-wine/src/res/searchal.ico differ diff --git a/miranda-wine/src/res/sendmail.ico b/miranda-wine/src/res/sendmail.ico new file mode 100644 index 0000000..55097a1 Binary files /dev/null and b/miranda-wine/src/res/sendmail.ico differ diff --git a/miranda-wine/src/res/smalldot.ico b/miranda-wine/src/res/smalldot.ico new file mode 100644 index 0000000..47f0556 Binary files /dev/null and b/miranda-wine/src/res/smalldot.ico differ diff --git a/miranda-wine/src/res/sms.ico b/miranda-wine/src/res/sms.ico new file mode 100644 index 0000000..4beb6e7 Binary files /dev/null and b/miranda-wine/src/res/sms.ico differ diff --git a/miranda-wine/src/res/sortcold.bmp b/miranda-wine/src/res/sortcold.bmp new file mode 100644 index 0000000..1fc197f Binary files /dev/null and b/miranda-wine/src/res/sortcold.bmp differ diff --git a/miranda-wine/src/res/sortcolu.bmp b/miranda-wine/src/res/sortcolu.bmp new file mode 100644 index 0000000..271acc9 Binary files /dev/null and b/miranda-wine/src/res/sortcolu.bmp differ diff --git a/miranda-wine/src/res/timestamp.ico b/miranda-wine/src/res/timestamp.ico new file mode 100644 index 0000000..83b8abf Binary files /dev/null and b/miranda-wine/src/res/timestamp.ico differ diff --git a/miranda-wine/src/res/url.ico b/miranda-wine/src/res/url.ico new file mode 100644 index 0000000..34a5643 Binary files /dev/null and b/miranda-wine/src/res/url.ico differ diff --git a/miranda-wine/src/res/useronli.ico b/miranda-wine/src/res/useronli.ico new file mode 100644 index 0000000..b6e4190 Binary files /dev/null and b/miranda-wine/src/res/useronli.ico differ diff --git a/miranda-wine/src/res/viewdetails.ico b/miranda-wine/src/res/viewdetails.ico new file mode 100644 index 0000000..c9fb124 Binary files /dev/null and b/miranda-wine/src/res/viewdetails.ico differ 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 +#include +#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 \r\n" + "#include \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 + -- cgit v1.2.3